1b435f31f0b0815e1b8276b3d4304d33da09285a
[vpp.git] / vnet / vnet / mpls / node.c
1 /*
2  * node.c: mpls-o-gre decap processing
3  *
4  * Copyright (c) 2012-2014 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 <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/mpls/mpls.h>
21
22 typedef struct {
23   u32 next_index;
24   u32 label_host_byte_order;
25 } mpls_input_trace_t;
26
27 static u8 *
28 format_mpls_input_trace (u8 * s, va_list * args)
29 {
30   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
31   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
32   mpls_input_trace_t * t = va_arg (*args, mpls_input_trace_t *);
33   char * next_name;
34
35   next_name = "BUG!";
36
37 #define _(a,b) if (t->next_index == MPLS_INPUT_NEXT_##a) next_name = b;
38   foreach_mpls_input_next;
39 #undef _
40   
41   s = format (s, "MPLS: next %s[%d]  label %d ttl %d", 
42               next_name, t->next_index,
43               vnet_mpls_uc_get_label(t->label_host_byte_order),
44               vnet_mpls_uc_get_ttl(t->label_host_byte_order));
45
46   return s;
47 }
48
49 vlib_node_registration_t mpls_input_node;
50
51 typedef struct {
52   u32 last_label;
53   u32 last_inner_fib_index;
54   u32 last_outer_fib_index;
55   mpls_main_t * mpls_main;
56 } mpls_input_runtime_t;
57
58 static inline uword
59 mpls_input_inline (vlib_main_t * vm,
60                    vlib_node_runtime_t * node,
61                    vlib_frame_t * from_frame)
62 {
63   u32 n_left_from, next_index, * from, * to_next;
64   mpls_input_runtime_t * rt;
65   mpls_main_t * mm;
66   u32 cpu_index = os_get_cpu_number();
67   vlib_simple_counter_main_t * cm;
68   vnet_main_t * vnm = vnet_get_main();
69
70   from = vlib_frame_vector_args (from_frame);
71   n_left_from = from_frame->n_vectors;
72   rt = vlib_node_get_runtime_data (vm, mpls_input_node.index);
73   mm = rt->mpls_main;
74   /* 
75    * Force an initial lookup every time, in case the control-plane
76    * changed the label->FIB mapping.
77    */
78   rt->last_label = ~0;
79
80   next_index = node->cached_next_index;
81
82   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
83                          VNET_INTERFACE_COUNTER_MPLS);
84
85   while (n_left_from > 0)
86     {
87       u32 n_left_to_next;
88
89       vlib_get_next_frame (vm, node, next_index,
90                            to_next, n_left_to_next);
91
92       while (n_left_from > 0 && n_left_to_next > 0)
93         {
94           u32 bi0;
95           vlib_buffer_t * b0;
96           mpls_unicast_header_t * h0;
97           u32 label0;
98           u32 next0;
99           ip_config_main_t * cm0;
100           u32 sw_if_index0;
101
102           bi0 = from[0];
103           to_next[0] = bi0;
104           from += 1;
105           to_next += 1;
106           n_left_from -= 1;
107           n_left_to_next -= 1;
108
109           b0 = vlib_get_buffer (vm, bi0);
110           h0 = vlib_buffer_get_current (b0);
111           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
112
113           cm0 = &mm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
114           b0->current_config_index = vec_elt (cm0->config_index_by_sw_if_index,
115                                               sw_if_index0);
116
117           label0 = clib_net_to_host_u32 (h0->label_exp_s_ttl);
118           /* TTL expired? */
119           if (PREDICT_FALSE(vnet_mpls_uc_get_ttl (label0) == 0))
120            {
121               next0 = MPLS_INPUT_NEXT_DROP;
122               b0->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
123             }
124           else
125             {
126               vnet_get_config_data (&cm0->config_main,
127                                     &b0->current_config_index,
128                                     &next0,
129                                     /* # bytes of config data */ 0);
130               vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
131             }
132
133           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
134             {
135               mpls_input_trace_t *tr = vlib_add_trace (vm, node, 
136                                                        b0, sizeof (*tr));
137               tr->next_index = next0;
138               tr->label_host_byte_order = label0;
139             }
140
141           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
142                                            to_next, n_left_to_next,
143                                            bi0, next0);
144         }
145
146       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
147     }
148   vlib_node_increment_counter (vm, mpls_input_node.index,
149                                MPLS_ERROR_PKTS_DECAP, from_frame->n_vectors);
150   return from_frame->n_vectors;
151 }
152
153 static uword
154 mpls_input (vlib_main_t * vm,
155             vlib_node_runtime_t * node,
156             vlib_frame_t * from_frame)
157 {
158   return mpls_input_inline (vm, node, from_frame);
159 }
160
161 static char * mpls_error_strings[] = {
162 #define mpls_error(n,s) s,
163 #include "error.def"
164 #undef mpls_error
165 };
166
167 VLIB_REGISTER_NODE (mpls_input_node) = {
168   .function = mpls_input,
169   .name = "mpls-input",
170   /* Takes a vector of packets. */
171   .vector_size = sizeof (u32),
172
173   .runtime_data_bytes = sizeof(mpls_input_runtime_t),
174
175   .n_errors = MPLS_N_ERROR,
176   .error_strings = mpls_error_strings,
177
178   .n_next_nodes = MPLS_INPUT_N_NEXT,
179   .next_nodes = {
180 #define _(s,n) [MPLS_INPUT_NEXT_##s] = n,
181     foreach_mpls_input_next
182 #undef _
183   },
184
185   .format_buffer = format_mpls_unicast_header_net_byte_order,
186   .format_trace = format_mpls_input_trace,
187 };
188
189 VLIB_NODE_FUNCTION_MULTIARCH (mpls_input_node, mpls_input)
190
191 static void
192 mpls_setup_nodes (vlib_main_t * vm)
193 {
194   mpls_input_runtime_t * rt;
195   pg_node_t * pn;
196
197   pn = pg_get_node (mpls_input_node.index);
198   pn->unformat_edit = unformat_pg_mpls_header;
199
200   rt = vlib_node_get_runtime_data (vm, mpls_input_node.index);
201   rt->last_label = (u32) ~0;
202   rt->last_inner_fib_index = 0;
203   rt->last_outer_fib_index = 0;
204   rt->mpls_main = &mpls_main;
205
206   ethernet_register_input_type (vm, ETHERNET_TYPE_MPLS_UNICAST,
207                                 mpls_input_node.index);
208 }
209
210 static clib_error_t * mpls_input_init (vlib_main_t * vm)
211 {
212   clib_error_t * error; 
213
214   error = vlib_call_init_function (vm, mpls_init);
215   if (error)
216     clib_error_report (error);
217
218   mpls_setup_nodes (vm);
219
220   return (mpls_feature_init(vm));
221 }
222
223 VLIB_INIT_FUNCTION (mpls_input_init);