4 * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "rte_eth_bond_private.h"
35 #include "rte_eth_bond_alb.h"
38 simple_hash(uint8_t *hash_start, int hash_size)
44 for (i = 0; i < hash_size; ++i)
45 hash ^= hash_start[i];
51 calculate_slave(struct bond_dev_private *internals)
55 idx = (internals->mode6.last_slave + 1) % internals->active_slave_count;
56 internals->mode6.last_slave = idx;
57 return internals->active_slaves[idx];
61 bond_mode_alb_enable(struct rte_eth_dev *bond_dev)
63 struct bond_dev_private *internals = bond_dev->data->dev_private;
64 struct client_data *hash_table = internals->mode6.client_table;
67 char mem_name[RTE_ETH_NAME_MAX_LEN];
68 int socket_id = bond_dev->data->numa_node;
70 /* Fill hash table with initial values */
71 memset(hash_table, 0, sizeof(struct client_data) * ALB_HASH_TABLE_SIZE);
72 rte_spinlock_init(&internals->mode6.lock);
73 internals->mode6.last_slave = ALB_NULL_INDEX;
74 internals->mode6.ntt = 0;
76 /* Initialize memory pool for ARP packets to send */
77 if (internals->mode6.mempool == NULL) {
79 * 256 is size of ETH header, ARP header and nested VLAN headers.
80 * The value is chosen to be cache aligned.
82 data_size = 256 + RTE_PKTMBUF_HEADROOM;
83 snprintf(mem_name, sizeof(mem_name), "%s_MODE6",
84 bond_dev->device->name);
85 internals->mode6.mempool = rte_pktmbuf_pool_create(mem_name,
86 512 * RTE_MAX_ETHPORTS,
87 RTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ?
88 32 : RTE_MEMPOOL_CACHE_MAX_SIZE,
89 0, data_size, socket_id);
91 if (internals->mode6.mempool == NULL) {
92 RTE_LOG(ERR, PMD, "%s: Failed to initialize ALB mempool.\n",
93 bond_dev->device->name);
94 goto mempool_alloc_error;
104 void bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
105 struct bond_dev_private *internals) {
108 struct client_data *hash_table = internals->mode6.client_table;
109 struct client_data *client_info;
113 arp = (struct arp_hdr *) ((char *) (eth_h + 1) + offset);
115 /* ARP Requests are forwarded to the application with no changes */
116 if (arp->arp_op != rte_cpu_to_be_16(ARP_OP_REPLY))
119 /* From now on, we analyze only ARP Reply packets */
120 hash_index = simple_hash((uint8_t *) &arp->arp_data.arp_sip,
121 sizeof(arp->arp_data.arp_sip));
122 client_info = &hash_table[hash_index];
125 * We got reply for ARP Request send by the application. We need to
126 * update client table when received data differ from what is stored
127 * in ALB table and issue sending update packet to that slave.
129 rte_spinlock_lock(&internals->mode6.lock);
130 if (client_info->in_use == 0 ||
131 client_info->app_ip != arp->arp_data.arp_tip ||
132 client_info->cli_ip != arp->arp_data.arp_sip ||
133 !is_same_ether_addr(&client_info->cli_mac, &arp->arp_data.arp_sha) ||
134 client_info->vlan_count != offset / sizeof(struct vlan_hdr) ||
135 memcmp(client_info->vlan, eth_h + 1, offset) != 0
137 client_info->in_use = 1;
138 client_info->app_ip = arp->arp_data.arp_tip;
139 client_info->cli_ip = arp->arp_data.arp_sip;
140 ether_addr_copy(&arp->arp_data.arp_sha, &client_info->cli_mac);
141 client_info->slave_idx = calculate_slave(internals);
142 rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
143 ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_tha);
144 memcpy(client_info->vlan, eth_h + 1, offset);
145 client_info->vlan_count = offset / sizeof(struct vlan_hdr);
147 internals->mode6.ntt = 1;
148 rte_spinlock_unlock(&internals->mode6.lock);
152 bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
153 struct bond_dev_private *internals)
157 struct client_data *hash_table = internals->mode6.client_table;
158 struct client_data *client_info;
162 struct ether_addr bonding_mac;
164 arp = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
167 * Traffic with src MAC other than bonding should be sent on
168 * current primary port.
170 rte_eth_macaddr_get(internals->port_id, &bonding_mac);
171 if (!is_same_ether_addr(&bonding_mac, &arp->arp_data.arp_sha)) {
172 rte_eth_macaddr_get(internals->current_primary_port,
173 &arp->arp_data.arp_sha);
174 return internals->current_primary_port;
177 hash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,
179 client_info = &hash_table[hash_index];
181 rte_spinlock_lock(&internals->mode6.lock);
182 if (arp->arp_op == rte_cpu_to_be_16(ARP_OP_REPLY)) {
183 if (client_info->in_use) {
184 if (client_info->app_ip == arp->arp_data.arp_sip &&
185 client_info->cli_ip == arp->arp_data.arp_tip) {
186 /* Entry is already assigned to this client */
187 if (!is_broadcast_ether_addr(&arp->arp_data.arp_tha)) {
188 ether_addr_copy(&arp->arp_data.arp_tha,
189 &client_info->cli_mac);
191 rte_eth_macaddr_get(client_info->slave_idx,
192 &client_info->app_mac);
193 ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
194 memcpy(client_info->vlan, eth_h + 1, offset);
195 client_info->vlan_count = offset / sizeof(struct vlan_hdr);
196 rte_spinlock_unlock(&internals->mode6.lock);
197 return client_info->slave_idx;
201 /* Assign new slave to this client and update src mac in ARP */
202 client_info->in_use = 1;
203 client_info->ntt = 0;
204 client_info->app_ip = arp->arp_data.arp_sip;
205 ether_addr_copy(&arp->arp_data.arp_tha, &client_info->cli_mac);
206 client_info->cli_ip = arp->arp_data.arp_tip;
207 client_info->slave_idx = calculate_slave(internals);
208 rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
209 ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
210 memcpy(client_info->vlan, eth_h + 1, offset);
211 client_info->vlan_count = offset / sizeof(struct vlan_hdr);
212 rte_spinlock_unlock(&internals->mode6.lock);
213 return client_info->slave_idx;
216 /* If packet is not ARP Reply, send it on current primary port. */
217 rte_spinlock_unlock(&internals->mode6.lock);
218 rte_eth_macaddr_get(internals->current_primary_port,
219 &arp->arp_data.arp_sha);
220 return internals->current_primary_port;
224 bond_mode_alb_arp_upd(struct client_data *client_info,
225 struct rte_mbuf *pkt, struct bond_dev_private *internals)
227 struct ether_hdr *eth_h;
228 struct arp_hdr *arp_h;
231 rte_spinlock_lock(&internals->mode6.lock);
232 eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
234 ether_addr_copy(&client_info->app_mac, ð_h->s_addr);
235 ether_addr_copy(&client_info->cli_mac, ð_h->d_addr);
236 if (client_info->vlan_count > 0)
237 eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
239 eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
241 arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr)
242 + client_info->vlan_count * sizeof(struct vlan_hdr));
244 memcpy(eth_h + 1, client_info->vlan,
245 client_info->vlan_count * sizeof(struct vlan_hdr));
247 ether_addr_copy(&client_info->app_mac, &arp_h->arp_data.arp_sha);
248 arp_h->arp_data.arp_sip = client_info->app_ip;
249 ether_addr_copy(&client_info->cli_mac, &arp_h->arp_data.arp_tha);
250 arp_h->arp_data.arp_tip = client_info->cli_ip;
252 arp_h->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
253 arp_h->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
254 arp_h->arp_hln = ETHER_ADDR_LEN;
255 arp_h->arp_pln = sizeof(uint32_t);
256 arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
258 slave_idx = client_info->slave_idx;
259 rte_spinlock_unlock(&internals->mode6.lock);
265 bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)
267 struct bond_dev_private *internals = bond_dev->data->dev_private;
268 struct client_data *client_info;
272 /* If active slave count is 0, it's pointless to refresh alb table */
273 if (internals->active_slave_count <= 0)
276 rte_spinlock_lock(&internals->mode6.lock);
277 internals->mode6.last_slave = ALB_NULL_INDEX;
279 for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
280 client_info = &internals->mode6.client_table[i];
281 if (client_info->in_use) {
282 client_info->slave_idx = calculate_slave(internals);
283 rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
284 internals->mode6.ntt = 1;
287 rte_spinlock_unlock(&internals->mode6.lock);