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, ð_h->src_addr); 217 rte_ether_addr_copy(&client_info->cli_mac, ð_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