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
);