L2-LEARN:fix l2fib entry seq num not updated on hit (VPP-888)
[vpp.git] / src / vnet / l2 / l2_api.c
1 /*
2  *------------------------------------------------------------------
3  * l2_api.c - layer 2 forwarding api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25 #include <vnet/l2/l2_input.h>
26 #include <vnet/l2/l2_fib.h>
27 #include <vnet/l2/l2_vtr.h>
28
29 #include <vnet/vnet_msg_enum.h>
30
31 #define vl_typedefs             /* define message structures */
32 #include <vnet/vnet_all_api_h.h>
33 #undef vl_typedefs
34
35 #define vl_endianfun            /* define message structures */
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_endianfun
38
39 #define vl_api_bridge_domain_details_t_endian vl_noop_handler
40 #define vl_api_bridge_domain_details_t_print vl_noop_handler
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <vnet/vnet_all_api_h.h>
46 #undef vl_printfun
47
48 #include <vlibapi/api_helper_macros.h>
49
50 #define foreach_vpe_api_msg                                 \
51 _(L2_XCONNECT_DUMP, l2_xconnect_dump)                       \
52 _(L2_FIB_CLEAR_TABLE, l2_fib_clear_table)                   \
53 _(L2_FIB_TABLE_DUMP, l2_fib_table_dump)                     \
54 _(L2FIB_FLUSH_ALL, l2fib_flush_all)                         \
55 _(L2FIB_FLUSH_INT, l2fib_flush_int)                         \
56 _(L2FIB_FLUSH_BD, l2fib_flush_bd)                           \
57 _(L2FIB_ADD_DEL, l2fib_add_del)                             \
58 _(L2_FLAGS, l2_flags)                                       \
59 _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del)             \
60 _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump)                   \
61 _(BRIDGE_FLAGS, bridge_flags)                               \
62 _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \
63 _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
64 _(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age)
65
66 static void
67 send_l2_xconnect_details (unix_shared_memory_queue_t * q, u32 context,
68                           u32 rx_sw_if_index, u32 tx_sw_if_index)
69 {
70   vl_api_l2_xconnect_details_t *mp;
71
72   mp = vl_msg_api_alloc (sizeof (*mp));
73   memset (mp, 0, sizeof (*mp));
74   mp->_vl_msg_id = ntohs (VL_API_L2_XCONNECT_DETAILS);
75   mp->context = context;
76   mp->rx_sw_if_index = htonl (rx_sw_if_index);
77   mp->tx_sw_if_index = htonl (tx_sw_if_index);
78
79   vl_msg_api_send_shmem (q, (u8 *) & mp);
80 }
81
82 static void
83 vl_api_l2_xconnect_dump_t_handler (vl_api_l2_xconnect_dump_t * mp)
84 {
85   unix_shared_memory_queue_t *q;
86   vnet_main_t *vnm = vnet_get_main ();
87   vnet_interface_main_t *im = &vnm->interface_main;
88   l2input_main_t *l2im = &l2input_main;
89   vnet_sw_interface_t *swif;
90   l2_input_config_t *config;
91
92   q = vl_api_client_index_to_input_queue (mp->client_index);
93   if (q == 0)
94     return;
95
96   /* *INDENT-OFF* */
97   pool_foreach (swif, im->sw_interfaces,
98   ({
99     config = vec_elt_at_index (l2im->configs, swif->sw_if_index);
100     if (config->xconnect)
101       send_l2_xconnect_details (q, mp->context, swif->sw_if_index,
102                                 config->output_sw_if_index);
103   }));
104   /* *INDENT-ON* */
105 }
106
107 static void
108 vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp)
109 {
110   int rv = 0;
111   vl_api_l2_fib_clear_table_reply_t *rmp;
112
113   /* Clear all MACs including static MACs  */
114   l2fib_clear_table ();
115
116   REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY);
117 }
118
119 static void
120 send_l2fib_table_entry (vpe_api_main_t * am,
121                         unix_shared_memory_queue_t * q,
122                         l2fib_entry_key_t * l2fe_key,
123                         l2fib_entry_result_t * l2fe_res, u32 context)
124 {
125   vl_api_l2_fib_table_details_t *mp;
126
127   mp = vl_msg_api_alloc (sizeof (*mp));
128   memset (mp, 0, sizeof (*mp));
129   mp->_vl_msg_id = ntohs (VL_API_L2_FIB_TABLE_DETAILS);
130
131   mp->bd_id =
132     ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id);
133
134   mp->mac = l2fib_make_key (l2fe_key->fields.mac, 0);
135   mp->sw_if_index = ntohl (l2fe_res->fields.sw_if_index);
136   mp->static_mac = l2fe_res->fields.static_mac;
137   mp->filter_mac = l2fe_res->fields.filter;
138   mp->bvi_mac = l2fe_res->fields.bvi;
139   mp->context = context;
140
141   vl_msg_api_send_shmem (q, (u8 *) & mp);
142 }
143
144 static void
145 vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp)
146 {
147   vpe_api_main_t *am = &vpe_api_main;
148   bd_main_t *bdm = &bd_main;
149   l2fib_entry_key_t *l2fe_key = NULL;
150   l2fib_entry_result_t *l2fe_res = NULL;
151   u32 ni, bd_id = ntohl (mp->bd_id);
152   u32 bd_index;
153   unix_shared_memory_queue_t *q;
154   uword *p;
155
156   q = vl_api_client_index_to_input_queue (mp->client_index);
157   if (q == 0)
158     return;
159
160   /* see l2fib_table_dump: ~0 means "any" */
161   if (bd_id == ~0)
162     bd_index = ~0;
163   else
164     {
165       p = hash_get (bdm->bd_index_by_bd_id, bd_id);
166       if (p == 0)
167         return;
168
169       bd_index = p[0];
170     }
171
172   l2fib_table_dump (bd_index, &l2fe_key, &l2fe_res);
173
174   vec_foreach_index (ni, l2fe_key)
175   {
176     send_l2fib_table_entry (am, q, vec_elt_at_index (l2fe_key, ni),
177                             vec_elt_at_index (l2fe_res, ni), mp->context);
178   }
179   vec_free (l2fe_key);
180   vec_free (l2fe_res);
181 }
182
183 static void
184 vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp)
185 {
186   bd_main_t *bdm = &bd_main;
187   l2input_main_t *l2im = &l2input_main;
188   vl_api_l2fib_add_del_reply_t *rmp;
189   int rv = 0;
190   u32 bd_id = ntohl (mp->bd_id);
191   uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
192
193   if (!p)
194     {
195       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
196       goto bad_sw_if_index;
197     }
198   u32 bd_index = p[0];
199
200   u64 mac = mp->mac;
201   if (mp->is_add)
202     {
203       if (mp->filter_mac)
204         l2fib_add_filter_entry (mac, bd_index);
205       else
206         {
207           u32 sw_if_index = ntohl (mp->sw_if_index);
208           VALIDATE_SW_IF_INDEX (mp);
209           if (vec_len (l2im->configs) <= sw_if_index)
210             {
211               rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
212               goto bad_sw_if_index;
213             }
214           else
215             {
216               l2_input_config_t *config;
217               config = vec_elt_at_index (l2im->configs, sw_if_index);
218               if (config->bridge == 0)
219                 {
220                   rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
221                   goto bad_sw_if_index;
222                 }
223             }
224           u32 static_mac = mp->static_mac ? 1 : 0;
225           u32 bvi_mac = mp->bvi_mac ? 1 : 0;
226           l2fib_add_fwd_entry (mac, bd_index, sw_if_index, static_mac,
227                                bvi_mac);
228         }
229     }
230   else
231     {
232       l2fib_del_entry (mac, bd_index);
233     }
234
235   BAD_SW_IF_INDEX_LABEL;
236
237   REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY);
238 }
239
240 static void
241 vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp)
242 {
243   int rv = 0;
244   vlib_main_t *vm = vlib_get_main ();
245   vl_api_l2fib_flush_int_reply_t *rmp;
246
247   VALIDATE_SW_IF_INDEX (mp);
248
249   u32 sw_if_index = ntohl (mp->sw_if_index);
250   l2fib_flush_int_mac (vm, sw_if_index);
251
252   BAD_SW_IF_INDEX_LABEL;
253   REPLY_MACRO (VL_API_L2FIB_FLUSH_INT_REPLY);
254 }
255
256 static void
257 vl_api_l2fib_flush_all_t_handler (vl_api_l2fib_flush_all_t * mp)
258 {
259   int rv = 0;
260   vl_api_l2fib_flush_all_reply_t *rmp;
261
262   l2fib_flush_all_mac (vlib_get_main ());
263   REPLY_MACRO (VL_API_L2FIB_FLUSH_ALL_REPLY);
264 }
265
266 static void
267 vl_api_l2fib_flush_bd_t_handler (vl_api_l2fib_flush_bd_t * mp)
268 {
269   int rv = 0;
270   vlib_main_t *vm = vlib_get_main ();
271   bd_main_t *bdm = &bd_main;
272   vl_api_l2fib_flush_bd_reply_t *rmp;
273
274   u32 bd_id = ntohl (mp->bd_id);
275   uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id);
276   if (p == 0)
277     {
278       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
279       goto out;
280     }
281   l2fib_flush_bd_mac (vm, *p);
282 out:
283   REPLY_MACRO (VL_API_L2FIB_FLUSH_BD_REPLY);
284 }
285
286 static void
287 vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp)
288 {
289   vl_api_l2_flags_reply_t *rmp;
290   int rv = 0;
291   u32 rbm = 0;
292
293   VALIDATE_SW_IF_INDEX (mp);
294
295   u32 sw_if_index = ntohl (mp->sw_if_index);
296   u32 flags = ntohl (mp->feature_bitmap) & L2INPUT_VALID_MASK;
297   rbm = l2input_intf_bitmap_enable (sw_if_index, flags, mp->is_set);
298
299   BAD_SW_IF_INDEX_LABEL;
300
301   /* *INDENT-OFF* */
302   REPLY_MACRO2(VL_API_L2_FLAGS_REPLY,
303   ({
304     rmp->resulting_feature_bitmap = ntohl(rbm);
305   }));
306   /* *INDENT-ON* */
307 }
308
309 static void
310 vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t
311                                             * mp)
312 {
313   vlib_main_t *vm = vlib_get_main ();
314   bd_main_t *bdm = &bd_main;
315   vl_api_bridge_domain_set_mac_age_reply_t *rmp;
316   int rv = 0;
317   u32 bd_id = ntohl (mp->bd_id);
318   uword *p;
319
320   if (bd_id == 0)
321     {
322       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
323       goto out;
324     }
325
326   p = hash_get (bdm->bd_index_by_bd_id, bd_id);
327   if (p == 0)
328     {
329       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
330       goto out;
331     }
332   bd_set_mac_age (vm, *p, mp->mac_age);
333 out:
334   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_MAC_AGE_REPLY);
335 }
336
337 static void
338 vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp)
339 {
340   l2_bridge_domain_add_del_args_t a = {
341     .is_add = mp->is_add,
342     .flood = mp->flood,
343     .uu_flood = mp->uu_flood,
344     .forward = mp->forward,
345     .learn = mp->learn,
346     .arp_term = mp->arp_term,
347     .mac_age = mp->mac_age,
348     .bd_id = ntohl (mp->bd_id),
349   };
350
351   int rv = bd_add_del (&a);
352
353   vl_api_bridge_domain_add_del_reply_t *rmp;
354   REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY);
355 }
356
357 static void
358 send_bridge_domain_details (l2input_main_t * l2im,
359                             unix_shared_memory_queue_t * q,
360                             l2_bridge_domain_t * bd_config,
361                             u32 n_sw_ifs, u32 context)
362 {
363   vl_api_bridge_domain_details_t *mp;
364   l2_flood_member_t *m;
365   vl_api_bridge_domain_sw_if_t *sw_ifs;
366   l2_input_config_t *input_cfg;
367
368   mp = vl_msg_api_alloc (sizeof (*mp) +
369                          (n_sw_ifs * sizeof (vl_api_bridge_domain_sw_if_t)));
370   memset (mp, 0, sizeof (*mp));
371   mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_DETAILS);
372   mp->bd_id = ntohl (bd_config->bd_id);
373   mp->flood = bd_feature_flood (bd_config);
374   mp->uu_flood = bd_feature_uu_flood (bd_config);
375   mp->forward = bd_feature_forward (bd_config);
376   mp->learn = bd_feature_learn (bd_config);
377   mp->arp_term = bd_feature_arp_term (bd_config);
378   mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index);
379   mp->mac_age = bd_config->mac_age;
380   mp->context = context;
381
382   sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details;
383   vec_foreach (m, bd_config->members)
384   {
385     sw_ifs->sw_if_index = ntohl (m->sw_if_index);
386     input_cfg = vec_elt_at_index (l2im->configs, m->sw_if_index);
387     sw_ifs->shg = input_cfg->shg;
388     sw_ifs++;
389     mp->n_sw_ifs++;
390   }
391   mp->n_sw_ifs = htonl (mp->n_sw_ifs);
392
393   vl_msg_api_send_shmem (q, (u8 *) & mp);
394 }
395
396 static void
397 vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp)
398 {
399   bd_main_t *bdm = &bd_main;
400   l2input_main_t *l2im = &l2input_main;
401
402   unix_shared_memory_queue_t *q =
403     vl_api_client_index_to_input_queue (mp->client_index);
404   if (q == 0)
405     return;
406
407   u32 bd_id = ntohl (mp->bd_id);
408   if (bd_id == 0)
409     return;
410
411   u32 bd_index, end;
412   if (bd_id == ~0)
413     bd_index = 0, end = vec_len (l2im->bd_configs);
414   else
415     {
416       bd_index = bd_find_index (bdm, bd_id);
417       if (bd_index == ~0)
418         return;
419
420       end = bd_index + 1;
421     }
422
423   for (; bd_index < end; bd_index++)
424     {
425       l2_bridge_domain_t *bd_config =
426         l2input_bd_config_from_index (l2im, bd_index);
427       /* skip dummy bd_id 0 */
428       if (bd_config && (bd_config->bd_id > 0))
429         send_bridge_domain_details (l2im, q, bd_config,
430                                     vec_len (bd_config->members),
431                                     mp->context);
432     }
433 }
434
435 static void
436 vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp)
437 {
438   vlib_main_t *vm = vlib_get_main ();
439   bd_main_t *bdm = &bd_main;
440   vl_api_bridge_flags_reply_t *rmp;
441   int rv = 0;
442
443   u32 flags = ntohl (mp->feature_bitmap);
444   u32 bd_id = ntohl (mp->bd_id);
445   if (bd_id == 0)
446     {
447       rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
448       goto out;
449     }
450
451   u32 bd_index = bd_find_index (bdm, bd_id);
452   if (bd_index == ~0)
453     {
454       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
455       goto out;
456     }
457
458   bd_set_flags (vm, bd_index, flags, mp->is_set);
459
460 out:
461   /* *INDENT-OFF* */
462   REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY,
463   ({
464     rmp->resulting_feature_bitmap = ntohl(flags);
465   }));
466   /* *INDENT-ON* */
467 }
468
469 static void
470   vl_api_l2_interface_vlan_tag_rewrite_t_handler
471   (vl_api_l2_interface_vlan_tag_rewrite_t * mp)
472 {
473   int rv = 0;
474   vl_api_l2_interface_vlan_tag_rewrite_reply_t *rmp;
475   vnet_main_t *vnm = vnet_get_main ();
476   vlib_main_t *vm = vlib_get_main ();
477   u32 vtr_op;
478
479   VALIDATE_SW_IF_INDEX (mp);
480
481   vtr_op = ntohl (mp->vtr_op);
482
483   /* The L2 code is unsuspicious */
484   switch (vtr_op)
485     {
486     case L2_VTR_DISABLED:
487     case L2_VTR_PUSH_1:
488     case L2_VTR_PUSH_2:
489     case L2_VTR_POP_1:
490     case L2_VTR_POP_2:
491     case L2_VTR_TRANSLATE_1_1:
492     case L2_VTR_TRANSLATE_1_2:
493     case L2_VTR_TRANSLATE_2_1:
494     case L2_VTR_TRANSLATE_2_2:
495       break;
496
497     default:
498       rv = VNET_API_ERROR_INVALID_VALUE;
499       goto bad_sw_if_index;
500     }
501
502   rv = l2vtr_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
503                         ntohl (mp->push_dot1q), ntohl (mp->tag1),
504                         ntohl (mp->tag2));
505
506   BAD_SW_IF_INDEX_LABEL;
507
508   REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY);
509 }
510
511 static void
512   vl_api_l2_interface_pbb_tag_rewrite_t_handler
513   (vl_api_l2_interface_pbb_tag_rewrite_t * mp)
514 {
515   vl_api_l2_interface_pbb_tag_rewrite_reply_t *rmp;
516   vnet_main_t *vnm = vnet_get_main ();
517   vlib_main_t *vm = vlib_get_main ();
518   u32 vtr_op;
519   int rv = 0;
520
521   VALIDATE_SW_IF_INDEX (mp);
522
523   vtr_op = ntohl (mp->vtr_op);
524
525   switch (vtr_op)
526     {
527     case L2_VTR_DISABLED:
528     case L2_VTR_PUSH_2:
529     case L2_VTR_POP_2:
530     case L2_VTR_TRANSLATE_2_1:
531       break;
532
533     default:
534       rv = VNET_API_ERROR_INVALID_VALUE;
535       goto bad_sw_if_index;
536     }
537
538   rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op,
539                         mp->b_dmac, mp->b_smac, ntohs (mp->b_vlanid),
540                         ntohl (mp->i_sid), ntohs (mp->outer_tag));
541
542   BAD_SW_IF_INDEX_LABEL;
543
544   REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY);
545 }
546
547 /*
548  * l2_api_hookup
549  * Add vpe's API message handlers to the table.
550  * vlib has alread mapped shared memory and
551  * added the client registration handlers.
552  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
553  */
554 #define vl_msg_name_crc_list
555 #include <vnet/vnet_all_api_h.h>
556 #undef vl_msg_name_crc_list
557
558 static void
559 setup_message_id_table (api_main_t * am)
560 {
561 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
562   foreach_vl_msg_name_crc_l2;
563 #undef _
564 }
565
566 static clib_error_t *
567 l2_api_hookup (vlib_main_t * vm)
568 {
569   api_main_t *am = &api_main;
570
571 #define _(N,n)                                                  \
572     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
573                            vl_api_##n##_t_handler,              \
574                            vl_noop_handler,                     \
575                            vl_api_##n##_t_endian,               \
576                            vl_api_##n##_t_print,                \
577                            sizeof(vl_api_##n##_t), 1);
578   foreach_vpe_api_msg;
579 #undef _
580
581   /*
582    * Set up the (msg_name, crc, message-id) table
583    */
584   setup_message_id_table (am);
585
586   return 0;
587 }
588
589 VLIB_API_INIT_FUNCTION (l2_api_hookup);
590
591 /*
592  * fd.io coding-style-patch-verification: ON
593  *
594  * Local Variables:
595  * eval: (c-set-style "gnu")
596  * End:
597  */