dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / src / vnet / cop / cop.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 #include <vnet/cop/cop.h>
16
17 cop_main_t cop_main;
18
19 static clib_error_t *
20 cop_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
21 {
22   cop_main_t * cm = &cop_main;
23   cop_config_data_t _data, *data = &_data;
24   vlib_main_t * vm = cm->vlib_main;
25   vnet_hw_interface_t * hi = vnet_get_sup_hw_interface (vnm, sw_if_index);;
26   cop_config_main_t * ccm;
27   int address_family;
28   u32 ci, default_next;
29
30   memset (data, 0, sizeof(*data));
31
32   /* 
33    * Ignore local interface, pg interfaces. $$$ need a #define for the
34    * first "real" interface. The answer is 5 at the moment.
35    */
36   if (hi->dev_class_index == vnet_local_interface_device_class.index)
37     return 0;
38
39    for (address_family = VNET_COP_IP4; address_family < VNET_N_COPS;
40        address_family++)
41     {
42       ccm = &cm->cop_config_mains[address_family];
43
44       /* 
45        * Once-only code to initialize the per-address-family
46        * cop feature subgraphs.
47        * Since the (single) start-node, cop-input, must be able
48        * to push pkts into three separate subgraphs, we
49        * use a unified cop_feature_type_t enumeration.
50        */
51
52       if (!(ccm->config_main.node_index_by_feature_index))
53         {
54           switch (address_family)
55             {
56             case VNET_COP_IP4:
57               {
58                 static char * start_nodes[] = { "cop-input" };
59                 static char * feature_nodes[] = {
60                   [IP4_RX_COP_WHITELIST] = "ip4-cop-whitelist",
61                   [IP4_RX_COP_INPUT] = "ip4-input",
62                 };
63                 
64                 vnet_config_init (vm, &ccm->config_main, 
65                                   start_nodes, ARRAY_LEN(start_nodes),
66                                   feature_nodes, ARRAY_LEN(feature_nodes));
67               }
68               break;
69             case VNET_COP_IP6:
70               {
71                 static char * start_nodes[] = { "cop-input" };
72                 static char * feature_nodes[] = {
73                   [IP6_RX_COP_WHITELIST] = "ip6-cop-whitelist",
74                   [IP6_RX_COP_INPUT] = "ip6-input",
75                 };
76                 vnet_config_init (vm, &ccm->config_main, 
77                                   start_nodes, ARRAY_LEN(start_nodes),
78                                   feature_nodes, ARRAY_LEN(feature_nodes));
79               }
80               break;
81
82             case VNET_COP_DEFAULT:
83               {
84                 static char * start_nodes[] = { "cop-input" };
85                 static char * feature_nodes[] = {
86                   [DEFAULT_RX_COP_WHITELIST] = "default-cop-whitelist",
87                   [DEFAULT_RX_COP_INPUT] = "ethernet-input",
88                 };
89                 vnet_config_init (vm, &ccm->config_main, 
90                                   start_nodes, ARRAY_LEN(start_nodes),
91                                   feature_nodes, ARRAY_LEN(feature_nodes));
92               }
93               break;
94
95             default:
96               clib_warning ("bug");
97               break;
98             }
99         }
100       vec_validate_init_empty (ccm->config_index_by_sw_if_index, sw_if_index,
101                                ~0);
102
103       ci = ccm->config_index_by_sw_if_index[sw_if_index];
104
105       /* Create a sensible initial config: send pkts to xxx-input */
106       if (address_family == VNET_COP_IP4)
107         default_next = IP4_RX_COP_INPUT;
108       else if (address_family == VNET_COP_IP6)
109         default_next = IP6_RX_COP_INPUT;
110       else
111         default_next = DEFAULT_RX_COP_INPUT;
112         
113       if (is_add)
114         ci = vnet_config_add_feature (vm, &ccm->config_main,
115                                       ci, 
116                                       default_next,
117                                       data, sizeof(*data));
118       else
119         ci = vnet_config_del_feature (vm, &ccm->config_main,
120                                       ci, 
121                                       default_next,
122                                       data, sizeof(*data));
123
124       ccm->config_index_by_sw_if_index[sw_if_index] = ci;
125     }
126   return 0;
127 }
128
129 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (cop_sw_interface_add_del);
130
131 static clib_error_t *
132 cop_init (vlib_main_t *vm)
133 {
134   cop_main_t * cm = &cop_main;
135   clib_error_t * error;
136
137   if ((error = vlib_call_init_function (vm, ip4_whitelist_init)))
138     return error;
139
140   if ((error = vlib_call_init_function (vm, ip6_whitelist_init)))
141     return error;
142
143   cm->vlib_main = vm;
144   cm->vnet_main = vnet_get_main();
145
146   return 0;
147 }
148
149 VLIB_INIT_FUNCTION (cop_init);
150
151 int cop_interface_enable_disable (u32 sw_if_index, int enable_disable)
152 {
153   cop_main_t * cm = &cop_main;
154   vnet_sw_interface_t * sw;
155   int rv;
156   u32 node_index = enable_disable ? cop_input_node.index : ~0;
157
158   /* Not a physical port? */
159   sw = vnet_get_sw_interface (cm->vnet_main, sw_if_index);
160   if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
161     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
162   
163   /* 
164    * Redirect pkts from the driver to the cop node.
165    * Returns VNET_API_ERROR_UNIMPLEMENTED if the h/w driver
166    * doesn't implement the API. 
167    *
168    * Node_index = ~0 => shut off redirection
169    */
170   rv = vnet_hw_interface_rx_redirect_to_node (cm->vnet_main, sw_if_index,
171                                               node_index);
172   return rv;
173 }
174
175 static clib_error_t *
176 cop_enable_disable_command_fn (vlib_main_t * vm,
177                                 unformat_input_t * input,
178                                 vlib_cli_command_t * cmd)
179 {
180   cop_main_t * cm = &cop_main;
181   u32 sw_if_index = ~0;
182   int enable_disable = 1;
183     
184   int rv;
185
186   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
187     if (unformat (input, "disable"))
188       enable_disable = 0;
189     else if (unformat (input, "%U", unformat_vnet_sw_interface,
190                        cm->vnet_main, &sw_if_index))
191       ;
192     else
193       break;
194   }
195
196   if (sw_if_index == ~0)
197     return clib_error_return (0, "Please specify an interface...");
198     
199   rv = cop_interface_enable_disable (sw_if_index, enable_disable);
200
201   switch(rv) {
202   case 0:
203     break;
204
205   case VNET_API_ERROR_INVALID_SW_IF_INDEX:
206     return clib_error_return 
207       (0, "Invalid interface, only works on physical ports");
208     break;
209
210   case VNET_API_ERROR_UNIMPLEMENTED:
211     return clib_error_return (0, "Device driver doesn't support redirection");
212     break;
213
214   default:
215     return clib_error_return (0, "cop_interface_enable_disable returned %d",
216                               rv);
217   }
218   return 0;
219 }
220
221 VLIB_CLI_COMMAND (cop_interface_command, static) = {
222     .path = "cop interface",
223     .short_help = 
224     "cop interface <interface-name> [disable]",
225     .function = cop_enable_disable_command_fn,
226 };
227
228
229 int cop_whitelist_enable_disable (cop_whitelist_enable_disable_args_t *a)
230 {
231   cop_main_t * cm = &cop_main;
232   vlib_main_t * vm = cm->vlib_main;
233   ip4_main_t * im4 = &ip4_main;
234   ip6_main_t * im6 = &ip6_main;
235   int address_family;
236   int is_add;
237   cop_config_main_t * ccm;
238   u32 next_to_add_del = 0;
239   uword * p;
240   u32 fib_index = 0;
241   u32 ci;
242   cop_config_data_t _data, *data=&_data;
243
244   /*
245    * Enable / disable whitelist processing on the specified interface
246    */
247
248   for (address_family = VNET_COP_IP4; address_family < VNET_N_COPS;
249        address_family++) 
250     {
251       ccm = &cm->cop_config_mains[address_family];
252     
253       switch(address_family)
254         {
255         case VNET_COP_IP4:
256           is_add = (a->ip4 != 0);
257           next_to_add_del = IP4_RX_COP_WHITELIST;
258           /* configured opaque data must match, or no supper */
259           p = hash_get (im4->fib_index_by_table_id, a->fib_id);
260           if (p)
261             fib_index = p[0];
262           else
263             {
264               if (is_add)
265                 return VNET_API_ERROR_NO_SUCH_FIB;
266               else
267                 continue;
268             }
269           break;
270               
271         case VNET_COP_IP6:
272           is_add = (a->ip6 != 0);
273           next_to_add_del = IP6_RX_COP_WHITELIST;
274           p = hash_get (im6->fib_index_by_table_id, a->fib_id);
275           if (p)
276             fib_index = p[0];
277           else
278             {
279               if (is_add)
280                 return VNET_API_ERROR_NO_SUCH_FIB;
281               else
282                 continue;
283             }
284           break;
285
286         case VNET_COP_DEFAULT:
287           is_add = (a->default_cop != 0);
288           next_to_add_del = DEFAULT_RX_COP_WHITELIST;
289           break;
290         
291         default:
292           clib_warning ("BUG");
293         }
294
295       ci = ccm->config_index_by_sw_if_index[a->sw_if_index];
296       data->fib_index = fib_index;
297
298       if (is_add)
299         ci = vnet_config_add_feature (vm, &ccm->config_main,
300                                       ci,
301                                       next_to_add_del,
302                                       data, sizeof (*data));
303       else
304         ci = vnet_config_del_feature (vm, &ccm->config_main,
305                                       ci,
306                                       next_to_add_del,
307                                       data, sizeof (*data));
308
309       ccm->config_index_by_sw_if_index[a->sw_if_index] = ci;
310     }
311   return 0;
312 }
313
314 static clib_error_t *
315 cop_whitelist_enable_disable_command_fn (vlib_main_t * vm,
316                                          unformat_input_t * input,
317                                          vlib_cli_command_t * cmd)
318 {
319   cop_main_t * cm = &cop_main;
320   u32 sw_if_index = ~0;
321   u8 ip4 = 0;
322   u8 ip6 = 0;
323   u8 default_cop = 0;
324   u32 fib_id = 0;
325   int rv;
326   cop_whitelist_enable_disable_args_t _a, * a = &_a;
327
328   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
329     if (unformat (input, "ip4"))
330       ip4 = 1;
331     else if (unformat (input, "ip6"))
332       ip6 = 1;
333     else if (unformat (input, "default"))
334       default_cop = 1;
335     else if (unformat (input, "%U", unformat_vnet_sw_interface,
336                        cm->vnet_main, &sw_if_index))
337       ;
338     else if (unformat (input, "fib-id %d", &fib_id))
339       ;
340     else
341       break;
342   }
343
344   if (sw_if_index == ~0)
345     return clib_error_return (0, "Please specify an interface...");
346     
347   a->sw_if_index = sw_if_index;
348   a->ip4 = ip4;
349   a->ip6 = ip6;
350   a->default_cop = default_cop;
351   a->fib_id = fib_id;
352
353   rv = cop_whitelist_enable_disable (a);
354
355   switch(rv) {
356   case 0:
357     break;
358
359   case VNET_API_ERROR_INVALID_SW_IF_INDEX:
360     return clib_error_return 
361       (0, "Invalid interface, only works on physical ports");
362     break;
363
364   case VNET_API_ERROR_NO_SUCH_FIB:
365     return clib_error_return 
366       (0, "Invalid fib");
367     break;
368
369   case VNET_API_ERROR_UNIMPLEMENTED:
370     return clib_error_return (0, "Device driver doesn't support redirection");
371     break;
372
373   default:
374     return clib_error_return (0, "cop_whitelist_enable_disable returned %d",
375                               rv);
376   }
377
378   return 0;
379 }
380
381 VLIB_CLI_COMMAND (cop_whitelist_command, static) = {
382     .path = "cop whitelist",
383     .short_help = 
384     "cop whitelist <interface-name> [ip4][ip6][default][fib-id <NN>][disable]",
385     .function = cop_whitelist_enable_disable_command_fn,
386 };
387