Line data Source code
1 : /* 2 : * SPDX-License-Identifier: Apache-2.0 3 : * Copyright(c) 2021 Cisco Systems, Inc. 4 : */ 5 : 6 : #include <vnet/vnet.h> 7 : #include <vnet/ethernet/ethernet.h> 8 : #include <vnet/ip/ip4_packet.h> 9 : #include <vnet/ip/ip6_packet.h> 10 : #include <vnet/hash/hash.h> 11 : #include <vppinfra/crc32.h> 12 : 13 : #ifdef clib_crc32c_uses_intrinsics 14 : 15 : static const u8 l4_mask_bits[256] = { 16 : [IP_PROTOCOL_ICMP] = 16, [IP_PROTOCOL_IGMP] = 8, 17 : [IP_PROTOCOL_TCP] = 32, [IP_PROTOCOL_UDP] = 32, 18 : [IP_PROTOCOL_IPSEC_ESP] = 32, [IP_PROTOCOL_IPSEC_AH] = 32, 19 : [IP_PROTOCOL_ICMP6] = 16, 20 : }; 21 : 22 : static_always_inline u32 23 0 : compute_ip6_key (ip6_header_t *ip) 24 : { 25 0 : u32 hash = 0, l4hdr; 26 : u8 pr; 27 : /* dst + src ip as u64 */ 28 0 : hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 8)); 29 0 : hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 16)); 30 0 : hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 24)); 31 0 : hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 32)); 32 0 : pr = ip->protocol; 33 0 : l4hdr = *(u32 *) ip6_next_header (ip) & pow2_mask (l4_mask_bits[pr]); 34 : /* protocol + l4 hdr */ 35 0 : return clib_crc32c_u64 (hash, ((u64) pr << 32) | l4hdr); 36 : } 37 : 38 : static_always_inline u32 39 0 : compute_ip4_key (ip4_header_t *ip) 40 : { 41 0 : u32 hash = 0, l4hdr; 42 : u8 pr; 43 : /* dst + src ip as u64 */ 44 0 : hash = clib_crc32c_u64 (0, *(u64 *) ((u8 *) ip + 12)); 45 0 : pr = ip->protocol; 46 0 : l4hdr = *(u32 *) ip4_next_header (ip) & pow2_mask (l4_mask_bits[pr]); 47 : /* protocol + l4 hdr */ 48 0 : return clib_crc32c_u64 (hash, ((u64) pr << 32) | l4hdr); 49 : } 50 : static_always_inline u32 51 0 : compute_ip_key (void *p) 52 : { 53 0 : if ((((u8 *) p)[0] & 0xf0) == 0x40) 54 0 : return compute_ip4_key (p); 55 0 : else if ((((u8 *) p)[0] & 0xf0) == 0x60) 56 0 : return compute_ip6_key (p); 57 0 : return 0; 58 : } 59 : 60 : void 61 0 : vnet_crc32c_5tuple_ip_func (void **p, u32 *hash, u32 n_packets) 62 : { 63 0 : u32 n_left_from = n_packets; 64 : 65 0 : while (n_left_from >= 8) 66 : { 67 0 : clib_prefetch_load (p[4]); 68 0 : clib_prefetch_load (p[5]); 69 0 : clib_prefetch_load (p[6]); 70 0 : clib_prefetch_load (p[7]); 71 : 72 0 : hash[0] = compute_ip_key (p[0]); 73 0 : hash[1] = compute_ip_key (p[1]); 74 0 : hash[2] = compute_ip_key (p[2]); 75 0 : hash[3] = compute_ip_key (p[3]); 76 : 77 0 : hash += 4; 78 0 : n_left_from -= 4; 79 0 : p += 4; 80 : } 81 : 82 0 : while (n_left_from > 0) 83 : { 84 0 : hash[0] = compute_ip_key (p[0]); 85 : 86 0 : hash += 1; 87 0 : n_left_from -= 1; 88 0 : p += 1; 89 : } 90 0 : } 91 : 92 : static_always_inline u32 93 0 : compute_ethernet_key (void *p) 94 : { 95 0 : u16 ethertype = 0, l2hdr_sz = 0; 96 : 97 0 : ethernet_header_t *eh = (ethernet_header_t *) p; 98 0 : ethertype = clib_net_to_host_u16 (eh->type); 99 0 : l2hdr_sz = sizeof (ethernet_header_t); 100 : 101 0 : if (ethernet_frame_is_tagged (ethertype)) 102 : { 103 0 : ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1); 104 : 105 0 : ethertype = clib_net_to_host_u16 (vlan->type); 106 0 : l2hdr_sz += sizeof (*vlan); 107 0 : while (ethernet_frame_is_tagged (ethertype)) 108 : { 109 0 : vlan++; 110 0 : ethertype = clib_net_to_host_u16 (vlan->type); 111 0 : l2hdr_sz += sizeof (*vlan); 112 : } 113 : } 114 : 115 0 : if (ethertype == ETHERNET_TYPE_IP4) 116 : { 117 0 : ip4_header_t *ip4 = (ip4_header_t *) (p + l2hdr_sz); 118 0 : return compute_ip4_key (ip4); 119 : } 120 0 : else if (ethertype == ETHERNET_TYPE_IP6) 121 : { 122 0 : ip6_header_t *ip6 = (ip6_header_t *) (p + l2hdr_sz); 123 0 : return compute_ip6_key (ip6); 124 : } 125 0 : return 0; 126 : } 127 : 128 : void 129 0 : vnet_crc32c_5tuple_ethernet_func (void **p, u32 *hash, u32 n_packets) 130 : { 131 0 : u32 n_left_from = n_packets; 132 : 133 0 : while (n_left_from >= 8) 134 : { 135 0 : clib_prefetch_load (p[4]); 136 0 : clib_prefetch_load (p[5]); 137 0 : clib_prefetch_load (p[6]); 138 0 : clib_prefetch_load (p[7]); 139 : 140 0 : hash[0] = compute_ethernet_key (p[0]); 141 0 : hash[1] = compute_ethernet_key (p[1]); 142 0 : hash[2] = compute_ethernet_key (p[2]); 143 0 : hash[3] = compute_ethernet_key (p[3]); 144 : 145 0 : hash += 4; 146 0 : n_left_from -= 4; 147 0 : p += 4; 148 : } 149 : 150 0 : while (n_left_from > 0) 151 : { 152 0 : hash[0] = compute_ethernet_key (p[0]); 153 : 154 0 : hash += 1; 155 0 : n_left_from -= 1; 156 0 : p += 1; 157 : } 158 0 : } 159 : 160 559 : VNET_REGISTER_HASH_FUNCTION (crc32c_5tuple, static) = { 161 : .name = "crc32c-5tuple", 162 : .description = "IPv4/IPv6 header and TCP/UDP ports", 163 : .priority = 50, 164 : .function[VNET_HASH_FN_TYPE_ETHERNET] = vnet_crc32c_5tuple_ethernet_func, 165 : .function[VNET_HASH_FN_TYPE_IP] = vnet_crc32c_5tuple_ip_func, 166 : }; 167 : 168 : #endif