Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | * l2_vtr.h : layer 2 vlan tag rewrite processing |
| 3 | * |
| 4 | * Copyright (c) 2013 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 | #ifndef included_vnet_l2_vtr_h |
| 19 | #define included_vnet_l2_vtr_h |
| 20 | |
| 21 | #include <vlib/vlib.h> |
| 22 | #include <vnet/vnet.h> |
| 23 | #include <vnet/ethernet/packet.h> |
| 24 | #include <vnet/l2/l2_vtr.h> |
| 25 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 26 | /* VTR config options for API and CLI support */ |
| 27 | typedef enum |
| 28 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 29 | L2_VTR_DISABLED, |
| 30 | L2_VTR_PUSH_1, |
| 31 | L2_VTR_PUSH_2, |
| 32 | L2_VTR_POP_1, |
| 33 | L2_VTR_POP_2, |
| 34 | L2_VTR_TRANSLATE_1_1, |
| 35 | L2_VTR_TRANSLATE_1_2, |
| 36 | L2_VTR_TRANSLATE_2_1, |
| 37 | L2_VTR_TRANSLATE_2_2 |
| 38 | } l2_vtr_op_t; |
| 39 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 40 | /** |
| 41 | * Per-interface vlan tag rewrite configuration |
| 42 | * There will be one instance of this struct for each sw_if_index |
| 43 | * for both input vtr and output vtr |
| 44 | */ |
| 45 | typedef struct |
| 46 | { |
| 47 | union |
| 48 | { |
| 49 | /* |
| 50 | * Up to two vlan tags to push. |
| 51 | * if there is only one vlan tag to push, it is in tags[1]. |
| 52 | */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 53 | ethernet_vlan_header_tv_t tags[2]; |
| 54 | u64 raw_tags; |
| 55 | }; |
| 56 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 57 | union |
| 58 | { |
| 59 | struct |
| 60 | { |
| 61 | u8 push_bytes; /* number of bytes to push for up to 2 vlans (0,4,8) */ |
| 62 | u8 pop_bytes; /* number of bytes to pop for up to 2 vlans (0,4,8) */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 63 | }; |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 64 | u16 push_and_pop_bytes; /* if 0 then the feature is disabled */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 65 | }; |
| 66 | } vtr_config_t; |
| 67 | |
| 68 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 69 | /** |
| 70 | * Perform the configured tag rewrite on the packet. |
| 71 | * Return 0 if ok, 1 if packet should be dropped (e.g. tried to pop |
| 72 | * too many tags) |
| 73 | */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 74 | always_inline u32 |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 75 | l2_vtr_process (vlib_buffer_t * b0, vtr_config_t * config) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 76 | { |
| 77 | u64 temp_8; |
| 78 | u32 temp_4; |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 79 | u8 *eth; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 80 | |
| 81 | eth = vlib_buffer_get_current (b0); |
| 82 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 83 | /* copy the 12B dmac and smac to a temporary location */ |
| 84 | temp_8 = *((u64 *) eth); |
| 85 | temp_4 = *((u32 *) (eth + 8)); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 86 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 87 | /* adjust for popped tags */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 88 | eth += config->pop_bytes; |
| 89 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 90 | /* if not enough tags to pop then drop packet */ |
| 91 | if (PREDICT_FALSE ((vnet_buffer (b0)->l2.l2_len - 12) < config->pop_bytes)) |
| 92 | { |
| 93 | return 1; |
| 94 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 95 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 96 | /* copy the 2 new tags to the start of the packet */ |
| 97 | *((u64 *) (eth + 12 - 8)) = config->raw_tags; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 98 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 99 | /* TODO: set cos bits */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 100 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 101 | /* adjust for pushed tags: */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 102 | eth -= config->push_bytes; |
| 103 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 104 | /* copy the 12 dmac and smac back to the packet */ |
| 105 | *((u64 *) eth) = temp_8; |
| 106 | *((u32 *) (eth + 8)) = temp_4; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 107 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 108 | /* Update l2_len */ |
| 109 | vnet_buffer (b0)->l2.l2_len += |
| 110 | (word) config->push_bytes - (word) config->pop_bytes; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 111 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 112 | /* Update vlan tag count */ |
| 113 | ethernet_buffer_adjust_vlan_count_by_bytes (b0, |
| 114 | (word) config->push_bytes - |
| 115 | (word) config->pop_bytes); |
Chris Luke | 194ebc5 | 2016-04-25 14:26:55 -0400 | [diff] [blame] | 116 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 117 | /* Update packet len */ |
| 118 | vlib_buffer_advance (b0, |
| 119 | (word) config->pop_bytes - (word) config->push_bytes); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 120 | |
| 121 | return 0; |
| 122 | } |
| 123 | |
| 124 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 125 | /* |
| 126 | * Perform the egress pre-vlan tag rewrite EFP Filter check. |
| 127 | * The post-vlan tag rewrite check is a separate graph node. |
| 128 | * |
| 129 | * This check insures that a packet being output to an interface |
| 130 | * (before output vtr is performed) has vlan tags that match those |
| 131 | * on a packet received from that interface (after vtr has been performed). |
| 132 | * This means verifying that any tags pushed by input vtr are present |
| 133 | * on the packet. |
| 134 | * |
| 135 | * Return 0 if ok, 1 if packet should be dropped. |
| 136 | * This function should be passed the input vtr config for the interface. |
| 137 | */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 138 | always_inline u8 |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 139 | l2_efp_filter_process (vlib_buffer_t * b0, vtr_config_t * in_config) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 140 | { |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 141 | u8 *eth; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 142 | u64 packet_tags; |
| 143 | u64 tag_mask; |
| 144 | |
| 145 | eth = vlib_buffer_get_current (b0); |
| 146 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 147 | /* |
| 148 | * If there are 2 tags pushed, they must match config->tags[0] and |
| 149 | * config->tags[1]. |
| 150 | * If there is one tag pushed, it must match config->tag[1]. |
| 151 | * If there are 0 tags pushed, the check passes. |
| 152 | */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 153 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 154 | /* mask for two vlan id and ethertypes, no cos bits */ |
| 155 | tag_mask = clib_net_to_host_u64 (0xFFFF0FFFFFFF0FFF); |
| 156 | /* mask for one vlan id and ethertype, no cos bits */ |
| 157 | tag_mask = |
| 158 | (in_config->push_bytes == |
| 159 | 4) ? clib_net_to_host_u64 (0xFFFF0FFF) : tag_mask; |
| 160 | /* mask for always match */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 161 | tag_mask = (in_config->push_bytes == 0) ? 0 : tag_mask; |
| 162 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 163 | /* |
| 164 | * Read 8B from the packet, getting the proper set of vlan tags |
| 165 | * For 0 push bytes, the address doesn't matter since the mask |
| 166 | * clears the data to 0. |
| 167 | */ |
| 168 | packet_tags = *((u64 *) (eth + 4 + in_config->push_bytes)); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 169 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 170 | /* Check if the packet tags match the configured tags */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 171 | return (packet_tags & tag_mask) != in_config->raw_tags; |
| 172 | } |
| 173 | |
Pavel Kotucek | 95300d1 | 2016-08-26 16:11:36 +0200 | [diff] [blame] | 174 | typedef struct |
| 175 | { |
| 176 | union |
| 177 | { |
| 178 | ethernet_pbb_header_t macs_tags; |
| 179 | struct |
| 180 | { |
| 181 | u64 data1; |
| 182 | u64 data2; |
| 183 | u16 data3; |
| 184 | u32 data4; |
| 185 | } raw_data; |
| 186 | }; |
| 187 | union |
| 188 | { |
| 189 | struct |
| 190 | { |
| 191 | u8 push_bytes; /* number of bytes to push pbb tags */ |
| 192 | u8 pop_bytes; /* number of bytes to pop pbb tags */ |
| 193 | }; |
| 194 | u16 push_and_pop_bytes; /* if 0 then the feature is disabled */ |
| 195 | }; |
| 196 | } ptr_config_t; |
| 197 | |
| 198 | always_inline u32 |
| 199 | l2_pbb_process (vlib_buffer_t * b0, ptr_config_t * config) |
| 200 | { |
| 201 | u8 *eth = vlib_buffer_get_current (b0); |
| 202 | |
| 203 | if (config->pop_bytes > 0) |
| 204 | { |
| 205 | ethernet_pbb_header_packed_t *ph = (ethernet_pbb_header_packed_t *) eth; |
| 206 | |
| 207 | // drop packet without PBB header or with wrong I-tag or B-tag |
| 208 | if (clib_net_to_host_u16 (ph->priority_dei_id) != |
| 209 | clib_net_to_host_u16 (config->macs_tags.priority_dei_id) |
| 210 | || clib_net_to_host_u32 (ph->priority_dei_uca_res_sid) != |
| 211 | clib_net_to_host_u32 (config->macs_tags.priority_dei_uca_res_sid)) |
| 212 | return 1; |
| 213 | |
| 214 | eth += config->pop_bytes; |
| 215 | } |
| 216 | |
| 217 | if (config->push_bytes > 0) |
| 218 | { |
| 219 | eth -= config->push_bytes; |
| 220 | // copy the B-DA (6B), B-SA (6B), B-TAG (4B), I-TAG (6B) |
| 221 | *((u64 *) eth) = config->raw_data.data1; |
| 222 | *((u64 *) (eth + 8)) = config->raw_data.data2; |
| 223 | *((u16 *) (eth + 16)) = config->raw_data.data3; |
| 224 | *((u32 *) (eth + 18)) = config->raw_data.data4; |
| 225 | } |
| 226 | |
| 227 | /* Update l2_len */ |
| 228 | vnet_buffer (b0)->l2.l2_len += |
| 229 | (word) config->push_bytes - (word) config->pop_bytes; |
| 230 | /* Update packet len */ |
| 231 | vlib_buffer_advance (b0, |
| 232 | (word) config->pop_bytes - (word) config->push_bytes); |
| 233 | |
| 234 | return 0; |
| 235 | } |
| 236 | |
| 237 | u32 l2pbb_configure (vlib_main_t * vlib_main, |
| 238 | vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op, |
| 239 | u8 * b_dmac, u8 * b_smac, |
| 240 | u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 241 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 242 | /** |
| 243 | * Configure vtag tag rewrite on the given interface. |
| 244 | * Return 1 if there is an error, 0 if ok |
| 245 | */ |
| 246 | u32 l2vtr_configure (vlib_main_t * vlib_main, |
| 247 | vnet_main_t * vnet_main, |
| 248 | u32 sw_if_index, |
| 249 | u32 vtr_op, u32 push_dot1q, u32 vtr_tag1, u32 vtr_tag2); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 250 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 251 | /** |
| 252 | * Get vtag tag rewrite on the given interface. |
| 253 | * Return 1 if there is an error, 0 if ok |
| 254 | */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 255 | u32 l2vtr_get (vlib_main_t * vlib_main, |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 256 | vnet_main_t * vnet_main, |
| 257 | u32 sw_if_index, |
| 258 | u32 * vtr_op, |
| 259 | u32 * push_dot1q, u32 * vtr_tag1, u32 * vtr_tag2); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 260 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 261 | #endif /* included_vnet_l2_vtr_h */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 262 | |
Dave Barach | 97d8dc2 | 2016-08-15 15:31:15 -0400 | [diff] [blame] | 263 | |
| 264 | /* |
| 265 | * fd.io coding-style-patch-verification: ON |
| 266 | * |
| 267 | * Local Variables: |
| 268 | * eval: (c-set-style "gnu") |
| 269 | * End: |
| 270 | */ |