VPP-651: Ensure sw_if_index to node mapping for L2 output path is only done via l2out...
[vpp.git] / src / plugins / acl / l2sess.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  *------------------------------------------------------------------
17  * l2sess.c - simple MAC-swap API / debug CLI handling
18  *------------------------------------------------------------------
19  */
20
21 #include <vnet/vnet.h>
22 #include <vnet/plugin/plugin.h>
23 #include <acl/l2sess.h>
24
25 #include <vlibapi/api.h>
26 #include <vlibmemory/api.h>
27 #include <vlibsocket/api.h>
28 #include <vppinfra/timing_wheel.h>
29
30 #include <vnet/l2/l2_output.h>
31 #include <vnet/l2/l2_input.h>
32
33 void
34 l2sess_init_next_features (vlib_main_t * vm, l2sess_main_t * sm)
35 {
36 #define _(node_name, node_var, is_out, is_ip6, is_track)                 \
37   if (is_out)                                                            \
38     feat_bitmap_init_next_nodes(vm, node_var.index, L2OUTPUT_N_FEAT,      \
39                                 l2output_get_feat_names (),               \
40                                 sm->node_var ## _feat_next_node_index); \
41   else                                                                   \
42     feat_bitmap_init_next_nodes(vm, node_var.index, L2INPUT_N_FEAT,      \
43                                 l2input_get_feat_names (),               \
44                                 sm->node_var ## _feat_next_node_index);
45
46   foreach_l2sess_node
47 #undef _
48 }
49
50 void
51 l2sess_add_our_next_nodes (vlib_main_t * vm, l2sess_main_t * sm,
52                            u8 * prev_node_name, int add_output_nodes)
53 {
54   vlib_node_t *n;
55   n = vlib_get_node_by_name (vm, prev_node_name);
56 #define _(node_name, node_var, is_out, is_ip6, is_track) \
57   if (is_out == add_output_nodes) { \
58     u32 idx = vlib_node_add_next_with_slot(vm, n->index, node_var.index, ~0); \
59     if (is_track) { \
60       sm->next_slot_track_node_by_is_ip6_is_out[is_ip6][is_out] = idx; \
61     } \
62   }
63   foreach_l2sess_node
64 #undef _
65 }
66
67 void
68 l2sess_setup_nodes (void)
69 {
70   vlib_main_t *vm = vlib_get_main ();
71   l2sess_main_t *sm = &l2sess_main;
72
73   l2sess_init_next_features (vm, sm);
74
75   l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-input-classify", 0);
76   l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-output-classify", 1);
77
78 }
79
80 static char *
81 get_l4_proto_str (int is_ip6, uint8_t l4_proto)
82 {
83   switch (l4_proto)
84     {
85     case 6:
86       return "tcp";
87     case 17:
88       return "udp";
89     case 1:
90       return "icmp";
91     case 58:
92       return "icmp6";
93     default:
94       return "<?l4-unknown?>";
95     }
96 }
97
98 static clib_error_t *
99 l2sess_show_command_fn (vlib_main_t * vm,
100                         unformat_input_t * input, vlib_cli_command_t * cmd)
101 {
102   l2sess_main_t *sm = &l2sess_main;
103   clib_time_t *ct = &vm->clib_time;
104   l2s_session_t *s;
105   u64 now = clib_cpu_time_now ();
106
107   vlib_cli_output (vm, "Timing wheel info: \n%U", format_timing_wheel,
108                    &sm->timing_wheel, 255);
109
110   pool_foreach (s, sm->sessions, (
111                                    {
112                                    f64 ctime =
113                                    (now -
114                                     s->create_time) * ct->seconds_per_clock;
115                                    f64 atime0 =
116                                    (now -
117                                     s->side[0].active_time) *
118                                    ct->seconds_per_clock;
119                                    f64 atime1 =
120                                    (now -
121                                     s->side[1].active_time) *
122                                    ct->seconds_per_clock;
123 /*
124     f64 ctime = (s->create_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock;
125     f64 atime0 = (s->side[0].active_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock;
126     f64 atime1 = (s->side[1].active_time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock;
127 */
128                                    u8 * out0 =
129                                    format (0,
130                                            "%5d: create time: %U pkts/bytes/active time: [ %ld %ld %U : %ld %ld %U ]\n",
131                                            (s - sm->sessions),
132                                            format_time_interval, "h:m:s:u",
133                                            ctime, s->side[0].n_packets,
134                                            s->side[0].n_bytes,
135                                            format_time_interval, "h:m:s:u",
136                                            atime0, s->side[1].n_packets,
137                                            s->side[1].n_bytes,
138                                            format_time_interval, "h:m:s:u",
139                                            atime1); u8 * out1 = 0;
140                                    if (s->is_ip6)
141                                    {
142                                    out1 =
143                                    format (0, "%s %U :%u <-> %U :%u",
144                                            get_l4_proto_str (s->is_ip6,
145                                                              s->l4_proto),
146                                            format_ip6_address,
147                                            &s->side[0].addr.ip6,
148                                            s->side[0].port,
149                                            format_ip6_address,
150                                            &s->side[1].addr.ip6,
151                                            s->side[1].port);}
152                                    else
153                                    {
154                                    out1 =
155                                    format (0, "%s %U :%u <-> %U :%u",
156                                            get_l4_proto_str (s->is_ip6,
157                                                              s->l4_proto),
158                                            format_ip4_address,
159                                            &s->side[0].addr.ip4,
160                                            s->side[0].port,
161                                            format_ip4_address,
162                                            &s->side[1].addr.ip4,
163                                            s->side[1].port);}
164                                    vlib_cli_output (vm, "%s       %s", out0,
165                                                     out1); vec_free (out0);
166                                    vec_free (out1);}
167                 ));
168   return 0;
169 }
170
171 static clib_error_t *
172 l2sess_show_count_command_fn (vlib_main_t * vm,
173                               unformat_input_t * input,
174                               vlib_cli_command_t * cmd)
175 {
176   l2sess_main_t *sm = &l2sess_main;
177
178   vlib_cli_output (vm, "Timing wheel info: \n%U", format_timing_wheel,
179                    &sm->timing_wheel, 255);
180   vlib_cli_output (vm, "session pool len: %d, pool elts: %d",
181                    pool_len (sm->sessions), pool_elts (sm->sessions));
182   vlib_cli_output (vm,
183                    "attempted to delete sessions which were already free: %d",
184                    sm->counter_attempted_delete_free_session);
185   return 0;
186 }
187
188
189 /* *INDENT-OFF* */
190 VLIB_CLI_COMMAND (l2sess_show_command, static) = {
191     .path = "show l2sess",
192     .short_help = "show l2sess",
193     .function = l2sess_show_command_fn,
194 };
195
196 VLIB_CLI_COMMAND (l2sess_show_count_command, static) = {
197     .path = "show l2sess count",
198     .short_help = "show l2sess count",
199     .function = l2sess_show_count_command_fn,
200 };
201 /* *INDENT-OFF* */
202
203 static inline u64
204 time_sec_to_clock( clib_time_t *ct, f64 sec)
205 {
206   return (u64)(((f64)sec)/ct->seconds_per_clock);
207 }
208
209 static clib_error_t * l2sess_init (vlib_main_t * vm)
210 {
211   l2sess_main_t * sm = &l2sess_main;
212   clib_error_t * error = 0;
213   u64 cpu_time_now = clib_cpu_time_now();
214
215
216   clib_time_t *ct = &vm->clib_time;
217   sm->udp_session_idle_timeout = time_sec_to_clock(ct, UDP_SESSION_IDLE_TIMEOUT_SEC);
218   sm->tcp_session_idle_timeout = time_sec_to_clock(ct, TCP_SESSION_IDLE_TIMEOUT_SEC);
219   sm->tcp_session_transient_timeout = time_sec_to_clock(ct, TCP_SESSION_TRANSIENT_TIMEOUT_SEC);
220
221   /* The min sched time of 10e-1 causes erroneous behavior... */
222   sm->timing_wheel.min_sched_time = 10e-2;
223   sm->timing_wheel.max_sched_time = 3600.0*48.0;
224   timing_wheel_init (&sm->timing_wheel, cpu_time_now, vm->clib_time.clocks_per_second);
225   sm->timer_wheel_next_expiring_time = 0;
226   sm->timer_wheel_tick = time_sec_to_clock(ct, sm->timing_wheel.min_sched_time);
227   /* Pre-allocate expired nodes. */
228   vec_alloc (sm->data_from_advancing_timing_wheel, 32);
229
230   l2sess_setup_nodes();
231   l2output_init_output_node_vec (&sm->output_next_nodes.output_node_index_vec);
232
233   return error;
234 }
235
236 VLIB_INIT_FUNCTION (l2sess_init);
237
238