1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2015 Intel Corporation
5 #include "eth_bond_private.h"
6 #include "rte_eth_bond_alb.h"
9 simple_hash(uint8_t *hash_start, int hash_size)
15 for (i = 0; i < hash_size; ++i)
16 hash ^= hash_start[i];
22 calculate_slave(struct bond_dev_private *internals)
26 idx = (internals->mode6.last_slave + 1) % internals->active_slave_count;
27 internals->mode6.last_slave = idx;
28 return internals->active_slaves[idx];
32 bond_mode_alb_enable(struct rte_eth_dev *bond_dev)
34 struct bond_dev_private *internals = bond_dev->data->dev_private;
35 struct client_data *hash_table = internals->mode6.client_table;
38 char mem_name[RTE_ETH_NAME_MAX_LEN];
39 int socket_id = bond_dev->data->numa_node;
41 /* Fill hash table with initial values */
42 memset(hash_table, 0, sizeof(struct client_data) * ALB_HASH_TABLE_SIZE);
43 rte_spinlock_init(&internals->mode6.lock);
44 internals->mode6.last_slave = ALB_NULL_INDEX;
45 internals->mode6.ntt = 0;
47 /* Initialize memory pool for ARP packets to send */
48 if (internals->mode6.mempool == NULL) {
50 * 256 is size of ETH header, ARP header and nested VLAN headers.
51 * The value is chosen to be cache aligned.
53 data_size = 256 + RTE_PKTMBUF_HEADROOM;
54 snprintf(mem_name, sizeof(mem_name), "%s_ALB",
55 bond_dev->device->name);
56 internals->mode6.mempool = rte_pktmbuf_pool_create(mem_name,
57 512 * RTE_MAX_ETHPORTS,
58 RTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ?
59 32 : RTE_MEMPOOL_CACHE_MAX_SIZE,
60 0, data_size, socket_id);
62 if (internals->mode6.mempool == NULL) {
63 RTE_BOND_LOG(ERR, "%s: Failed to initialize ALB mempool.\n",
64 bond_dev->device->name);
65 goto mempool_alloc_error;
75 void bond_mode_alb_arp_recv(struct rte_ether_hdr *eth_h, uint16_t offset,
76 struct bond_dev_private *internals)
78 struct rte_arp_hdr *arp;
80 struct client_data *hash_table = internals->mode6.client_table;
81 struct client_data *client_info;
85 arp = (struct rte_arp_hdr *)((char *)(eth_h + 1) + offset);
87 /* ARP Requests are forwarded to the application with no changes */
88 if (arp->arp_opcode != rte_cpu_to_be_16(RTE_ARP_OP_REPLY))
91 /* From now on, we analyze only ARP Reply packets */
92 hash_index = simple_hash((uint8_t *) &arp->arp_data.arp_sip,
93 sizeof(arp->arp_data.arp_sip));
94 client_info = &hash_table[hash_index];
97 * We got reply for ARP Request send by the application. We need to
98 * update client table when received data differ from what is stored
99 * in ALB table and issue sending update packet to that slave.
101 rte_spinlock_lock(&internals->mode6.lock);
102 if (client_info->in_use == 0 ||
103 client_info->app_ip != arp->arp_data.arp_tip ||
104 client_info->cli_ip != arp->arp_data.arp_sip ||
105 !rte_is_same_ether_addr(&client_info->cli_mac,
106 &arp->arp_data.arp_sha) ||
107 client_info->vlan_count != offset / sizeof(struct rte_vlan_hdr) ||
108 memcmp(client_info->vlan, eth_h + 1, offset) != 0
110 client_info->in_use = 1;
111 client_info->app_ip = arp->arp_data.arp_tip;
112 client_info->cli_ip = arp->arp_data.arp_sip;
113 rte_ether_addr_copy(&arp->arp_data.arp_sha,
114 &client_info->cli_mac);
115 client_info->slave_idx = calculate_slave(internals);
116 rte_eth_macaddr_get(client_info->slave_idx,
117 &client_info->app_mac);
118 rte_ether_addr_copy(&client_info->app_mac,
119 &arp->arp_data.arp_tha);
120 memcpy(client_info->vlan, eth_h + 1, offset);
121 client_info->vlan_count = offset / sizeof(struct rte_vlan_hdr);
123 internals->mode6.ntt = 1;
124 rte_spinlock_unlock(&internals->mode6.lock);
128 bond_mode_alb_arp_xmit(struct rte_ether_hdr *eth_h, uint16_t offset,
129 struct bond_dev_private *internals)
131 struct rte_arp_hdr *arp;
133 struct client_data *hash_table = internals->mode6.client_table;
134 struct client_data *client_info;
138 struct rte_ether_addr bonding_mac;
140 arp = (struct rte_arp_hdr *)((char *)(eth_h + 1) + offset);
143 * Traffic with src MAC other than bonding should be sent on
144 * current primary port.
146 rte_eth_macaddr_get(internals->port_id, &bonding_mac);
147 if (!rte_is_same_ether_addr(&bonding_mac, &arp->arp_data.arp_sha)) {
148 rte_eth_macaddr_get(internals->current_primary_port,
149 &arp->arp_data.arp_sha);
150 return internals->current_primary_port;
153 hash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,
155 client_info = &hash_table[hash_index];
157 rte_spinlock_lock(&internals->mode6.lock);
158 if (arp->arp_opcode == rte_cpu_to_be_16(RTE_ARP_OP_REPLY)) {
159 if (client_info->in_use) {
160 if (client_info->app_ip == arp->arp_data.arp_sip &&
161 client_info->cli_ip == arp->arp_data.arp_tip) {
162 /* Entry is already assigned to this client */
163 if (!rte_is_broadcast_ether_addr(
164 &arp->arp_data.arp_tha)) {
166 &arp->arp_data.arp_tha,
167 &client_info->cli_mac);
169 rte_eth_macaddr_get(client_info->slave_idx,
170 &client_info->app_mac);
171 rte_ether_addr_copy(&client_info->app_mac,
172 &arp->arp_data.arp_sha);
173 memcpy(client_info->vlan, eth_h + 1, offset);
174 client_info->vlan_count = offset / sizeof(struct rte_vlan_hdr);
175 rte_spinlock_unlock(&internals->mode6.lock);
176 return client_info->slave_idx;
180 /* Assign new slave to this client and update src mac in ARP */
181 client_info->in_use = 1;
182 client_info->ntt = 0;
183 client_info->app_ip = arp->arp_data.arp_sip;
184 rte_ether_addr_copy(&arp->arp_data.arp_tha,
185 &client_info->cli_mac);
186 client_info->cli_ip = arp->arp_data.arp_tip;
187 client_info->slave_idx = calculate_slave(internals);
188 rte_eth_macaddr_get(client_info->slave_idx,
189 &client_info->app_mac);
190 rte_ether_addr_copy(&client_info->app_mac,
191 &arp->arp_data.arp_sha);
192 memcpy(client_info->vlan, eth_h + 1, offset);
193 client_info->vlan_count = offset / sizeof(struct rte_vlan_hdr);
194 rte_spinlock_unlock(&internals->mode6.lock);
195 return client_info->slave_idx;
198 /* If packet is not ARP Reply, send it on current primary port. */
199 rte_spinlock_unlock(&internals->mode6.lock);
200 rte_eth_macaddr_get(internals->current_primary_port,
201 &arp->arp_data.arp_sha);
202 return internals->current_primary_port;
206 bond_mode_alb_arp_upd(struct client_data *client_info,
207 struct rte_mbuf *pkt, struct bond_dev_private *internals)
209 struct rte_ether_hdr *eth_h;
210 struct rte_arp_hdr *arp_h;
213 rte_spinlock_lock(&internals->mode6.lock);
214 eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
216 rte_ether_addr_copy(&client_info->app_mac, ð_h->s_addr);
217 rte_ether_addr_copy(&client_info->cli_mac, ð_h->d_addr);
218 if (client_info->vlan_count > 0)
219 eth_h->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
221 eth_h->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP);
223 arp_h = (struct rte_arp_hdr *)(
224 (char *)eth_h + sizeof(struct rte_ether_hdr)
225 + client_info->vlan_count * sizeof(struct rte_vlan_hdr));
227 memcpy(eth_h + 1, client_info->vlan,
228 client_info->vlan_count * sizeof(struct rte_vlan_hdr));
230 rte_ether_addr_copy(&client_info->app_mac, &arp_h->arp_data.arp_sha);
231 arp_h->arp_data.arp_sip = client_info->app_ip;
232 rte_ether_addr_copy(&client_info->cli_mac, &arp_h->arp_data.arp_tha);
233 arp_h->arp_data.arp_tip = client_info->cli_ip;
235 arp_h->arp_hardware = rte_cpu_to_be_16(RTE_ARP_HRD_ETHER);
236 arp_h->arp_protocol = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
237 arp_h->arp_hlen = RTE_ETHER_ADDR_LEN;
238 arp_h->arp_plen = sizeof(uint32_t);
239 arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
241 slave_idx = client_info->slave_idx;
242 rte_spinlock_unlock(&internals->mode6.lock);
248 bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)
250 struct bond_dev_private *internals = bond_dev->data->dev_private;
251 struct client_data *client_info;
255 /* If active slave count is 0, it's pointless to refresh alb table */
256 if (internals->active_slave_count <= 0)
259 rte_spinlock_lock(&internals->mode6.lock);
260 internals->mode6.last_slave = ALB_NULL_INDEX;
262 for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
263 client_info = &internals->mode6.client_table[i];
264 if (client_info->in_use) {
265 client_info->slave_idx = calculate_slave(internals);
266 rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
267 internals->mode6.ntt = 1;
270 rte_spinlock_unlock(&internals->mode6.lock);