get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2811,
    "url": "https://patches.dpdk.org/api/patches/2811/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1422615464-4432-3-git-send-email-michalx.k.jastrzebski@intel.com/",
    "project": {
        "id": 1,
        "url": "https://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": "<1422615464-4432-3-git-send-email-michalx.k.jastrzebski@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1422615464-4432-3-git-send-email-michalx.k.jastrzebski@intel.com",
    "date": "2015-01-30T10:57:42",
    "name": "[dpdk-dev,2/4] bond: added link bonding mode 6 implementation.",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "cb2cadd1abcc607ac3e8fae785628653e329278c",
    "submitter": {
        "id": 74,
        "url": "https://patches.dpdk.org/api/people/74/?format=api",
        "name": "Michal Jastrzebski",
        "email": "michalx.k.jastrzebski@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1422615464-4432-3-git-send-email-michalx.k.jastrzebski@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/2811/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/2811/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id AD3AD5A8E;\n\tFri, 30 Jan 2015 11:59:14 +0100 (CET)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby dpdk.org (Postfix) with ESMTP id B6F1C5A82\n\tfor <dev@dpdk.org>; Fri, 30 Jan 2015 11:59:11 +0100 (CET)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby fmsmga101.fm.intel.com with ESMTP; 30 Jan 2015 02:59:09 -0800",
            "from unknown (HELO Sent) ([10.217.248.89])\n\tby orsmga001.jf.intel.com with SMTP; 30 Jan 2015 02:59:08 -0800",
            "by Sent (sSMTP sendmail emulation); Fri, 30 Jan 2015 11:58:45 +0200"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.09,491,1418112000\"; d=\"scan'208\";a=\"645014276\"",
        "From": "Michal Jastrzebski <michalx.k.jastrzebski@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 30 Jan 2015 11:57:42 +0100",
        "Message-Id": "<1422615464-4432-3-git-send-email-michalx.k.jastrzebski@intel.com>",
        "X-Mailer": "git-send-email 2.1.1",
        "In-Reply-To": "<1422615464-4432-1-git-send-email-michalx.k.jastrzebski@intel.com>",
        "References": "<1422615464-4432-1-git-send-email-michalx.k.jastrzebski@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 2/4] bond: added link bonding mode 6\n\timplementation.",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This mode includes adaptive TLB and receive load balancing (RLB). In RLB\nthe bonding driver intercepts ARP replies send by local system and\noverwrites its source MAC address, so that different peers send data to\nthe server on different slave interfaces. When local system sends ARP\nrequest, it saves IP information from it. When ARP reply from that peer\nis received, its MAC is stored, one of slave MACs assigned and ARP reply\nsend to that peer.\n\nSigned-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>\n---\n lib/librte_pmd_bond/Makefile               |    1 +\n lib/librte_pmd_bond/rte_eth_bond.h         |    9 +\n lib/librte_pmd_bond/rte_eth_bond_alb.c     |  251 ++++++++++++++++++++++++++++\n lib/librte_pmd_bond/rte_eth_bond_alb.h     |  109 ++++++++++++\n lib/librte_pmd_bond/rte_eth_bond_api.c     |    6 +\n lib/librte_pmd_bond/rte_eth_bond_args.c    |    1 +\n lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  231 ++++++++++++++++++++++---\n lib/librte_pmd_bond/rte_eth_bond_private.h |    2 +\n 8 files changed, 589 insertions(+), 21 deletions(-)\n create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c\n create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h",
    "diff": "diff --git a/lib/librte_pmd_bond/Makefile b/lib/librte_pmd_bond/Makefile\nindex cdff126..d111f0c 100644\n--- a/lib/librte_pmd_bond/Makefile\n+++ b/lib/librte_pmd_bond/Makefile\n@@ -46,6 +46,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_api.c\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_pmd.c\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_args.c\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_8023ad.c\n+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_alb.c\n \n ifeq ($(CONFIG_RTE_MBUF_REFCNT),n)\n $(info WARNING: Link Bonding Broadcast mode is disabled because it needs MBUF_REFCNT.)\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h\nindex 7177983..13581cb 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond.h\n+++ b/lib/librte_pmd_bond/rte_eth_bond.h\n@@ -101,6 +101,15 @@ extern \"C\" {\n  * This mode provides an adaptive transmit load balancing. It dynamically\n  * changes the transmitting slave, according to the computed load. Statistics\n  * are collected in 100ms intervals and scheduled every 10ms */\n+#define BONDING_MODE_ALB\t(6)\n+/**< Adaptive Load Balancing (Mode 6)\n+ * This mode includes adaptive TLB and receive load balancing (RLB). In RLB the\n+ * bonding driver intercepts ARP replies send by local system and overwrites its\n+ * source MAC address, so that different peers send data to the server on\n+ * different slave interfaces. When local system sends ARP request, it saves IP\n+ * information from it. When ARP reply from that peer is received, its MAC is\n+ * stored, one of slave MACs assigned and ARP reply send to that peer.\n+ */\n \n /* Balance Mode Transmit Policies */\n #define BALANCE_XMIT_POLICY_LAYER2\t\t(0)\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.c b/lib/librte_pmd_bond/rte_eth_bond_alb.c\nnew file mode 100644\nindex 0000000..449b2f8\n--- /dev/null\n+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.c\n@@ -0,0 +1,251 @@\n+#include \"rte_eth_bond_private.h\"\n+#include \"rte_eth_bond_alb.h\"\n+\n+static inline uint8_t\n+simple_hash(uint8_t *hash_start, int hash_size)\n+{\n+\tint i;\n+\tuint8_t hash;\n+\n+\thash = 0;\n+\tfor (i = 0; i < hash_size; ++i)\n+\t\thash ^= hash_start[i];\n+\n+\treturn hash;\n+}\n+\n+static uint8_t\n+calculate_slave(struct bond_dev_private *internals)\n+{\n+\tuint8_t idx;\n+\n+\tidx = (internals->mode6.last_slave + 1)%internals->active_slave_count;\n+\treturn internals->active_slaves[idx];\n+}\n+\n+int\n+bond_mode_alb_enable(struct rte_eth_dev *bond_dev)\n+{\n+\tstruct bond_dev_private *internals = bond_dev->data->dev_private;\n+\tstruct client_data *hash_table = internals->mode6.client_table;\n+\n+\tuint16_t element_size;\n+\tchar mem_name[RTE_ETH_NAME_MAX_LEN];\n+\tint socket_id = bond_dev->pci_dev->numa_node;\n+\n+\t/* Fill hash table with initial values */\n+\tmemset(hash_table, 0, sizeof(struct client_data) * ALB_HASH_TABLE_SIZE);\n+\n+\tinternals->mode6.last_slave = ALB_NULL_INDEX;\n+\tinternals->mode6.ntt = 0;\n+\n+\t/* Initialize memory pool for ARP packets to send */\n+\tif (internals->mode6.mempool == NULL) {\n+\t\t/*\n+\t\t * 256 is size of ETH header, ARP header and nested VLAN headers.\n+\t\t * The value is chosen to be cache aligned.\n+\t\t */\n+\t\telement_size = 256 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;\n+\t\tsnprintf(mem_name, sizeof(mem_name), \"%s_MODE6\", bond_dev->data->name);\n+\t\tinternals->mode6.mempool = rte_mempool_create(mem_name,\n+\t\t\t\t512 * RTE_MAX_ETHPORTS,\n+\t\t\t\telement_size,\n+\t\t\t\tRTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ?\n+\t\t\t\t\t\t32 : RTE_MEMPOOL_CACHE_MAX_SIZE,\n+\t\t\t\tsizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init,\n+\t\t\t\tNULL, rte_pktmbuf_init, NULL, socket_id, 0);\n+\n+\t\tif (internals->mode6.mempool == NULL) {\n+\t\t\tRTE_LOG(ERR, PMD, \"%s: Failed to initialize ALB mempool.\\n\",\n+\t\t\t\t\tbond_dev->data->name);\n+\t\t\trte_panic(\n+\t\t\t\t\t\"Failed to alocate memory pool ('%s')\\n\" \"for bond device '%s'\\n\",\n+\t\t\t\t\tmem_name, bond_dev->data->name);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void\n+bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,\n+\t\tstruct bond_dev_private *internals)\n+{\n+\tstruct arp_hdr *arp;\n+\n+\tstruct client_data *hash_table = internals->mode6.client_table;\n+\tstruct client_data *client_info;\n+\n+\tuint8_t hash_index;\n+\n+\tarp = (struct arp_hdr *)((char *)(eth_h + 1) + offset);\n+\n+\thash_index = simple_hash((uint8_t *)&arp->arp_data.arp_sip,\n+\t\t\tsizeof(uint32_t));\n+\tclient_info = &hash_table[hash_index];\n+\n+\tif (arp->arp_op == rte_cpu_to_be_16(ARP_OP_REPLY)) {\n+\t\t/*\n+\t\t * We got reply for ARP Request send by the application. We need to\n+\t\t * update client table and issue sending update packet to that slave.\n+\t\t */\n+\t\trte_spinlock_lock(&internals->mode6.lock);\n+\t\tif (client_info->in_use == 0 ||\n+\t\t\tclient_info->app_ip != arp->arp_data.arp_tip ||\n+\t\t\tclient_info->cli_ip != arp->arp_data.arp_sip) {\n+\t\t\tclient_info->in_use = 1;\n+\t\t\tclient_info->app_ip = arp->arp_data.arp_tip;\n+\t\t\tclient_info->cli_ip = arp->arp_data.arp_sip;\n+\t\t\tether_addr_copy(&arp->arp_data.arp_sha, &client_info->cli_mac);\n+\t\t\tclient_info->slave_idx = calculate_slave(internals);\n+\t\t\tinternals->mode6.last_slave = client_info->slave_idx;\n+\t\t\trte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);\n+\t\t\tether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_tha);\n+\t\t\tmemcpy(client_info->vlan, eth_h + 1, offset);\n+\t\t} else if (!is_same_ether_addr(&client_info->cli_mac,\n+\t\t\t\t&arp->arp_data.arp_sha)) {\n+\t\t\t/*\n+\t\t\t *  We received response to broadcast message and must update\n+\t\t\t *  only client MAC.\n+\t\t\t */\n+\t\t\tether_addr_copy(&arp->arp_data.arp_sha, &client_info->cli_mac);\n+\t\t}\n+\t\tinternals->mode6.ntt = 1;\n+\t\trte_spinlock_unlock(&internals->mode6.lock);\n+\t}\n+\t/* ARP Requests are forwarded to the application with no changes */\n+}\n+\n+uint8_t\n+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,\n+\t\tstruct bond_dev_private *internals)\n+{\n+\tstruct arp_hdr *arp;\n+\n+\tstruct client_data *hash_table = internals->mode6.client_table;\n+\tstruct client_data *client_info;\n+\n+\tuint8_t hash_index;\n+\n+\tstruct ether_addr bonding_mac;\n+\n+\tarp = (struct arp_hdr *)((char *)(eth_h + 1) + offset);\n+\n+\t/*\n+\t * Traffic with src MAC other than bonding should be sent on\n+\t * current primary port.\n+\t */\n+\trte_eth_macaddr_get(internals->port_id, &bonding_mac);\n+\tif (!is_same_ether_addr(&bonding_mac, &arp->arp_data.arp_sha)) {\n+\t\trte_eth_macaddr_get(internals->current_primary_port,\n+\t\t\t\t&arp->arp_data.arp_sha);\n+\t\treturn internals->current_primary_port;\n+\t}\n+\n+\thash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,\n+\t\t\tsizeof(uint32_t));\n+\tclient_info = &hash_table[hash_index];\n+\n+\trte_spinlock_lock(&internals->mode6.lock);\n+\tif (arp->arp_op == rte_cpu_to_be_16(ARP_OP_REPLY)) {\n+\t\tif (client_info->in_use) {\n+\t\t\tif (client_info->app_ip == arp->arp_data.arp_sip &&\n+\t\t\t\tclient_info->cli_ip == arp->arp_data.arp_tip) {\n+\t\t\t\t/* Entry is already assigned to this client */\n+\t\t\t\tif (!is_broadcast_ether_addr(&arp->arp_data.arp_tha)) {\n+\t\t\t\t\tether_addr_copy(&arp->arp_data.arp_tha,\n+\t\t\t\t\t\t\t&client_info->cli_mac);\n+\t\t\t\t}\n+\t\t\t\trte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);\n+\t\t\t\tether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);\n+\t\t\t\tmemcpy(client_info->vlan, eth_h + 1, offset);\n+\t\t\t\trte_spinlock_unlock(&internals->mode6.lock);\n+\t\t\t\treturn client_info->slave_idx;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Assign new slave to this client and update src mac in ARP */\n+\t\tclient_info->in_use = 1;\n+\t\tclient_info->ntt = 0;\n+\t\tclient_info->app_ip = arp->arp_data.arp_sip;\n+\t\tether_addr_copy(&arp->arp_data.arp_tha, &client_info->cli_mac);\n+\t\tclient_info->cli_ip = arp->arp_data.arp_tip;\n+\t\tclient_info->slave_idx = calculate_slave(internals);\n+\t\tinternals->mode6.last_slave = client_info->slave_idx;\n+\t\trte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);\n+\t\tether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);\n+\t\tmemcpy(client_info->vlan, eth_h + 1, offset);\n+\t\trte_spinlock_unlock(&internals->mode6.lock);\n+\t\treturn client_info->slave_idx;\n+\t}\n+\n+\t/* If packet is not ARP Reply, send it on current primary port. */\n+\trte_spinlock_unlock(&internals->mode6.lock);\n+\trte_eth_macaddr_get(internals->current_primary_port,\n+\t\t\t&arp->arp_data.arp_sha);\n+\treturn internals->current_primary_port;\n+}\n+\n+uint8_t\n+bond_mode_alb_arp_upd(struct client_data *client_info,\n+\t\tstruct rte_mbuf *pkt, struct bond_dev_private *internals)\n+{\n+\tstruct ether_hdr *eth_h;\n+\tstruct arp_hdr *arp_h;\n+\tuint8_t slave_idx;\n+\n+\trte_spinlock_lock(&internals->mode6.lock);\n+\teth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);\n+\n+\tether_addr_copy(&client_info->app_mac, &eth_h->s_addr);\n+\tether_addr_copy(&client_info->cli_mac, &eth_h->d_addr);\n+\teth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);\n+\n+\tarp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr)\n+\t\t\t+ client_info->vlan_count * sizeof(struct vlan_hdr));\n+\n+\tmemcpy(eth_h + 1, client_info->vlan,\n+\t\t\tclient_info->vlan_count * sizeof(struct vlan_hdr));\n+\n+\tether_addr_copy(&client_info->app_mac, &arp_h->arp_data.arp_sha);\n+\tarp_h->arp_data.arp_sip = client_info->app_ip;\n+\tether_addr_copy(&client_info->cli_mac, &arp_h->arp_data.arp_tha);\n+\tarp_h->arp_data.arp_tip = client_info->cli_ip;\n+\n+\tarp_h->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);\n+\tarp_h->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);\n+\tarp_h->arp_hln = ETHER_ADDR_LEN;\n+\tarp_h->arp_pln = sizeof(uint32_t);\n+\tarp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);\n+\n+\tslave_idx = client_info->slave_idx;\n+\trte_spinlock_unlock(&internals->mode6.lock);\n+\n+\treturn slave_idx;\n+}\n+\n+void\n+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)\n+{\n+\tstruct bond_dev_private *internals = bond_dev->data->dev_private;\n+\tstruct client_data *client_info;\n+\n+\tint i;\n+\t/* If active slave count is 0, it's pointless to refresh alb table */\n+\tif (internals->active_slave_count <= 0)\n+\t\treturn;\n+\n+\trte_spinlock_lock(&internals->mode6.lock);\n+\tinternals->mode6.last_slave = ALB_NULL_INDEX;\n+\n+\tfor (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {\n+\t\tclient_info = &internals->mode6.client_table[i];\n+\t\tif (client_info->in_use) {\n+\t\t\tclient_info->slave_idx = calculate_slave(internals);\n+\t\t\tinternals->mode6.last_slave = client_info->slave_idx;\n+\t\t\trte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);\n+\t\t\tinternals->mode6.ntt = 1;\n+\t\t}\n+\t}\n+\trte_spinlock_unlock(&internals->mode6.lock);\n+}\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.h b/lib/librte_pmd_bond/rte_eth_bond_alb.h\nnew file mode 100644\nindex 0000000..0cfe942\n--- /dev/null\n+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.h\n@@ -0,0 +1,109 @@\n+#ifndef RTE_ETH_BOND_ALB_H_\n+#define RTE_ETH_BOND_ALB_H_\n+\n+#include <rte_ether.h>\n+#include <rte_arp.h>\n+\n+#define ALB_HASH_TABLE_SIZE\t256\n+#define ALB_NULL_INDEX\t\t0xFFFFFFFF\n+\n+struct client_data {\n+\t/** ARP data of single client */\n+\tstruct ether_addr app_mac;\n+\t/**< MAC address of application running DPDK */\n+\tuint32_t app_ip;\n+\t/**< IP address of application running DPDK */\n+\tstruct ether_addr cli_mac;\n+\t/**< Client MAC address */\n+\tuint32_t cli_ip;\n+\t/**< Client IP address */\n+\n+\tuint8_t slave_idx;\n+\t/**< Index of slave on which we connect with that client */\n+\tuint8_t in_use;\n+\t/**< Flag indicating if entry in client table is currently used */\n+\tuint8_t ntt;\n+\t/**< Flag indicating if we need to send update to this client on next tx */\n+\n+\tstruct vlan_hdr vlan[2];\n+\t/**< Content of vlan headers */\n+\tuint8_t vlan_count;\n+\t/**< Number of nested vlan headers */\n+};\n+\n+struct mode_alb_private {\n+\tstruct client_data client_table[ALB_HASH_TABLE_SIZE];\n+\t/**< Hash table storing ARP data of every client connected */\n+\tstruct rte_mempool *mempool;\n+\t/**< Mempool for creating ARP update packets */\n+\tuint8_t ntt;\n+\t/**< Flag indicating if we need to send update to any client on next tx */\n+\tuint32_t last_slave;\n+\t/**< Index of last used slave in client table */\n+\trte_spinlock_t lock;\n+};\n+\n+/**\n+ * ALB mode initialization.\n+ *\n+ * @param bond_dev\t\tPointer to bonding device.\n+ *\n+ * @return\n+ * Error code - 0 on success.\n+ */\n+int\n+bond_mode_alb_enable(struct rte_eth_dev *bond_dev);\n+\n+/**\n+ * Function handles ARP packet reception. If received ARP request, it is\n+ * forwarded to application without changes. If it is ARP reply, client table\n+ * is updated.\n+ *\n+ * @param eth_h\t\t\tETH header of received packet.\n+ * @param offset\t\tVlan header offset.\n+ * @param internals\t\tBonding data.\n+ */\n+void\n+bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,\n+\t\tstruct bond_dev_private *internals);\n+\n+/**\n+ * Function handles ARP packet transmission. It also decides on which slave\n+ * send that packet. If packet is ARP Request, it is send on primary slave.\n+ * If it is ARP Reply, it is send on slave stored in client table for that\n+ * connection. On Reply function also updates data in client table.\n+ *\n+ * @param eth_h\t\t\tETH header of transmitted packet.\n+ * @param offset\t\tVlan header offset.\n+ * @param internals\t\tBonding data.\n+ *\n+ * @return\n+ * Index of slave on which packet should be sent.\n+ */\n+uint8_t\n+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,\n+\t\tstruct bond_dev_private *internals);\n+\n+/**\n+ * Function fills packet with ARP data from client_info.\n+ *\n+ * @param client_info\tData of client to which packet is sent.\n+ * @param pkt\t\t\tPointer to packet which is sent.\n+ * @param internals\t\tBonding data.\n+ *\n+ * @return\n+ * Index of slawe on which packet should be sent.\n+ */\n+uint8_t\n+bond_mode_alb_arp_upd(struct client_data *client_info,\n+\t\tstruct rte_mbuf *pkt, struct bond_dev_private *internals);\n+\n+/**\n+ * Function updates slave indexes of active connections.\n+ *\n+ * @param bond_dev\t\tPointer to bonded device struct.\n+ */\n+void\n+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev);\n+\n+#endif /* RTE_ETH_BOND_ALB_H_ */\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c\nindex 4ab3267..92ef3ae 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_api.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c\n@@ -120,6 +120,9 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)\n \n \tinternals->active_slaves[internals->active_slave_count] = port_id;\n \tinternals->active_slave_count++;\n+\n+\tif (internals->mode == BONDING_MODE_ALB)\n+\t\tbond_mode_alb_client_list_upd(eth_dev);\n }\n \n void\n@@ -152,6 +155,9 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)\n \n \tif (eth_dev->data->dev_started && internals->mode == BONDING_MODE_8023AD)\n \t\tbond_mode_8023ad_start(eth_dev);\n+\n+\tif (internals->mode == BONDING_MODE_ALB)\n+\t\tbond_mode_alb_client_list_upd(eth_dev);\n }\n \n uint8_t\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c\nindex ca4de38..a3f7f55 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_args.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c\n@@ -175,6 +175,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,\n #endif\n \tcase BONDING_MODE_8023AD:\n \tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n+\tcase BONDING_MODE_ALB:\n \t\treturn 0;\n \tdefault:\n \t\tRTE_BOND_LOG(ERR, \"Invalid slave mode value (%s) specified\", value);\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c\nindex 8b80297..b0525cc 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c\n@@ -56,6 +56,42 @@\n /* Table for statistics in mode 5 TLB */\n static uint64_t tlb_last_obytets[RTE_MAX_ETHPORTS];\n \n+static inline size_t\n+get_vlan_offset(struct ether_hdr *eth_hdr)\n+{\n+\tsize_t vlan_offset = 0;\n+\n+\t/* Calculate VLAN offset */\n+\tif (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == eth_hdr->ether_type) {\n+\t\tstruct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);\n+\t\tvlan_offset = sizeof(struct vlan_hdr);\n+\n+\t\twhile (rte_cpu_to_be_16(ETHER_TYPE_VLAN) ==\n+\t\t\t\tvlan_hdr->eth_proto) {\n+\t\t\tvlan_hdr = vlan_hdr + 1;\n+\t\t\tvlan_offset += sizeof(struct vlan_hdr);\n+\t\t}\n+\t}\n+\treturn vlan_offset;\n+}\n+\n+static uint16_t\n+get_vlan_ethertype(struct ether_hdr *eth_hdr)\n+{\n+\tif (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == eth_hdr->ether_type) {\n+\t\tstruct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);\n+\n+\t\twhile (rte_cpu_to_be_16(ETHER_TYPE_VLAN) ==\n+\t\t\t\tvlan_hdr->eth_proto) {\n+\t\t\tvlan_hdr = vlan_hdr + 1;\n+\t\t}\n+\n+\t\treturn vlan_hdr->eth_proto;\n+\t} else {\n+\t\treturn eth_hdr->ether_type;\n+\t}\n+}\n+\n static uint16_t\n bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n {\n@@ -173,6 +209,34 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,\n }\n \n static uint16_t\n+bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;\n+\tstruct bond_dev_private *internals = bd_tx_q->dev_private;\n+\n+\tstruct ether_hdr *eth_h;\n+\n+\tuint16_t ether_type, offset;\n+\tuint16_t nb_recv_pkts;\n+\n+\tint i;\n+\n+\tnb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);\n+\n+\tfor (i = 0; i < nb_recv_pkts; i++) {\n+\t\teth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);\n+\t\toffset = get_vlan_offset(eth_h);\n+\t\tether_type = get_vlan_ethertype(eth_h);\n+\n+\t\tif (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {\n+\t\t\tbond_mode_alb_arp_recv(eth_h, offset, internals);\n+\t\t}\n+\t}\n+\n+\treturn nb_recv_pkts;\n+}\n+\n+static uint16_t\n bond_ethdev_tx_burst_round_robin(void *queue, struct rte_mbuf **bufs,\n \t\tuint16_t nb_pkts)\n {\n@@ -281,25 +345,6 @@ ipv6_hash(struct ipv6_hdr *ipv6_hdr)\n \t\t\t(word_src_addr[3] ^ word_dst_addr[3]);\n }\n \n-static inline size_t\n-get_vlan_offset(struct ether_hdr *eth_hdr)\n-{\n-\tsize_t vlan_offset = 0;\n-\n-\t/* Calculate VLAN offset */\n-\tif (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == eth_hdr->ether_type) {\n-\t\tstruct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);\n-\t\tvlan_offset = sizeof(struct vlan_hdr);\n-\n-\t\twhile (rte_cpu_to_be_16(ETHER_TYPE_VLAN) ==\n-\t\t\t\tvlan_hdr->eth_proto) {\n-\t\t\tvlan_hdr = vlan_hdr + 1;\n-\t\t\tvlan_offset += sizeof(struct vlan_hdr);\n-\t\t}\n-\t}\n-\treturn vlan_offset;\n-}\n-\n uint16_t\n xmit_l2_hash(const struct rte_mbuf *buf, uint8_t slave_count)\n {\n@@ -525,6 +570,134 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n }\n \n static uint16_t\n+bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;\n+\tstruct bond_dev_private *internals = bd_tx_q->dev_private;\n+\n+\tstruct ether_hdr *eth_h;\n+\tuint16_t ether_type, offset;\n+\n+\tstruct client_data *client_info;\n+\n+\t/*\n+\t * We create transmit buffers for every slave and one additional to send\n+\t * through tlb. In worst case every packet will be send on one port.\n+\t */\n+\tstruct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS + 1][nb_pkts];\n+\tuint16_t slave_bufs_pkts[RTE_MAX_ETHPORTS + 1] = { 0 };\n+\n+\t/*\n+\t * We create separate transmit buffers for update packets as they wont be\n+\t * counted in num_tx_total.\n+\t */\n+\tstruct rte_mbuf *update_bufs[RTE_MAX_ETHPORTS][ALB_HASH_TABLE_SIZE];\n+\tuint16_t update_bufs_pkts[RTE_MAX_ETHPORTS] = { 0 };\n+\n+\tstruct rte_mbuf *upd_pkt;\n+\tsize_t pkt_size;\n+\n+\tuint16_t num_send, num_not_send = 0;\n+\tuint16_t num_tx_total = 0;\n+\tuint8_t slave_idx;\n+\n+\tint i, j;\n+\n+\t/* Search tx buffer for ARP packets and forward them to alb */\n+\tfor (i = 0; i < nb_pkts; i++) {\n+\t\teth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);\n+\t\toffset = get_vlan_offset(eth_h);\n+\t\tether_type = get_vlan_ethertype(eth_h);\n+\n+\t\tif (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {\n+\t\t\tslave_idx = bond_mode_alb_arp_xmit(eth_h, offset, internals);\n+\n+\t\t\t/* Change src mac in eth header */\n+\t\t\trte_eth_macaddr_get(slave_idx, &eth_h->s_addr);\n+\n+\t\t\t/* Add packet to slave tx buffer */\n+\t\t\tslave_bufs[slave_idx][slave_bufs_pkts[slave_idx]] = bufs[i];\n+\t\t\tslave_bufs_pkts[slave_idx]++;\n+\t\t} else {\n+\t\t\t/* If packet is not ARP, send it with TLB policy */\n+\t\t\tslave_bufs[RTE_MAX_ETHPORTS][slave_bufs_pkts[RTE_MAX_ETHPORTS]] =\n+\t\t\t\t\tbufs[i];\n+\t\t\tslave_bufs_pkts[RTE_MAX_ETHPORTS]++;\n+\t\t}\n+\t}\n+\n+\t/* Update connected client ARP tables */\n+\tif (internals->mode6.ntt) {\n+\t\tfor (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {\n+\t\t\tclient_info = &internals->mode6.client_table[i];\n+\n+\t\t\tif (client_info->in_use) {\n+\t\t\t\t/* Allocate new packet to send ARP update on current slave */\n+\t\t\t\tupd_pkt = rte_pktmbuf_alloc(internals->mode6.mempool);\n+\t\t\t\tif (upd_pkt == NULL) {\n+\t\t\t\t\tRTE_LOG(ERR, PMD, \"Failed to allocate ARP packet from pool\\n\");\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t\tpkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr);\n+\t\t\t\tupd_pkt->data_len = pkt_size;\n+\t\t\t\tupd_pkt->pkt_len = pkt_size;\n+\n+\t\t\t\tslave_idx = bond_mode_alb_arp_upd(client_info, upd_pkt,\n+\t\t\t\t\t\tinternals);\n+\n+\t\t\t\t/* Add packet to update tx buffer */\n+\t\t\t\tupdate_bufs[slave_idx][update_bufs_pkts[slave_idx]] = upd_pkt;\n+\t\t\t\tupdate_bufs_pkts[slave_idx]++;\n+\t\t\t}\n+\t\t}\n+\t\tinternals->mode6.ntt = 0;\n+\t}\n+\n+\t/* Send ARP packets on proper slaves */\n+\tfor (i = 0; i < RTE_MAX_ETHPORTS; i++) {\n+\t\tif (slave_bufs_pkts[i] > 0) {\n+\t\t\tnum_send = rte_eth_tx_burst(i, bd_tx_q->queue_id,\n+\t\t\t\t\tslave_bufs[i], slave_bufs_pkts[i]);\n+\t\t\tfor (j = 0; j < slave_bufs_pkts[i] - num_send; j++) {\n+\t\t\t\tbufs[nb_pkts - 1 - num_not_send - j] =\n+\t\t\t\t\t\tslave_bufs[i][nb_pkts - 1 - j];\n+\t\t\t}\n+\n+\t\t\tnum_tx_total += num_send;\n+\t\t\tnum_not_send += slave_bufs_pkts[i] - num_send;\n+\t\t}\n+\t}\n+\n+\t/* Send update packets on proper slaves */\n+\tfor (i = 0; i < RTE_MAX_ETHPORTS; i++) {\n+\t\tif (update_bufs_pkts[i] > 0) {\n+\t\t\tnum_send = rte_eth_tx_burst(i, bd_tx_q->queue_id, update_bufs[i],\n+\t\t\t\t\tupdate_bufs_pkts[i]);\n+\t\t\tfor (j = num_send; j < update_bufs_pkts[i]; j++) {\n+\t\t\t\trte_pktmbuf_free(update_bufs[i][j]);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Send non-ARP packets using tlb policy */\n+\tif (slave_bufs_pkts[RTE_MAX_ETHPORTS] > 0) {\n+\t\tnum_send = bond_ethdev_tx_burst_tlb(queue,\n+\t\t\t\tslave_bufs[RTE_MAX_ETHPORTS],\n+\t\t\t\tslave_bufs_pkts[RTE_MAX_ETHPORTS]);\n+\n+\t\tfor (j = 0; j < slave_bufs_pkts[RTE_MAX_ETHPORTS]; j++) {\n+\t\t\tbufs[nb_pkts - 1 - num_not_send - j] =\n+\t\t\t\t\tslave_bufs[RTE_MAX_ETHPORTS][nb_pkts - 1 - j];\n+\t\t}\n+\n+\t\tnum_tx_total += num_send;\n+\t\tnum_not_send += slave_bufs_pkts[RTE_MAX_ETHPORTS] - num_send;\n+\t}\n+\n+\treturn num_tx_total;\n+}\n+\n+static uint16_t\n bond_ethdev_tx_burst_balance(void *queue, struct rte_mbuf **bufs,\n \t\tuint16_t nb_pkts)\n {\n@@ -852,6 +1025,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)\n \t\tbreak;\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n \tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n+\tcase BONDING_MODE_ALB:\n \tdefault:\n \t\tfor (i = 0; i < internals->slave_count; i++) {\n \t\t\tif (internals->slaves[i].port_id ==\n@@ -917,6 +1091,13 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)\n \t\teth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;\n \t\teth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;\n \t\tbreak;\n+\tcase BONDING_MODE_ALB:\n+\t\tif (bond_mode_alb_enable(eth_dev) != 0)\n+\t\t\treturn -1;\n+\n+\t\teth_dev->tx_pkt_burst = bond_ethdev_tx_burst_alb;\n+\t\teth_dev->rx_pkt_burst = bond_ethdev_rx_burst_alb;\n+\t\tbreak;\n \tdefault:\n \t\treturn -1;\n \t}\n@@ -1132,7 +1313,8 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)\n \tif (internals->mode == BONDING_MODE_8023AD)\n \t\tbond_mode_8023ad_start(eth_dev);\n \n-\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)\n+\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||\n+\t\t\tinternals->mode == BONDING_MODE_ALB)\n \t\tbond_ethdev_update_tlb_slave_cb(internals);\n \n \treturn 0;\n@@ -1164,7 +1346,8 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)\n \t\t}\n \t}\n \n-\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {\n+\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||\n+\t\t\tinternals->mode == BONDING_MODE_ALB) {\n \t\trte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);\n \t}\n \n@@ -1362,8 +1545,12 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)\n {\n \tstruct bond_dev_private *internals = dev->data->dev_private;\n \tstruct rte_eth_stats slave_stats;\n+\n \tint i;\n \n+\t/* clear bonded stats before populating from slaves */\n+\tmemset(stats, 0, sizeof(*stats));\n+\n \tfor (i = 0; i < internals->slave_count; i++) {\n \t\trte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);\n \n@@ -1418,6 +1605,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)\n \t/* Promiscuous mode is propagated only to primary slave */\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n \tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n+\tcase BONDING_MODE_ALB:\n \tdefault:\n \t\trte_eth_promiscuous_enable(internals->current_primary_port);\n \t}\n@@ -1447,6 +1635,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)\n \t/* Promiscuous mode is propagated only to primary slave */\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n \tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n+\tcase BONDING_MODE_ALB:\n \tdefault:\n \t\trte_eth_promiscuous_disable(internals->current_primary_port);\n \t}\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h\nindex e01e66b..e69e301 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_private.h\n+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h\n@@ -43,6 +43,7 @@ extern \"C\" {\n \n #include \"rte_eth_bond.h\"\n #include \"rte_eth_bond_8023ad_private.h\"\n+#include \"rte_eth_bond_alb.h\"\n \n #define PMD_BOND_SLAVE_PORT_KVARG\t\t\t(\"slave\")\n #define PMD_BOND_PRIMARY_SLAVE_KVARG\t\t(\"primary\")\n@@ -152,6 +153,7 @@ struct bond_dev_private {\n \t/**< Arary of bonded slaves details */\n \n \tstruct mode8023ad_private mode4;\n+\tstruct mode_alb_private mode6;\n \n \tuint32_t rx_offload_capa;            /** Rx offload capability */\n \tuint32_t tx_offload_capa;            /** Tx offload capability */\n",
    "prefixes": [
        "dpdk-dev",
        "2/4"
    ]
}