Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2015 Cisco and/or its affiliates. |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at: |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | /* |
| 16 | * ip/ip_lookup.h: ip (4 or 6) lookup structures, adjacencies, ... |
| 17 | * |
| 18 | * Copyright (c) 2008 Eliot Dresselhaus |
| 19 | * |
| 20 | * Permission is hereby granted, free of charge, to any person obtaining |
| 21 | * a copy of this software and associated documentation files (the |
| 22 | * "Software"), to deal in the Software without restriction, including |
| 23 | * without limitation the rights to use, copy, modify, merge, publish, |
| 24 | * distribute, sublicense, and/or sell copies of the Software, and to |
| 25 | * permit persons to whom the Software is furnished to do so, subject to |
| 26 | * the following conditions: |
| 27 | * |
| 28 | * The above copyright notice and this permission notice shall be |
| 29 | * included in all copies or substantial portions of the Software. |
| 30 | * |
| 31 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 32 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 33 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 34 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 35 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 36 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 37 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 38 | */ |
| 39 | |
| 40 | #ifndef included_ip_lookup_h |
| 41 | #define included_ip_lookup_h |
| 42 | |
| 43 | #include <vnet/vnet.h> |
| 44 | #include <vlib/buffer.h> |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 45 | #include <vnet/ip/ip4_packet.h> |
Pierre Pfister | 1dabaaf | 2016-04-25 14:15:15 +0100 | [diff] [blame] | 46 | #include <vnet/ip/ip6_packet.h> |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 47 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 48 | /** @brief Common (IP4/IP6) next index stored in adjacency. */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 49 | typedef enum { |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 50 | /** Packet does not match any route in table. */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 51 | IP_LOOKUP_NEXT_MISS, |
| 52 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 53 | /** Adjacency to drop this packet. */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 54 | IP_LOOKUP_NEXT_DROP, |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 55 | /** Adjacency to punt this packet. */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 56 | IP_LOOKUP_NEXT_PUNT, |
| 57 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 58 | /** This packet is for one of our own IP addresses. */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 59 | IP_LOOKUP_NEXT_LOCAL, |
| 60 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 61 | /** This packet matches an "interface route" and packets |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 62 | need to be passed to ARP to find rewrite string for |
| 63 | this destination. */ |
| 64 | IP_LOOKUP_NEXT_ARP, |
| 65 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 66 | /** This packet is to be rewritten and forwarded to the next |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 67 | processing node. This is typically the output interface but |
| 68 | might be another node for further output processing. */ |
| 69 | IP_LOOKUP_NEXT_REWRITE, |
| 70 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 71 | /** This packet needs to be classified */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 72 | IP_LOOKUP_NEXT_CLASSIFY, |
| 73 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 74 | /** This packet needs to go to MAP - RFC7596, RFC7597 */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 75 | IP_LOOKUP_NEXT_MAP, |
| 76 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 77 | /** This packet needs to go to MAP with Translation - RFC7599 */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 78 | IP_LOOKUP_NEXT_MAP_T, |
| 79 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 80 | /** This packets needs to go to indirect next hop */ |
Damjan Marion | aca64c9 | 2016-04-13 09:48:56 +0200 | [diff] [blame] | 81 | IP_LOOKUP_NEXT_INDIRECT, |
| 82 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 83 | /** This packets needs to go to ICMP error */ |
Ole Troan | 944f548 | 2016-05-24 11:56:58 +0200 | [diff] [blame] | 84 | IP_LOOKUP_NEXT_ICMP_ERROR, |
| 85 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 86 | IP_LOOKUP_N_NEXT, |
| 87 | } ip_lookup_next_t; |
| 88 | |
Ole Troan | f0f8522 | 2016-06-14 21:12:32 +0200 | [diff] [blame] | 89 | typedef enum { |
| 90 | IP4_LOOKUP_N_NEXT = IP_LOOKUP_N_NEXT, |
| 91 | } ip4_lookup_next_t; |
| 92 | |
| 93 | typedef enum { |
| 94 | /* Hop-by-hop header handling */ |
| 95 | IP6_LOOKUP_NEXT_HOP_BY_HOP = IP_LOOKUP_N_NEXT, |
| 96 | IP6_LOOKUP_NEXT_ADD_HOP_BY_HOP, |
| 97 | IP6_LOOKUP_NEXT_POP_HOP_BY_HOP, |
| 98 | IP6_LOOKUP_N_NEXT, |
| 99 | } ip6_lookup_next_t; |
| 100 | |
Damjan Marion | b270789 | 2016-04-13 11:21:07 +0200 | [diff] [blame] | 101 | #define IP4_LOOKUP_NEXT_NODES { \ |
| 102 | [IP_LOOKUP_NEXT_MISS] = "ip4-miss", \ |
| 103 | [IP_LOOKUP_NEXT_DROP] = "ip4-drop", \ |
| 104 | [IP_LOOKUP_NEXT_PUNT] = "ip4-punt", \ |
| 105 | [IP_LOOKUP_NEXT_LOCAL] = "ip4-local", \ |
| 106 | [IP_LOOKUP_NEXT_ARP] = "ip4-arp", \ |
| 107 | [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite-transit", \ |
| 108 | [IP_LOOKUP_NEXT_CLASSIFY] = "ip4-classify", \ |
| 109 | [IP_LOOKUP_NEXT_MAP] = "ip4-map", \ |
| 110 | [IP_LOOKUP_NEXT_MAP_T] = "ip4-map-t", \ |
Damjan Marion | aca64c9 | 2016-04-13 09:48:56 +0200 | [diff] [blame] | 111 | [IP_LOOKUP_NEXT_INDIRECT] = "ip4-indirect", \ |
Ole Troan | 944f548 | 2016-05-24 11:56:58 +0200 | [diff] [blame] | 112 | [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip4-icmp-error", \ |
Damjan Marion | b270789 | 2016-04-13 11:21:07 +0200 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | #define IP6_LOOKUP_NEXT_NODES { \ |
| 116 | [IP_LOOKUP_NEXT_MISS] = "ip6-miss", \ |
| 117 | [IP_LOOKUP_NEXT_DROP] = "ip6-drop", \ |
| 118 | [IP_LOOKUP_NEXT_PUNT] = "ip6-punt", \ |
| 119 | [IP_LOOKUP_NEXT_LOCAL] = "ip6-local", \ |
| 120 | [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor", \ |
| 121 | [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite", \ |
| 122 | [IP_LOOKUP_NEXT_CLASSIFY] = "ip6-classify", \ |
| 123 | [IP_LOOKUP_NEXT_MAP] = "ip6-map", \ |
| 124 | [IP_LOOKUP_NEXT_MAP_T] = "ip6-map-t", \ |
Damjan Marion | aca64c9 | 2016-04-13 09:48:56 +0200 | [diff] [blame] | 125 | [IP_LOOKUP_NEXT_INDIRECT] = "ip6-indirect", \ |
Ole Troan | 944f548 | 2016-05-24 11:56:58 +0200 | [diff] [blame] | 126 | [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip6-icmp-error", \ |
Ole Troan | f0f8522 | 2016-06-14 21:12:32 +0200 | [diff] [blame] | 127 | [IP6_LOOKUP_NEXT_HOP_BY_HOP] = "ip6-hop-by-hop", \ |
| 128 | [IP6_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip6-add-hop-by-hop", \ |
| 129 | [IP6_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip6-pop-hop-by-hop", \ |
Damjan Marion | b270789 | 2016-04-13 11:21:07 +0200 | [diff] [blame] | 130 | } |
| 131 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 132 | /* Flow hash configuration */ |
| 133 | #define IP_FLOW_HASH_SRC_ADDR (1<<0) |
| 134 | #define IP_FLOW_HASH_DST_ADDR (1<<1) |
| 135 | #define IP_FLOW_HASH_PROTO (1<<2) |
| 136 | #define IP_FLOW_HASH_SRC_PORT (1<<3) |
| 137 | #define IP_FLOW_HASH_DST_PORT (1<<4) |
| 138 | #define IP_FLOW_HASH_REVERSE_SRC_DST (1<<5) |
| 139 | |
| 140 | /* Default: 5-tuple without the "reverse" bit */ |
| 141 | #define IP_FLOW_HASH_DEFAULT (0x1F) |
| 142 | |
| 143 | #define foreach_flow_hash_bit \ |
| 144 | _(src, IP_FLOW_HASH_SRC_ADDR) \ |
| 145 | _(dst, IP_FLOW_HASH_DST_ADDR) \ |
| 146 | _(sport, IP_FLOW_HASH_SRC_PORT) \ |
| 147 | _(dport, IP_FLOW_HASH_DST_PORT) \ |
| 148 | _(proto, IP_FLOW_HASH_PROTO) \ |
| 149 | _(reverse, IP_FLOW_HASH_REVERSE_SRC_DST) |
| 150 | |
Pierre Pfister | fd8181b | 2016-07-16 08:51:16 +0100 | [diff] [blame] | 151 | #define IP_ADJACENCY_OPAQUE_SZ 16 |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 152 | /* IP unicast adjacency. */ |
| 153 | typedef struct { |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 154 | CLIB_CACHE_LINE_ALIGN_MARK(cacheline0); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 155 | /* Handle for this adjacency in adjacency heap. */ |
| 156 | u32 heap_handle; |
| 157 | |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 158 | STRUCT_MARK(signature_start); |
| 159 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 160 | /* Interface address index for this local/arp adjacency. */ |
| 161 | u32 if_address_index; |
| 162 | |
| 163 | /* Number of adjecencies in block. Greater than 1 means multipath; |
| 164 | otherwise equal to 1. */ |
| 165 | u16 n_adj; |
| 166 | |
| 167 | /* Next hop after ip4-lookup. */ |
| 168 | union { |
| 169 | ip_lookup_next_t lookup_next_index : 16; |
| 170 | u16 lookup_next_index_as_int; |
| 171 | }; |
| 172 | |
| 173 | /* Force re-lookup in a different FIB. ~0 => normal behavior */ |
| 174 | i16 explicit_fib_index; |
| 175 | u16 mcast_group_index; |
| 176 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 177 | /* Highest possible perf subgraph arc interposition, e.g. for ip6 ioam */ |
| 178 | u16 saved_lookup_next_index; |
| 179 | |
Damjan Marion | f1bd8be | 2016-03-29 13:06:36 +0200 | [diff] [blame] | 180 | union { |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 181 | /* IP_LOOKUP_NEXT_ARP only */ |
| 182 | struct { |
Pierre Pfister | 1dabaaf | 2016-04-25 14:15:15 +0100 | [diff] [blame] | 183 | ip46_address_t next_hop; |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 184 | } arp; |
Damjan Marion | f1bd8be | 2016-03-29 13:06:36 +0200 | [diff] [blame] | 185 | /* IP_LOOKUP_NEXT_CLASSIFY only */ |
| 186 | struct { |
| 187 | u16 table_index; |
| 188 | } classify; |
Damjan Marion | aca64c9 | 2016-04-13 09:48:56 +0200 | [diff] [blame] | 189 | /* IP_LOOKUP_NEXT_INDIRECT only */ |
| 190 | struct { |
| 191 | ip46_address_t next_hop; |
| 192 | } indirect; |
Pierre Pfister | fd8181b | 2016-07-16 08:51:16 +0100 | [diff] [blame] | 193 | u8 opaque[IP_ADJACENCY_OPAQUE_SZ]; |
Damjan Marion | f1bd8be | 2016-03-29 13:06:36 +0200 | [diff] [blame] | 194 | }; |
| 195 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 196 | /* |
| 197 | * Special format function for this adjacency. |
| 198 | * Specifically good for cases which use the entire rewrite |
| 199 | * for their own purposes. Can easily reduce to a u16 or a u8 if/when |
| 200 | * the first cache line reads "full" on the free space gas gauge. |
| 201 | */ |
| 202 | u32 special_adjacency_format_function_index; /* 0 is invalid */ |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 203 | STRUCT_MARK(signature_end); |
| 204 | |
| 205 | /* Number of FIB entries sharing this adjacency */ |
| 206 | u32 share_count; |
| 207 | /* Use this adjacency instead */ |
| 208 | u32 next_adj_with_signature; |
| 209 | |
| 210 | CLIB_CACHE_LINE_ALIGN_MARK(cacheline1); |
| 211 | |
| 212 | /* Rewrite in second/third cache lines */ |
| 213 | vnet_declare_rewrite (VLIB_BUFFER_PRE_DATA_SIZE); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 214 | } ip_adjacency_t; |
| 215 | |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 216 | static inline uword |
| 217 | vnet_ip_adjacency_signature (ip_adjacency_t * adj) |
| 218 | { |
| 219 | uword signature = 0xfeedfaceULL; |
| 220 | |
| 221 | /* Skip heap handle, sum everything up to but not including share_count */ |
Christophe Fontaine | fef15b4 | 2016-04-09 12:38:49 +0900 | [diff] [blame] | 222 | signature = hash_memory |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 223 | (STRUCT_MARK_PTR(adj, signature_start), |
| 224 | STRUCT_OFFSET_OF(ip_adjacency_t, signature_end) |
| 225 | - STRUCT_OFFSET_OF(ip_adjacency_t, signature_start), |
| 226 | signature); |
| 227 | |
| 228 | /* and the rewrite */ |
Christophe Fontaine | fef15b4 | 2016-04-09 12:38:49 +0900 | [diff] [blame] | 229 | signature = hash_memory (&adj->rewrite_header, VLIB_BUFFER_PRE_DATA_SIZE, |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 230 | signature); |
| 231 | return signature; |
| 232 | } |
| 233 | |
| 234 | static inline int |
| 235 | vnet_ip_adjacency_share_compare (ip_adjacency_t * a1, ip_adjacency_t *a2) |
| 236 | { |
| 237 | if (memcmp (STRUCT_MARK_PTR(a1, signature_start), |
| 238 | STRUCT_MARK_PTR(a2, signature_start), |
| 239 | STRUCT_OFFSET_OF(ip_adjacency_t, signature_end) |
| 240 | - STRUCT_OFFSET_OF(ip_adjacency_t, signature_start))) |
| 241 | return 0; |
| 242 | if (memcmp (&a1->rewrite_header, &a2->rewrite_header, |
| 243 | VLIB_BUFFER_PRE_DATA_SIZE)) |
| 244 | return 0; |
| 245 | return 1; |
| 246 | } |
| 247 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 248 | /* Index into adjacency table. */ |
| 249 | typedef u32 ip_adjacency_index_t; |
| 250 | |
| 251 | typedef struct { |
| 252 | /* Directly connected next-hop adjacency index. */ |
| 253 | u32 next_hop_adj_index; |
| 254 | |
| 255 | /* Path weight for this adjacency. */ |
| 256 | u32 weight; |
| 257 | } ip_multipath_next_hop_t; |
| 258 | |
| 259 | typedef struct { |
| 260 | /* Adjacency index of first index in block. */ |
| 261 | u32 adj_index; |
| 262 | |
| 263 | /* Power of 2 size of adjacency block. */ |
| 264 | u32 n_adj_in_block; |
| 265 | |
| 266 | /* Number of prefixes that point to this adjacency. */ |
| 267 | u32 reference_count; |
| 268 | |
| 269 | /* Normalized next hops are used as hash keys: they are sorted by weight |
| 270 | and weights are chosen so they add up to 1 << log2_n_adj_in_block (with |
| 271 | zero-weighted next hops being deleted). |
| 272 | Unnormalized next hops are saved so that control plane has a record of exactly |
| 273 | what the RIB told it. */ |
| 274 | struct { |
| 275 | /* Number of hops in the multipath. */ |
| 276 | u32 count; |
| 277 | |
| 278 | /* Offset into next hop heap for this block. */ |
| 279 | u32 heap_offset; |
| 280 | |
| 281 | /* Heap handle used to for example free block when we're done with it. */ |
| 282 | u32 heap_handle; |
| 283 | } normalized_next_hops, unnormalized_next_hops; |
| 284 | } ip_multipath_adjacency_t; |
| 285 | |
| 286 | /* IP multicast adjacency. */ |
| 287 | typedef struct { |
| 288 | /* Handle for this adjacency in adjacency heap. */ |
| 289 | u32 heap_handle; |
| 290 | |
| 291 | /* Number of adjecencies in block. */ |
| 292 | u32 n_adj; |
| 293 | |
| 294 | /* Rewrite string. */ |
| 295 | vnet_declare_rewrite (64 - 2*sizeof(u32)); |
| 296 | } ip_multicast_rewrite_t; |
| 297 | |
| 298 | typedef struct { |
| 299 | /* ip4-multicast-rewrite next index. */ |
| 300 | u32 next_index; |
| 301 | |
| 302 | u8 n_rewrite_bytes; |
| 303 | |
| 304 | u8 rewrite_string[64 - 1*sizeof(u32) - 1*sizeof(u8)]; |
| 305 | } ip_multicast_rewrite_string_t; |
| 306 | |
| 307 | typedef struct { |
| 308 | ip_multicast_rewrite_t * rewrite_heap; |
| 309 | |
| 310 | ip_multicast_rewrite_string_t * rewrite_strings; |
| 311 | |
| 312 | /* Negative rewrite string index; >= 0 sw_if_index. |
| 313 | Sorted. Used to hash. */ |
| 314 | i32 ** adjacency_id_vector; |
| 315 | |
| 316 | uword * adjacency_by_id_vector; |
| 317 | } ip_multicast_lookup_main_t; |
| 318 | |
| 319 | typedef struct { |
| 320 | /* Key for mhash; in fact, just a byte offset into mhash key vector. */ |
| 321 | u32 address_key; |
| 322 | |
| 323 | /* Interface which has this address. */ |
| 324 | u32 sw_if_index; |
| 325 | |
| 326 | /* Adjacency for neighbor probe (ARP) for this interface address. */ |
| 327 | u32 neighbor_probe_adj_index; |
| 328 | |
| 329 | /* Address (prefix) length for this interface. */ |
| 330 | u16 address_length; |
| 331 | |
| 332 | /* Will be used for something eventually. Primary vs. secondary? */ |
| 333 | u16 flags; |
| 334 | |
| 335 | /* Next and previous pointers for doubly linked list of |
| 336 | addresses per software interface. */ |
| 337 | u32 next_this_sw_interface; |
| 338 | u32 prev_this_sw_interface; |
| 339 | } ip_interface_address_t; |
| 340 | |
| 341 | typedef enum { |
| 342 | IP_LOCAL_NEXT_DROP, |
| 343 | IP_LOCAL_NEXT_PUNT, |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 344 | IP_LOCAL_NEXT_UDP_LOOKUP, |
| 345 | IP_LOCAL_NEXT_ICMP, |
| 346 | IP_LOCAL_N_NEXT, |
| 347 | } ip_local_next_t; |
| 348 | |
| 349 | struct ip_lookup_main_t; |
| 350 | |
| 351 | typedef void (* ip_add_del_adjacency_callback_t) (struct ip_lookup_main_t * lm, |
| 352 | u32 adj_index, |
| 353 | ip_adjacency_t * adj, |
| 354 | u32 is_del); |
| 355 | |
| 356 | typedef struct { |
| 357 | vnet_config_main_t config_main; |
| 358 | |
| 359 | u32 * config_index_by_sw_if_index; |
| 360 | } ip_config_main_t; |
| 361 | |
Pierre Pfister | 4c3f393 | 2016-07-27 17:46:11 +0100 | [diff] [blame] | 362 | //Function type used to register formatting of a custom adjacency formatting |
| 363 | typedef u8 *(* ip_adjacency_format_fn)(u8 * s, |
| 364 | struct ip_lookup_main_t * lm, |
| 365 | ip_adjacency_t *adj); |
| 366 | |
| 367 | typedef struct ip_adj_register_struct { |
| 368 | struct ip_adj_register_struct *next; |
| 369 | char *node_name; //Name of the node for this registered adjacency |
| 370 | ip_adjacency_format_fn fn; //Formatting function of this adjacency |
| 371 | u32 *next_index; //some place where the next index to be used will be put at init |
| 372 | } ip_adj_register_t; |
| 373 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 374 | typedef struct ip_lookup_main_t { |
| 375 | /* Adjacency heap. */ |
| 376 | ip_adjacency_t * adjacency_heap; |
| 377 | |
| 378 | /* Adjacency packet/byte counters indexed by adjacency index. */ |
| 379 | vlib_combined_counter_main_t adjacency_counters; |
| 380 | |
| 381 | /* Heap of (next hop, weight) blocks. Sorted by next hop. */ |
| 382 | ip_multipath_next_hop_t * next_hop_heap; |
| 383 | |
| 384 | /* Indexed by heap_handle from ip_adjacency_t. */ |
| 385 | ip_multipath_adjacency_t * multipath_adjacencies; |
| 386 | |
Dave Barach | dbf19ca | 2016-03-15 10:21:54 +0100 | [diff] [blame] | 387 | /* Adjacency by signature hash */ |
| 388 | uword * adj_index_by_signature; |
| 389 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 390 | /* Temporary vectors for looking up next hops in hash. */ |
| 391 | ip_multipath_next_hop_t * next_hop_hash_lookup_key; |
| 392 | ip_multipath_next_hop_t * next_hop_hash_lookup_key_normalized; |
| 393 | |
| 394 | /* Hash table mapping normalized next hops and weights |
| 395 | to multipath adjacency index. */ |
| 396 | uword * multipath_adjacency_by_next_hops; |
| 397 | |
| 398 | u32 * adjacency_remap_table; |
| 399 | u32 n_adjacency_remaps; |
| 400 | |
| 401 | /* If average error per adjacency is less than this threshold adjacency block |
| 402 | size is accepted. */ |
| 403 | f64 multipath_next_hop_error_tolerance; |
| 404 | |
| 405 | /* Adjacency index for routing table misses, local punts, and drops. */ |
| 406 | u32 miss_adj_index, drop_adj_index, local_adj_index; |
| 407 | |
| 408 | /* Miss adjacency is always first in adjacency table. */ |
| 409 | #define IP_LOOKUP_MISS_ADJ_INDEX 0 |
| 410 | |
| 411 | ip_add_del_adjacency_callback_t * add_del_adjacency_callbacks; |
| 412 | |
| 413 | /* Pool of addresses that are assigned to interfaces. */ |
| 414 | ip_interface_address_t * if_address_pool; |
| 415 | |
| 416 | /* Hash table mapping address to index in interface address pool. */ |
| 417 | mhash_t address_to_if_address_index; |
| 418 | |
| 419 | /* Head of doubly linked list of interface addresses for each software interface. |
| 420 | ~0 means this interface has no address. */ |
| 421 | u32 * if_address_pool_index_by_sw_if_index; |
| 422 | |
| 423 | /* First table index to use for this interface, ~0 => none */ |
| 424 | u32 * classify_table_index_by_sw_if_index; |
| 425 | |
| 426 | /* rx/tx interface/feature configuration. */ |
| 427 | ip_config_main_t rx_config_mains[VNET_N_CAST], tx_config_main; |
| 428 | |
| 429 | /* Number of bytes in a fib result. Must be at least |
| 430 | sizeof (uword). First word is always adjacency index. */ |
| 431 | u32 fib_result_n_bytes, fib_result_n_words; |
| 432 | |
| 433 | format_function_t * format_fib_result; |
| 434 | |
| 435 | /* 1 for ip6; 0 for ip4. */ |
| 436 | u32 is_ip6; |
| 437 | |
| 438 | /* Either format_ip4_address_and_length or format_ip6_address_and_length. */ |
| 439 | format_function_t * format_address_and_length; |
| 440 | |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 441 | /* Special adjacency format functions */ |
| 442 | format_function_t ** special_adjacency_format_functions; |
| 443 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 444 | /* Table mapping ip protocol to ip[46]-local node next index. */ |
| 445 | u8 local_next_by_ip_protocol[256]; |
| 446 | |
| 447 | /* IP_BUILTIN_PROTOCOL_{TCP,UDP,ICMP,OTHER} by protocol in IP header. */ |
| 448 | u8 builtin_protocol_by_ip_protocol[256]; |
Pierre Pfister | 4c3f393 | 2016-07-27 17:46:11 +0100 | [diff] [blame] | 449 | |
| 450 | /* Registered adjacencies */ |
| 451 | ip_adj_register_t *registered_adjacencies; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 452 | } ip_lookup_main_t; |
| 453 | |
| 454 | always_inline ip_adjacency_t * |
| 455 | ip_get_adjacency (ip_lookup_main_t * lm, |
| 456 | u32 adj_index) |
| 457 | { |
| 458 | ip_adjacency_t * adj; |
| 459 | |
Dave Barach | b2ef4dd | 2016-03-23 08:56:01 -0400 | [diff] [blame] | 460 | adj = vec_elt_at_index (lm->adjacency_heap, adj_index); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 461 | |
Dave Barach | b2ef4dd | 2016-03-23 08:56:01 -0400 | [diff] [blame] | 462 | ASSERT (adj->heap_handle != ~0); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 463 | |
| 464 | return adj; |
| 465 | } |
| 466 | |
| 467 | #define ip_prefetch_adjacency(lm,adj_index,type) \ |
| 468 | do { \ |
| 469 | ip_adjacency_t * _adj = (lm)->adjacency_heap + (adj_index); \ |
| 470 | CLIB_PREFETCH (_adj, sizeof (_adj[0]), type); \ |
| 471 | } while (0) |
| 472 | |
Pierre Pfister | 4c3f393 | 2016-07-27 17:46:11 +0100 | [diff] [blame] | 473 | /* Adds a next node to ip4 or ip6 lookup node which can be then used in adjacencies. |
| 474 | * @param vlib_main pointer |
| 475 | * @param lm ip4_main.lookup_main or ip6_main.lookup_main |
| 476 | * @param reg registration structure |
| 477 | * @param next_node_index Returned index to be used in adjacencies. |
| 478 | * @return 0 on success. -1 on failure. |
| 479 | */ |
| 480 | int ip_register_adjacency(vlib_main_t *vm, u8 is_ip4, |
| 481 | ip_adj_register_t *reg); |
| 482 | |
| 483 | /* |
| 484 | * Construction helpers to add IP adjacency at init. |
| 485 | */ |
| 486 | #define VNET_IP_REGISTER_ADJACENCY(ip,x,...) \ |
| 487 | __VA_ARGS__ ip_adj_register_t ip##adj_##x; \ |
| 488 | static void __vnet_##ip##_register_adjacency_##x (void) \ |
| 489 | __attribute__((__constructor__)) ; \ |
| 490 | static void __vnet_##ip##_register_adjacency_##x (void) \ |
| 491 | { \ |
| 492 | ip_lookup_main_t *lm = &ip##_main.lookup_main; \ |
| 493 | ip##adj_##x.next = lm->registered_adjacencies; \ |
| 494 | lm->registered_adjacencies = &ip##adj_##x; \ |
| 495 | } \ |
| 496 | __VA_ARGS__ ip_adj_register_t ip##adj_##x |
| 497 | |
| 498 | #define VNET_IP4_REGISTER_ADJACENCY(x,...) \ |
| 499 | VNET_IP_REGISTER_ADJACENCY(ip4, x, __VA_ARGS__) |
| 500 | |
| 501 | #define VNET_IP6_REGISTER_ADJACENCY(x,...) \ |
| 502 | VNET_IP_REGISTER_ADJACENCY(ip6, x, __VA_ARGS__) |
| 503 | |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 504 | static inline void |
| 505 | ip_register_add_del_adjacency_callback(ip_lookup_main_t * lm, |
| 506 | ip_add_del_adjacency_callback_t cb) |
| 507 | { |
| 508 | vec_add1(lm->add_del_adjacency_callbacks, cb); |
| 509 | } |
| 510 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 511 | always_inline void |
| 512 | ip_call_add_del_adjacency_callbacks (ip_lookup_main_t * lm, u32 adj_index, u32 is_del) |
| 513 | { |
| 514 | ip_adjacency_t * adj; |
| 515 | uword i; |
| 516 | adj = ip_get_adjacency (lm, adj_index); |
| 517 | for (i = 0; i < vec_len (lm->add_del_adjacency_callbacks); i++) |
| 518 | lm->add_del_adjacency_callbacks[i] (lm, adj_index, adj, is_del); |
| 519 | } |
| 520 | |
| 521 | /* Create new block of given number of contiguous adjacencies. */ |
| 522 | ip_adjacency_t * |
| 523 | ip_add_adjacency (ip_lookup_main_t * lm, |
| 524 | ip_adjacency_t * adj, |
| 525 | u32 n_adj, |
| 526 | u32 * adj_index_result); |
| 527 | |
| 528 | void ip_del_adjacency (ip_lookup_main_t * lm, u32 adj_index); |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 529 | void |
| 530 | ip_update_adjacency (ip_lookup_main_t * lm, |
| 531 | u32 adj_index, |
| 532 | ip_adjacency_t * copy_adj); |
| 533 | |
| 534 | static inline int |
| 535 | ip_adjacency_is_multipath(ip_lookup_main_t * lm, u32 adj_index) |
| 536 | { |
Keith Burns (alagalah) | 52fc44d | 2016-03-25 09:38:50 -0700 | [diff] [blame] | 537 | if (!vec_len(lm->multipath_adjacencies)) |
| 538 | return 0; |
| 539 | |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 540 | if (vec_len(lm->multipath_adjacencies) < adj_index - 1) |
| 541 | return 0; |
| 542 | |
Keith Burns (alagalah) | 52fc44d | 2016-03-25 09:38:50 -0700 | [diff] [blame] | 543 | |
Damjan Marion | 102ec52 | 2016-03-29 13:18:17 +0200 | [diff] [blame] | 544 | return (lm->multipath_adjacencies[adj_index].adj_index == adj_index && |
| 545 | lm->multipath_adjacencies[adj_index].n_adj_in_block > 0); |
| 546 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 547 | |
| 548 | void |
| 549 | ip_multipath_adjacency_free (ip_lookup_main_t * lm, |
| 550 | ip_multipath_adjacency_t * a); |
| 551 | |
| 552 | u32 |
| 553 | ip_multipath_adjacency_add_del_next_hop (ip_lookup_main_t * lm, |
| 554 | u32 is_del, |
| 555 | u32 old_mp_adj_index, |
| 556 | u32 next_hop_adj_index, |
| 557 | u32 next_hop_weight, |
| 558 | u32 * new_mp_adj_index); |
| 559 | |
| 560 | clib_error_t * |
| 561 | ip_interface_address_add_del (ip_lookup_main_t * lm, |
| 562 | u32 sw_if_index, |
| 563 | void * address, |
| 564 | u32 address_length, |
| 565 | u32 is_del, |
| 566 | u32 * result_index); |
| 567 | |
| 568 | always_inline ip_interface_address_t * |
| 569 | ip_get_interface_address (ip_lookup_main_t * lm, void * addr_fib) |
| 570 | { |
| 571 | uword * p = mhash_get (&lm->address_to_if_address_index, addr_fib); |
| 572 | return p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0; |
| 573 | } |
| 574 | |
| 575 | always_inline void * |
| 576 | ip_interface_address_get_address (ip_lookup_main_t * lm, ip_interface_address_t * a) |
| 577 | { return mhash_key_to_mem (&lm->address_to_if_address_index, a->address_key); } |
| 578 | |
| 579 | always_inline ip_interface_address_t * |
| 580 | ip_interface_address_for_packet (ip_lookup_main_t * lm, vlib_buffer_t * b, u32 sw_if_index) |
| 581 | { |
| 582 | ip_adjacency_t * adj; |
| 583 | u32 if_address_index; |
| 584 | |
| 585 | adj = ip_get_adjacency (lm, vnet_buffer (b)->ip.adj_index[VLIB_TX]); |
| 586 | |
| 587 | ASSERT (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP |
| 588 | || adj->lookup_next_index == IP_LOOKUP_NEXT_LOCAL); |
| 589 | if_address_index = adj->if_address_index; |
| 590 | if_address_index = (if_address_index == ~0 ? |
| 591 | vec_elt (lm->if_address_pool_index_by_sw_if_index, sw_if_index) |
| 592 | : if_address_index); |
| 593 | |
Pierre Pfister | d076f19 | 2016-06-22 12:58:30 +0100 | [diff] [blame] | 594 | return (if_address_index != ~0)?pool_elt_at_index (lm->if_address_pool, if_address_index):NULL; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 595 | } |
| 596 | |
| 597 | #define foreach_ip_interface_address(lm,a,sw_if_index,loop,body) \ |
| 598 | do { \ |
| 599 | vnet_main_t *_vnm = vnet_get_main(); \ |
| 600 | u32 _sw_if_index = sw_if_index; \ |
| 601 | vnet_sw_interface_t *_swif; \ |
| 602 | _swif = vnet_get_sw_interface (_vnm, _sw_if_index); \ |
| 603 | \ |
| 604 | /* \ |
| 605 | * Loop => honor unnumbered interface addressing. \ |
| 606 | */ \ |
| 607 | if (loop && _swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) \ |
| 608 | _sw_if_index = _swif->unnumbered_sw_if_index; \ |
| 609 | u32 _ia = \ |
| 610 | (vec_len((lm)->if_address_pool_index_by_sw_if_index) \ |
| 611 | > (_sw_if_index)) \ |
| 612 | ? vec_elt ((lm)->if_address_pool_index_by_sw_if_index, \ |
| 613 | (_sw_if_index)) : (u32)~0; \ |
| 614 | ip_interface_address_t * _a; \ |
| 615 | while (_ia != ~0) \ |
| 616 | { \ |
| 617 | _a = pool_elt_at_index ((lm)->if_address_pool, _ia); \ |
| 618 | _ia = _a->next_this_sw_interface; \ |
| 619 | (a) = _a; \ |
| 620 | body; \ |
| 621 | } \ |
| 622 | } while (0) |
| 623 | |
| 624 | void ip_lookup_init (ip_lookup_main_t * lm, u32 ip_lookup_node_index); |
Dave Barach | 6f9bca2 | 2016-04-30 10:25:32 -0400 | [diff] [blame^] | 625 | u32 vnet_register_special_adjacency_format_function |
| 626 | (ip_lookup_main_t * lm, format_function_t * fp); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 627 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 628 | #endif /* included_ip_lookup_h */ |