xref: /dpdk/drivers/net/bonding/rte_eth_bond_alb.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2015 Intel Corporation
3  */
4 
5 #include "eth_bond_private.h"
6 #include "rte_eth_bond_alb.h"
7 
8 static inline uint8_t
9 simple_hash(uint8_t *hash_start, int hash_size)
10 {
11 	int i;
12 	uint8_t hash;
13 
14 	hash = 0;
15 	for (i = 0; i < hash_size; ++i)
16 		hash ^= hash_start[i];
17 
18 	return hash;
19 }
20 
21 static uint16_t
22 calculate_member(struct bond_dev_private *internals)
23 {
24 	uint16_t idx;
25 
26 	idx = (internals->mode6.last_member + 1) % internals->active_member_count;
27 	internals->mode6.last_member = idx;
28 	return internals->active_members[idx];
29 }
30 
31 int
32 bond_mode_alb_enable(struct rte_eth_dev *bond_dev)
33 {
34 	struct bond_dev_private *internals = bond_dev->data->dev_private;
35 	struct client_data *hash_table = internals->mode6.client_table;
36 
37 	uint16_t data_size;
38 	char mem_name[RTE_ETH_NAME_MAX_LEN];
39 	int socket_id = bond_dev->data->numa_node;
40 
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_member = ALB_NULL_INDEX;
45 	internals->mode6.ntt = 0;
46 
47 	/* Initialize memory pool for ARP packets to send */
48 	if (internals->mode6.mempool == NULL) {
49 		/*
50 		 * 256 is size of ETH header, ARP header and nested VLAN headers.
51 		 * The value is chosen to be cache aligned.
52 		 */
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);
61 
62 		if (internals->mode6.mempool == NULL) {
63 			RTE_BOND_LOG(ERR, "%s: Failed to initialize ALB mempool.",
64 				     bond_dev->device->name);
65 			goto mempool_alloc_error;
66 		}
67 	}
68 
69 	return 0;
70 
71 mempool_alloc_error:
72 	return -ENOMEM;
73 }
74 
75 void bond_mode_alb_arp_recv(struct rte_ether_hdr *eth_h, uint16_t offset,
76 		struct bond_dev_private *internals)
77 {
78 	struct rte_arp_hdr *arp;
79 
80 	struct client_data *hash_table = internals->mode6.client_table;
81 	struct client_data *client_info;
82 
83 	uint8_t hash_index;
84 
85 	arp = (struct rte_arp_hdr *)((char *)(eth_h + 1) + offset);
86 
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))
89 		return;
90 
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];
95 
96 	/*
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 member.
100 	 */
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
109 	) {
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->member_idx = calculate_member(internals);
116 		rte_eth_macaddr_get(client_info->member_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);
122 	}
123 	internals->mode6.ntt = 1;
124 	rte_spinlock_unlock(&internals->mode6.lock);
125 }
126 
127 uint16_t
128 bond_mode_alb_arp_xmit(struct rte_ether_hdr *eth_h, uint16_t offset,
129 		struct bond_dev_private *internals)
130 {
131 	struct rte_arp_hdr *arp;
132 
133 	struct client_data *hash_table = internals->mode6.client_table;
134 	struct client_data *client_info;
135 
136 	uint8_t hash_index;
137 
138 	struct rte_ether_addr bonding_mac;
139 
140 	arp = (struct rte_arp_hdr *)((char *)(eth_h + 1) + offset);
141 
142 	/*
143 	 * Traffic with src MAC other than bonding should be sent on
144 	 * current primary port.
145 	 */
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;
151 	}
152 
153 	hash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,
154 			sizeof(uint32_t));
155 	client_info = &hash_table[hash_index];
156 
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)) {
165 					rte_ether_addr_copy(
166 						&arp->arp_data.arp_tha,
167 						&client_info->cli_mac);
168 				}
169 				rte_eth_macaddr_get(client_info->member_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->member_idx;
177 			}
178 		}
179 
180 		/* Assign new member 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->member_idx = calculate_member(internals);
188 		rte_eth_macaddr_get(client_info->member_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->member_idx;
196 	}
197 
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;
203 }
204 
205 uint16_t
206 bond_mode_alb_arp_upd(struct client_data *client_info,
207 		struct rte_mbuf *pkt, struct bond_dev_private *internals)
208 {
209 	struct rte_ether_hdr *eth_h;
210 	struct rte_arp_hdr *arp_h;
211 	uint16_t member_idx;
212 
213 	rte_spinlock_lock(&internals->mode6.lock);
214 	eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
215 
216 	rte_ether_addr_copy(&client_info->app_mac, &eth_h->src_addr);
217 	rte_ether_addr_copy(&client_info->cli_mac, &eth_h->dst_addr);
218 	if (client_info->vlan_count > 0)
219 		eth_h->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
220 	else
221 		eth_h->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP);
222 
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));
226 
227 	memcpy(eth_h + 1, client_info->vlan,
228 			client_info->vlan_count * sizeof(struct rte_vlan_hdr));
229 
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;
234 
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);
240 
241 	member_idx = client_info->member_idx;
242 	rte_spinlock_unlock(&internals->mode6.lock);
243 
244 	return member_idx;
245 }
246 
247 void
248 bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)
249 {
250 	struct bond_dev_private *internals = bond_dev->data->dev_private;
251 	struct client_data *client_info;
252 
253 	int i;
254 
255 	/* If active member count is 0, it's pointless to refresh alb table */
256 	if (internals->active_member_count <= 0)
257 		return;
258 
259 	rte_spinlock_lock(&internals->mode6.lock);
260 	internals->mode6.last_member = ALB_NULL_INDEX;
261 
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->member_idx = calculate_member(internals);
266 			rte_eth_macaddr_get(client_info->member_idx, &client_info->app_mac);
267 			internals->mode6.ntt = 1;
268 		}
269 	}
270 	rte_spinlock_unlock(&internals->mode6.lock);
271 }
272