Neale Ranns | 59ff918 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 1 | /* |
| 2 | * tunnel.h: shared definitions for tunnels. |
| 3 | * |
| 4 | * Copyright (c) 2019 Cisco and/or its affiliates. |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at: |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | #include <vnet/tunnel/tunnel.h> |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 19 | #include <vnet/fib/fib_table.h> |
| 20 | #include <vnet/fib/fib_entry_track.h> |
| 21 | |
| 22 | #include <vnet/ip/ip6_inlines.h> |
| 23 | |
| 24 | const u8 TUNNEL_ENCAP_DECAP_FLAG_MASK = ( |
| 25 | #define _(a, b, c) TUNNEL_ENCAP_DECAP_FLAG_##a | |
| 26 | foreach_tunnel_encap_decap_flag |
| 27 | #undef _ |
| 28 | 0); |
| 29 | const u8 TUNNEL_FLAG_MASK = ( |
| 30 | #define _(a, b, c) TUNNEL_FLAG_##a | |
| 31 | foreach_tunnel_flag |
| 32 | #undef _ |
| 33 | 0); |
Neale Ranns | 59ff918 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 34 | |
| 35 | u8 * |
| 36 | format_tunnel_mode (u8 * s, va_list * args) |
| 37 | { |
| 38 | tunnel_mode_t mode = va_arg (*args, int); |
| 39 | |
| 40 | switch (mode) |
| 41 | { |
| 42 | #define _(n, v) case TUNNEL_MODE_##n: \ |
| 43 | s = format (s, "%s", v); \ |
| 44 | break; |
| 45 | foreach_tunnel_mode |
| 46 | #undef _ |
| 47 | } |
| 48 | |
| 49 | return (s); |
| 50 | } |
| 51 | |
Neale Ranns | 14053c9 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 52 | uword |
| 53 | unformat_tunnel_mode (unformat_input_t * input, va_list * args) |
| 54 | { |
| 55 | tunnel_mode_t *m = va_arg (*args, tunnel_mode_t *); |
| 56 | |
| 57 | if (unformat (input, "p2p")) |
| 58 | *m = TUNNEL_MODE_P2P; |
| 59 | else if (unformat (input, "p2mp") || unformat (input, "mp")) |
| 60 | *m = TUNNEL_MODE_MP; |
| 61 | else |
| 62 | return 0; |
| 63 | return 1; |
| 64 | } |
| 65 | |
Neale Ranns | 59ff918 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 66 | u8 * |
| 67 | format_tunnel_encap_decap_flags (u8 * s, va_list * args) |
| 68 | { |
| 69 | tunnel_encap_decap_flags_t f = va_arg (*args, int); |
| 70 | |
| 71 | if (f == TUNNEL_ENCAP_DECAP_FLAG_NONE) |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 72 | s = format (s, "none"); |
Neale Ranns | 59ff918 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 73 | |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 74 | #define _(a, b, c) \ |
| 75 | else if (f & TUNNEL_ENCAP_DECAP_FLAG_##a) s = format (s, "%s ", b); |
| 76 | foreach_tunnel_encap_decap_flag |
Neale Ranns | 59ff918 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 77 | #undef _ |
| 78 | return (s); |
| 79 | } |
| 80 | |
Mohammed Hawari | 59b792f | 2020-12-01 11:30:57 +0100 | [diff] [blame] | 81 | uword |
| 82 | unformat_tunnel_encap_decap_flags (unformat_input_t * input, va_list * args) |
| 83 | { |
| 84 | tunnel_encap_decap_flags_t *f = |
| 85 | va_arg (*args, tunnel_encap_decap_flags_t *); |
| 86 | #define _(a,b,c) if (unformat(input, b)) {\ |
| 87 | *f |= TUNNEL_ENCAP_DECAP_FLAG_##a;\ |
| 88 | return 1;\ |
| 89 | } |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 90 | foreach_tunnel_encap_decap_flag; |
Mohammed Hawari | 59b792f | 2020-12-01 11:30:57 +0100 | [diff] [blame] | 91 | #undef _ |
| 92 | return 0; |
| 93 | } |
| 94 | |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 95 | u8 * |
| 96 | format_tunnel_flags (u8 *s, va_list *args) |
| 97 | { |
| 98 | tunnel_flags_t f = va_arg (*args, int); |
| 99 | |
| 100 | if (f == TUNNEL_FLAG_NONE) |
| 101 | s = format (s, "none"); |
| 102 | |
| 103 | #define _(a, b, c) else if (f & TUNNEL_FLAG_##a) s = format (s, "%s ", c); |
| 104 | foreach_tunnel_flag |
| 105 | #undef _ |
| 106 | return (s); |
| 107 | } |
| 108 | |
| 109 | uword |
| 110 | unformat_tunnel_flags (unformat_input_t *input, va_list *args) |
| 111 | { |
| 112 | tunnel_flags_t *f = va_arg (*args, tunnel_flags_t *); |
| 113 | #define _(a, b, c) \ |
| 114 | if (unformat (input, c)) \ |
| 115 | { \ |
| 116 | *f |= TUNNEL_FLAG_##a; \ |
| 117 | return 1; \ |
| 118 | } |
| 119 | foreach_tunnel_flag; |
| 120 | #undef _ |
| 121 | return 0; |
| 122 | } |
| 123 | |
| 124 | ip_address_family_t |
| 125 | tunnel_get_af (const tunnel_t *t) |
| 126 | { |
| 127 | return (ip_addr_version (&t->t_src)); |
| 128 | } |
| 129 | |
| 130 | void |
| 131 | tunnel_copy (const tunnel_t *src, tunnel_t *dst) |
| 132 | { |
| 133 | ip_address_copy (&dst->t_dst, &src->t_dst); |
| 134 | ip_address_copy (&dst->t_src, &src->t_src); |
| 135 | |
| 136 | dst->t_encap_decap_flags = src->t_encap_decap_flags; |
| 137 | dst->t_flags = src->t_flags; |
| 138 | dst->t_mode = src->t_mode; |
| 139 | dst->t_table_id = src->t_table_id; |
| 140 | dst->t_dscp = src->t_dscp; |
| 141 | dst->t_hop_limit = src->t_hop_limit; |
| 142 | dst->t_fib_index = src->t_fib_index; |
| 143 | |
| 144 | dst->t_flags &= ~TUNNEL_FLAG_RESOLVED; |
| 145 | dst->t_fib_entry_index = FIB_NODE_INDEX_INVALID; |
| 146 | dst->t_sibling = ~0; |
| 147 | } |
| 148 | |
| 149 | u8 * |
| 150 | format_tunnel (u8 *s, va_list *args) |
| 151 | { |
| 152 | const tunnel_t *t = va_arg (*args, tunnel_t *); |
| 153 | u32 indent = va_arg (*args, u32); |
| 154 | |
| 155 | s = format (s, "%Utable-ID:%d [%U->%U] hop-limit:%d %U %U [%U] [%U]", |
| 156 | format_white_space, indent, t->t_table_id, format_ip_address, |
| 157 | &t->t_src, format_ip_address, &t->t_dst, t->t_hop_limit, |
| 158 | format_tunnel_mode, t->t_mode, format_ip_dscp, t->t_dscp, |
| 159 | format_tunnel_flags, t->t_flags, format_tunnel_encap_decap_flags, |
| 160 | t->t_encap_decap_flags); |
| 161 | if (t->t_flags & TUNNEL_FLAG_RESOLVED) |
| 162 | s = format (s, " [resolved via fib-entry: %d]", t->t_fib_entry_index); |
| 163 | |
| 164 | return (s); |
| 165 | } |
| 166 | |
| 167 | uword |
| 168 | unformat_tunnel (unformat_input_t *input, va_list *args) |
| 169 | { |
| 170 | tunnel_t *t = va_arg (*args, tunnel_t *); |
| 171 | |
| 172 | if (!unformat (input, "tunnel")) |
| 173 | return (0); |
| 174 | |
| 175 | unformat (input, "src %U", unformat_ip_address, &t->t_src); |
| 176 | unformat (input, "dst %U", unformat_ip_address, &t->t_dst); |
Neale Ranns | 9ec846c | 2021-02-09 14:04:02 +0000 | [diff] [blame] | 177 | unformat (input, "table-id %d", &t->t_table_id); |
| 178 | unformat (input, "hop-limit %d", &t->t_hop_limit); |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 179 | unformat (input, "%U", unformat_ip_dscp, &t->t_dscp); |
| 180 | unformat (input, "%U", unformat_tunnel_encap_decap_flags, |
| 181 | &t->t_encap_decap_flags); |
| 182 | unformat (input, "%U", unformat_tunnel_flags, &t->t_flags); |
| 183 | unformat (input, "%U", unformat_tunnel_mode, &t->t_mode); |
| 184 | |
Neale Ranns | a91cb45 | 2021-02-04 11:02:52 +0000 | [diff] [blame] | 185 | return (1); |
| 186 | } |
| 187 | |
| 188 | int |
| 189 | tunnel_resolve (tunnel_t *t, fib_node_type_t child_type, index_t child_index) |
| 190 | { |
| 191 | fib_prefix_t pfx; |
| 192 | |
| 193 | ip_address_to_fib_prefix (&t->t_dst, &pfx); |
| 194 | |
| 195 | t->t_fib_index = fib_table_find (pfx.fp_proto, t->t_table_id); |
| 196 | |
| 197 | if (t->t_fib_index == ~((u32) 0)) |
| 198 | return VNET_API_ERROR_NO_SUCH_FIB; |
| 199 | |
| 200 | t->t_fib_entry_index = fib_entry_track (t->t_fib_index, &pfx, child_type, |
| 201 | child_index, &t->t_sibling); |
| 202 | |
| 203 | t->t_flags |= TUNNEL_FLAG_RESOLVED; |
| 204 | |
| 205 | return (0); |
| 206 | } |
| 207 | |
| 208 | void |
| 209 | tunnel_unresolve (tunnel_t *t) |
| 210 | { |
| 211 | if (t->t_flags & TUNNEL_FLAG_RESOLVED) |
| 212 | fib_entry_untrack (t->t_fib_entry_index, t->t_sibling); |
| 213 | |
| 214 | t->t_flags &= ~TUNNEL_FLAG_RESOLVED; |
| 215 | } |
| 216 | |
| 217 | void |
| 218 | tunnel_contribute_forwarding (const tunnel_t *t, dpo_id_t *dpo) |
| 219 | { |
| 220 | fib_forward_chain_type_t fct; |
| 221 | |
| 222 | fct = fib_forw_chain_type_from_fib_proto ( |
| 223 | ip_address_family_to_fib_proto (ip_addr_version (&t->t_src))); |
| 224 | |
| 225 | fib_entry_contribute_forwarding (t->t_fib_entry_index, fct, dpo); |
| 226 | } |
| 227 | |
| 228 | void |
| 229 | tunnel_build_v6_hdr (const tunnel_t *t, ip_protocol_t next_proto, |
| 230 | ip6_header_t *ip) |
| 231 | { |
| 232 | ip->ip_version_traffic_class_and_flow_label = |
| 233 | clib_host_to_net_u32 (0x60000000); |
| 234 | ip6_set_dscp_network_order (ip, t->t_dscp); |
| 235 | |
| 236 | ip->hop_limit = 254; |
| 237 | ip6_address_copy (&ip->src_address, &ip_addr_v6 (&t->t_src)); |
| 238 | ip6_address_copy (&ip->dst_address, &ip_addr_v6 (&t->t_dst)); |
| 239 | |
| 240 | ip->protocol = next_proto; |
| 241 | ip->hop_limit = (t->t_hop_limit == 0 ? 254 : t->t_hop_limit); |
| 242 | ip6_set_flow_label_network_order ( |
| 243 | ip, ip6_compute_flow_hash (ip, IP_FLOW_HASH_DEFAULT)); |
| 244 | } |
| 245 | |
| 246 | void |
| 247 | tunnel_build_v4_hdr (const tunnel_t *t, ip_protocol_t next_proto, |
| 248 | ip4_header_t *ip) |
| 249 | { |
| 250 | ip->ip_version_and_header_length = 0x45; |
| 251 | ip->ttl = (t->t_hop_limit == 0 ? 254 : t->t_hop_limit); |
| 252 | ip->src_address.as_u32 = t->t_src.ip.ip4.as_u32; |
| 253 | ip->dst_address.as_u32 = t->t_dst.ip.ip4.as_u32; |
| 254 | ip->tos = t->t_dscp << 2; |
| 255 | ip->protocol = next_proto; |
| 256 | ip->checksum = ip4_header_checksum (ip); |
| 257 | } |
Neale Ranns | 59ff918 | 2019-12-29 23:55:18 +0000 | [diff] [blame] | 258 | |
| 259 | /* |
| 260 | * fd.io coding-style-patch-verification: ON |
| 261 | * |
| 262 | * Local Variables: |
| 263 | * eval: (c-set-style "gnu") |
| 264 | * End: |
| 265 | */ |