FIB Memory Usage Diagnostics
[vpp.git] / vnet / vnet / dpo / mpls_label_dpo.c
1 /*
2  * Copyright (c) 2016 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 #include <vnet/ip/ip.h>
17 #include <vnet/dpo/mpls_label_dpo.h>
18 #include <vnet/mpls/mpls.h>
19
20 /*
21  * pool of all MPLS Label DPOs
22  */
23 mpls_label_dpo_t *mpls_label_dpo_pool;
24
25 static mpls_label_dpo_t *
26 mpls_label_dpo_alloc (void)
27 {
28     mpls_label_dpo_t *mld;
29
30     pool_get_aligned(mpls_label_dpo_pool, mld, CLIB_CACHE_LINE_BYTES);
31     memset(mld, 0, sizeof(*mld));
32
33     dpo_reset(&mld->mld_dpo);
34
35     return (mld);
36 }
37
38 static index_t
39 mpls_label_dpo_get_index (mpls_label_dpo_t *mld)
40 {
41     return (mld - mpls_label_dpo_pool);
42 }
43
44 index_t
45 mpls_label_dpo_create (mpls_label_t label,
46                        mpls_eos_bit_t eos,
47                        u8 ttl,
48                        u8 exp,
49                        const dpo_id_t *dpo)
50 {
51     mpls_label_dpo_t *mld;
52
53     mld = mpls_label_dpo_alloc();
54
55     vnet_mpls_uc_set_label(&mld->mld_hdr.label_exp_s_ttl, label);
56     vnet_mpls_uc_set_ttl(&mld->mld_hdr.label_exp_s_ttl, ttl);
57     vnet_mpls_uc_set_exp(&mld->mld_hdr.label_exp_s_ttl, exp);
58     vnet_mpls_uc_set_s(&mld->mld_hdr.label_exp_s_ttl, eos);
59
60     /*
61      * get the header in network byte order since we will paint it
62      * on a packet in the data-plane
63      */
64     mld->mld_hdr.label_exp_s_ttl =
65         clib_host_to_net_u32(mld->mld_hdr.label_exp_s_ttl);
66
67     dpo_stack(DPO_MPLS_LABEL, DPO_PROTO_MPLS, &mld->mld_dpo, dpo);
68
69     return (mpls_label_dpo_get_index(mld));
70 }
71
72 u8*
73 format_mpls_label_dpo (u8 *s, va_list *args)
74 {
75     index_t index = va_arg (*args, index_t);
76     u32 indent = va_arg (*args, u32);
77     mpls_unicast_header_t hdr;
78     mpls_label_dpo_t *mld;
79
80     mld = mpls_label_dpo_get(index);
81
82     hdr.label_exp_s_ttl =
83         clib_net_to_host_u32(mld->mld_hdr.label_exp_s_ttl);
84
85     return (format(s, "mpls-label:[%d]:%U\n%U%U",
86                    index,
87                    format_mpls_header, hdr,
88                    format_white_space, indent,
89                    format_dpo_id, &mld->mld_dpo, indent+2));
90 }
91
92 static void
93 mpls_label_dpo_lock (dpo_id_t *dpo)
94 {
95     mpls_label_dpo_t *mld;
96
97     mld = mpls_label_dpo_get(dpo->dpoi_index);
98
99     mld->mld_locks++;
100 }
101
102 static void
103 mpls_label_dpo_unlock (dpo_id_t *dpo)
104 {
105     mpls_label_dpo_t *mld;
106
107     mld = mpls_label_dpo_get(dpo->dpoi_index);
108
109     mld->mld_locks--;
110
111     if (0 == mld->mld_locks)
112     {
113         dpo_reset(&mld->mld_dpo);
114         pool_put(mpls_label_dpo_pool, mld);
115     }
116 }
117
118 /**
119  * @brief A struct to hold tracing information for the MPLS label imposition
120  * node.
121  */
122 typedef struct mpls_label_imposition_trace_t_
123 {
124     /**
125      * The MPLS header imposed
126      */
127     mpls_unicast_header_t hdr;
128 } mpls_label_imposition_trace_t;
129
130 always_inline uword
131 mpls_label_imposition (vlib_main_t * vm,
132                        vlib_node_runtime_t * node,
133                        vlib_frame_t * from_frame)
134 {
135     u32 n_left_from, next_index, * from, * to_next;
136
137     from = vlib_frame_vector_args (from_frame);
138     n_left_from = from_frame->n_vectors;
139
140     next_index = node->cached_next_index;
141
142     while (n_left_from > 0)
143     {
144         u32 n_left_to_next;
145
146         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
147
148         while (n_left_from > 0 && n_left_to_next > 0)
149         {
150             mpls_unicast_header_t *hdr0;
151             mpls_label_dpo_t *mld0;
152             vlib_buffer_t * b0;
153             u32 bi0, mldi0;
154             u32 next0;
155
156             bi0 = from[0];
157             to_next[0] = bi0;
158             from += 1;
159             to_next += 1;
160             n_left_from -= 1;
161             n_left_to_next -= 1;
162
163             b0 = vlib_get_buffer (vm, bi0);
164
165             /* dst lookup was done by ip4 lookup */
166             mldi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
167             mld0 = mpls_label_dpo_get(mldi0);
168
169             /* Paint the MPLS header */
170             vlib_buffer_advance(b0, -sizeof(*hdr0));
171             hdr0 = vlib_buffer_get_current(b0);
172
173             // FIXME.
174             // need to copy the TTL from the correct place.
175             // for IPvX imposition from the IP header
176             // so we need a deidcated ipx-to-mpls-label-imp-node
177             // for mpls switch and stack another solution is required.
178             *hdr0 = mld0->mld_hdr;
179
180             next0 = mld0->mld_dpo.dpoi_next_node;
181             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mld0->mld_dpo.dpoi_index;
182
183             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
184             {
185                 mpls_label_imposition_trace_t *tr =
186                     vlib_add_trace (vm, node, b0, sizeof (*tr));
187                 tr->hdr = *hdr0;
188             }
189
190             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
191                                             n_left_to_next, bi0, next0);
192         }
193         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
194     }
195     return from_frame->n_vectors;
196 }
197
198 static u8 *
199 format_mpls_label_imposition_trace (u8 * s, va_list * args)
200 {
201     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
202     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
203     mpls_label_imposition_trace_t * t;
204     mpls_unicast_header_t hdr;
205     uword indent;
206
207     t = va_arg (*args, mpls_label_imposition_trace_t *);
208     indent = format_get_indent (s);
209     hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
210
211     s = format (s, "%Umpls-header:%U",
212                 format_white_space, indent,
213                 format_mpls_header, hdr);
214     return (s);
215 }
216
217 VLIB_REGISTER_NODE (mpls_label_imposition_node) = {
218     .function = mpls_label_imposition,
219     .name = "mpls-label-imposition",
220     .vector_size = sizeof (u32),
221
222     .format_trace = format_mpls_label_imposition_trace,
223     .n_next_nodes = 1,
224     .next_nodes = {
225         [0] = "error-drop",
226     }
227 };
228 VLIB_NODE_FUNCTION_MULTIARCH (mpls_label_imposition_node, mpls_label_imposition)
229
230 static void
231 mpls_label_dpo_mem_show (void)
232 {
233     fib_show_memory_usage("MPLS label",
234                           pool_elts(mpls_label_dpo_pool),
235                           pool_len(mpls_label_dpo_pool),
236                           sizeof(mpls_label_dpo_t));
237 }
238
239 const static dpo_vft_t mld_vft = {
240     .dv_lock = mpls_label_dpo_lock,
241     .dv_unlock = mpls_label_dpo_unlock,
242     .dv_format = format_mpls_label_dpo,
243     .dv_mem_show = mpls_label_dpo_mem_show,
244 };
245
246 const static char* const mpls_label_imp_ip4_nodes[] =
247 {
248     "mpls-label-imposition",
249     NULL,
250 };
251 const static char* const mpls_label_imp_ip6_nodes[] =
252 {
253     "mpls-label-imposition",
254     NULL,
255 };
256 const static char* const mpls_label_imp_mpls_nodes[] =
257 {
258     "mpls-label-imposition",
259     NULL,
260 };
261 const static char* const * const mpls_label_imp_nodes[DPO_PROTO_NUM] =
262 {
263     [DPO_PROTO_IP4]  = mpls_label_imp_ip4_nodes,
264     [DPO_PROTO_IP6]  = mpls_label_imp_ip6_nodes,
265     [DPO_PROTO_MPLS] = mpls_label_imp_mpls_nodes,
266 };
267
268
269 void
270 mpls_label_dpo_module_init (void)
271 {
272     dpo_register(DPO_MPLS_LABEL, &mld_vft, mpls_label_imp_nodes);
273 }