Line data Source code
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 : #include <vlib/vlib.h>
16 : #include <vnet/vnet.h>
17 : #include <vppinfra/error.h>
18 : #include <srv6-am/am.h>
19 :
20 :
21 : /******************************* Packet tracing *******************************/
22 :
23 : typedef struct
24 : {
25 : u32 localsid_index;
26 : } srv6_am_localsid_trace_t;
27 :
28 : typedef struct
29 : {
30 : ip6_address_t src, dst;
31 : } srv6_am_rewrite_trace_t;
32 :
33 : static u8 *
34 0 : format_srv6_am_localsid_trace (u8 * s, va_list * args)
35 : {
36 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38 0 : srv6_am_localsid_trace_t *t = va_arg (*args, srv6_am_localsid_trace_t *);
39 :
40 0 : return format (s, "SRv6-AM-localsid: localsid_index %d", t->localsid_index);
41 : }
42 :
43 : static u8 *
44 0 : format_srv6_am_rewrite_trace (u8 * s, va_list * args)
45 : {
46 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
47 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
48 0 : srv6_am_rewrite_trace_t *t = va_arg (*args, srv6_am_rewrite_trace_t *);
49 :
50 0 : return format (s, "SRv6-AM-rewrite: src %U dst %U",
51 : format_ip6_address, &t->src, format_ip6_address, &t->dst);
52 : }
53 :
54 :
55 : /***************************** Node registration ******************************/
56 :
57 : vlib_node_registration_t srv6_am_rewrite_node;
58 :
59 :
60 : /****************************** Packet counters *******************************/
61 :
62 : #define foreach_srv6_am_rewrite_counter \
63 : _(PROCESSED, "srv6-am rewritten packets") \
64 : _(NO_SRH, "(Error) No SRH.")
65 :
66 : typedef enum
67 : {
68 : #define _(sym,str) SRV6_AM_REWRITE_COUNTER_##sym,
69 : foreach_srv6_am_rewrite_counter
70 : #undef _
71 : SRV6_AM_REWRITE_N_COUNTERS,
72 : } srv6_am_rewrite_counters;
73 :
74 : static char *srv6_am_rewrite_counter_strings[] = {
75 : #define _(sym,string) string,
76 : foreach_srv6_am_rewrite_counter
77 : #undef _
78 : };
79 :
80 :
81 : /********************************* Next nodes *********************************/
82 :
83 : typedef enum
84 : {
85 : SRV6_AM_LOCALSID_NEXT_ERROR,
86 : SRV6_AM_LOCALSID_NEXT_REWRITE,
87 : SRV6_AM_LOCALSID_N_NEXT,
88 : } srv6_am_localsid_next_t;
89 :
90 : typedef enum
91 : {
92 : SRV6_AM_REWRITE_NEXT_ERROR,
93 : SRV6_AM_REWRITE_NEXT_LOOKUP,
94 : SRV6_AM_REWRITE_N_NEXT,
95 : } srv6_am_rewrite_next_t;
96 :
97 :
98 : /******************************* Local SID node *******************************/
99 :
100 : /**
101 : * @brief SRv6 masquerading.
102 : */
103 : static_always_inline void
104 0 : end_am_processing (vlib_buffer_t * b0,
105 : ip6_header_t * ip0,
106 : ip6_sr_header_t * sr0,
107 : ip6_sr_localsid_t * ls0, u32 * next0)
108 : {
109 : ip6_address_t *new_dst0;
110 :
111 0 : if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
112 : sr0->type != ROUTING_HEADER_TYPE_SR))
113 : {
114 0 : *next0 = SRV6_AM_LOCALSID_NEXT_ERROR;
115 0 : return;
116 : }
117 :
118 0 : if (PREDICT_FALSE (sr0->segments_left == 0))
119 : {
120 0 : *next0 = SRV6_AM_LOCALSID_NEXT_ERROR;
121 0 : return;
122 : }
123 :
124 : /* Decrement Segments Left */
125 0 : sr0->segments_left -= 1;
126 :
127 : /* Set Destination Address to Last Segment (index 0) */
128 0 : new_dst0 = (ip6_address_t *) (sr0->segments);
129 0 : ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
130 0 : ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
131 :
132 : /* Set Xconnect adjacency to VNF */
133 0 : vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ls0->nh_adj;
134 : }
135 :
136 : /**
137 : * @brief Graph node for applying SRv6 masquerading.
138 : */
139 : static uword
140 0 : srv6_am_localsid_fn (vlib_main_t * vm,
141 : vlib_node_runtime_t * node, vlib_frame_t * frame)
142 : {
143 0 : ip6_sr_main_t *sm = &sr_main;
144 : u32 n_left_from, next_index, *from, *to_next;
145 :
146 0 : from = vlib_frame_vector_args (frame);
147 0 : n_left_from = frame->n_vectors;
148 0 : next_index = node->cached_next_index;
149 :
150 0 : u32 thread_index = vm->thread_index;
151 :
152 0 : while (n_left_from > 0)
153 : {
154 : u32 n_left_to_next;
155 :
156 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
157 :
158 : /* TODO: Dual/quad loop */
159 :
160 0 : while (n_left_from > 0 && n_left_to_next > 0)
161 : {
162 : u32 bi0;
163 : vlib_buffer_t *b0;
164 0 : ip6_header_t *ip0 = 0;
165 : ip6_sr_header_t *sr0;
166 : ip6_sr_localsid_t *ls0;
167 0 : u32 next0 = SRV6_AM_LOCALSID_NEXT_REWRITE;
168 :
169 0 : bi0 = from[0];
170 0 : to_next[0] = bi0;
171 0 : from += 1;
172 0 : to_next += 1;
173 0 : n_left_from -= 1;
174 0 : n_left_to_next -= 1;
175 :
176 0 : b0 = vlib_get_buffer (vm, bi0);
177 0 : ip0 = vlib_buffer_get_current (b0);
178 0 : sr0 = (ip6_sr_header_t *) (ip0 + 1);
179 :
180 : /* Lookup the SR End behavior based on IP DA (adj) */
181 0 : ls0 = pool_elt_at_index (sm->localsids,
182 : vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
183 :
184 : /* SRH processing */
185 0 : end_am_processing (b0, ip0, sr0, ls0, &next0);
186 :
187 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
188 : {
189 : srv6_am_localsid_trace_t *tr =
190 0 : vlib_add_trace (vm, node, b0, sizeof *tr);
191 0 : tr->localsid_index = ls0 - sm->localsids;
192 : }
193 :
194 : /* This increments the SRv6 per LocalSID counters. */
195 0 : vlib_increment_combined_counter (((next0 ==
196 : SRV6_AM_LOCALSID_NEXT_ERROR) ?
197 : &(sm->sr_ls_invalid_counters) :
198 : &(sm->sr_ls_valid_counters)),
199 0 : thread_index, ls0 - sm->localsids,
200 : 1, vlib_buffer_length_in_chain (vm,
201 : b0));
202 :
203 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
204 : n_left_to_next, bi0, next0);
205 : }
206 :
207 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
208 : }
209 :
210 0 : return frame->n_vectors;
211 : }
212 :
213 : /* *INDENT-OFF* */
214 36399 : VLIB_REGISTER_NODE (srv6_am_localsid_node) = {
215 : .function = srv6_am_localsid_fn,
216 : .name = "srv6-am-localsid",
217 : .vector_size = sizeof (u32),
218 : .format_trace = format_srv6_am_localsid_trace,
219 : .type = VLIB_NODE_TYPE_INTERNAL,
220 : .n_next_nodes = SRV6_AM_LOCALSID_N_NEXT,
221 : .next_nodes = {
222 : [SRV6_AM_LOCALSID_NEXT_REWRITE] = "ip6-rewrite",
223 : [SRV6_AM_LOCALSID_NEXT_ERROR] = "error-drop",
224 : },
225 : };
226 : /* *INDENT-ON* */
227 :
228 :
229 : /******************************* Rewriting node *******************************/
230 :
231 : /**
232 : * @brief SRv6 de-masquerading.
233 : */
234 : static_always_inline void
235 0 : end_am_rewriting (vlib_node_runtime_t * node,
236 : vlib_buffer_t * b0,
237 : ip6_header_t * ip0, ip6_sr_header_t * sr0, u32 * next0)
238 : {
239 0 : if (PREDICT_FALSE (ip0->protocol != IP_PROTOCOL_IPV6_ROUTE ||
240 : sr0->type != ROUTING_HEADER_TYPE_SR))
241 : {
242 0 : b0->error = node->errors[SRV6_AM_REWRITE_COUNTER_NO_SRH];
243 0 : *next0 = SRV6_AM_REWRITE_NEXT_ERROR;
244 0 : return;
245 : }
246 :
247 : /* Restore Destination Address to active segment (index SL) */
248 0 : if (sr0->segments_left != 0)
249 : {
250 : ip6_address_t *new_dst0;
251 0 : new_dst0 = (ip6_address_t *) (sr0->segments) + sr0->segments_left;
252 0 : ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
253 0 : ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
254 : }
255 : }
256 :
257 : /**
258 : * @brief Graph node for applying SRv6 de-masquerading.
259 : */
260 : static uword
261 0 : srv6_am_rewrite_fn (vlib_main_t * vm,
262 : vlib_node_runtime_t * node, vlib_frame_t * frame)
263 : {
264 : u32 n_left_from, next_index, *from, *to_next;
265 0 : u32 cnt_packets = 0;
266 :
267 0 : from = vlib_frame_vector_args (frame);
268 0 : n_left_from = frame->n_vectors;
269 0 : next_index = node->cached_next_index;
270 :
271 0 : while (n_left_from > 0)
272 : {
273 : u32 n_left_to_next;
274 :
275 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
276 :
277 : /* TODO: Dual/quad loop */
278 :
279 0 : while (n_left_from > 0 && n_left_to_next > 0)
280 : {
281 : u32 bi0;
282 : vlib_buffer_t *b0;
283 0 : ip6_header_t *ip0 = 0;
284 : ip6_sr_header_t *sr0;
285 0 : u32 next0 = SRV6_AM_REWRITE_NEXT_LOOKUP;
286 :
287 0 : bi0 = from[0];
288 0 : to_next[0] = bi0;
289 0 : from += 1;
290 0 : to_next += 1;
291 0 : n_left_from -= 1;
292 0 : n_left_to_next -= 1;
293 :
294 0 : b0 = vlib_get_buffer (vm, bi0);
295 0 : ip0 = vlib_buffer_get_current (b0);
296 0 : sr0 = (ip6_sr_header_t *) (ip0 + 1);
297 :
298 : /* SRH processing */
299 0 : end_am_rewriting (node, b0, ip0, sr0, &next0);
300 :
301 0 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
302 0 : PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
303 : {
304 : srv6_am_rewrite_trace_t *tr =
305 0 : vlib_add_trace (vm, node, b0, sizeof *tr);
306 0 : clib_memcpy_fast (tr->src.as_u8, ip0->src_address.as_u8,
307 : sizeof tr->src.as_u8);
308 0 : clib_memcpy_fast (tr->dst.as_u8, ip0->dst_address.as_u8,
309 : sizeof tr->dst.as_u8);
310 : }
311 :
312 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
313 : n_left_to_next, bi0, next0);
314 :
315 0 : cnt_packets++;
316 : }
317 :
318 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
319 : }
320 :
321 : /* Update counters */
322 0 : vlib_node_increment_counter (vm, srv6_am_rewrite_node.index,
323 : SRV6_AM_REWRITE_COUNTER_PROCESSED,
324 : cnt_packets);
325 :
326 0 : return frame->n_vectors;
327 : }
328 :
329 : /* *INDENT-OFF* */
330 36399 : VLIB_REGISTER_NODE (srv6_am_rewrite_node) = {
331 : .function = srv6_am_rewrite_fn,
332 : .name = "srv6-am-rewrite",
333 : .vector_size = sizeof (u32),
334 : .format_trace = format_srv6_am_rewrite_trace,
335 : .type = VLIB_NODE_TYPE_INTERNAL,
336 : .n_errors = SRV6_AM_REWRITE_N_COUNTERS,
337 : .error_strings = srv6_am_rewrite_counter_strings,
338 : .n_next_nodes = SRV6_AM_REWRITE_N_NEXT,
339 : .next_nodes = {
340 : [SRV6_AM_REWRITE_NEXT_LOOKUP] = "ip6-lookup",
341 : [SRV6_AM_REWRITE_NEXT_ERROR] = "error-drop",
342 : },
343 : };
344 : /* *INDENT-ON* */
345 :
346 : /*
347 : * fd.io coding-style-patch-verification: ON
348 : *
349 : * Local Variables:
350 : * eval: (c-set-style "gnu")
351 : * End:
352 : */
|