Move java,lua api and remaining plugins to src/
[vpp.git] / src / plugins / ioam / encap / ip6_ioam_pot.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 <vlib/vlib.h>
16 #include <vnet/vnet.h>
17 #include <vnet/pg/pg.h>
18 #include <vppinfra/error.h>
19
20 #include <vnet/ip/ip6.h>
21 #include <vnet/ip/ip6_hop_by_hop.h>
22 #include <vnet/ip/ip6_hop_by_hop_packet.h>
23
24 #include <vppinfra/hash.h>
25 #include <vppinfra/error.h>
26 #include <vppinfra/elog.h>
27
28 #include <ioam/lib-pot/pot_util.h>
29
30 typedef CLIB_PACKED(struct {
31   ip6_hop_by_hop_option_t hdr;
32   u8 pot_type;
33 #define PROFILE_ID_MASK 0xF
34   u8 reserved_profile_id; /* 4 bits reserved, 4 bits to carry profile id */
35   u64 random;
36   u64 cumulative;
37 }) ioam_pot_option_t;
38
39 #define foreach_ip6_hop_by_hop_ioam_pot_stats                           \
40   _(PROCESSED, "Pkts with ip6 hop-by-hop pot options")                  \
41   _(PROFILE_MISS, "Pkts with ip6 hop-by-hop pot options but no profile set") \
42   _(PASSED, "Pkts with POT in Policy")                                  \
43   _(FAILED, "Pkts with POT out of Policy") 
44
45 static char * ip6_hop_by_hop_ioam_pot_stats_strings[] = {
46 #define _(sym,string) string,
47   foreach_ip6_hop_by_hop_ioam_pot_stats
48 #undef _
49 };
50
51 typedef enum {
52 #define _(sym,str) IP6_IOAM_POT_##sym,
53   foreach_ip6_hop_by_hop_ioam_pot_stats
54 #undef _
55   IP6_IOAM_POT_N_STATS,
56 } ip6_ioam_pot_stats_t;
57
58 typedef struct {
59   /* stats */
60   u64 counters[ARRAY_LEN(ip6_hop_by_hop_ioam_pot_stats_strings)];
61   
62   /* convenience */
63   vlib_main_t * vlib_main;
64   vnet_main_t * vnet_main;
65 } ip6_hop_by_hop_ioam_pot_main_t;
66
67 ip6_hop_by_hop_ioam_pot_main_t ip6_hop_by_hop_ioam_pot_main;
68
69 always_inline void 
70 ip6_ioam_stats_increment_counter (u32 counter_index, u64 increment)
71 {
72   ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
73
74   hm->counters[counter_index] += increment;
75 }
76
77
78 static u8 * format_ioam_pot (u8 * s, va_list * args)
79 {
80   ioam_pot_option_t * pot0 = va_arg (*args, ioam_pot_option_t *);
81   u64 random, cumulative;
82   random = cumulative = 0;
83   if (pot0) 
84     { 
85       random = clib_net_to_host_u64 (pot0->random);
86       cumulative = clib_net_to_host_u64 (pot0->cumulative);
87     }
88
89   s = format (s, "random = 0x%Lx, Cumulative = 0x%Lx, Index = 0x%x", 
90               random, cumulative, pot0 ? pot0->reserved_profile_id : ~0);
91   return s;
92 }
93
94 u8 *
95 ip6_hbh_ioam_proof_of_transit_trace_handler (u8 *s, ip6_hop_by_hop_option_t *opt)
96 {
97   ioam_pot_option_t *pot;
98
99   s = format (s, "    POT opt present\n");
100   pot = (ioam_pot_option_t *) opt;
101   s = format (s, "         %U\n", format_ioam_pot, pot);
102   return (s);
103 }
104
105 int
106 ip6_hbh_ioam_proof_of_transit_handler (vlib_buffer_t *b,
107                                        ip6_header_t *ip,
108                                        ip6_hop_by_hop_option_t *opt0)
109 {
110   ioam_pot_option_t * pot0;
111   u64 random = 0, cumulative = 0;
112   int rv = 0;
113   u8 pot_profile_index;
114   pot_profile *pot_profile = 0, *new_profile = 0;
115   u8 pot_encap = 0;
116
117   pot0 = (ioam_pot_option_t *) opt0;
118   pot_encap = (pot0->random == 0);
119   pot_profile_index = pot_profile_get_active_id();
120   pot_profile = pot_profile_get_active();
121   if (pot_encap && PREDICT_FALSE(!pot_profile))
122     {
123       ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
124       return(-1);
125     }
126   if (pot_encap)
127     {
128       pot0->reserved_profile_id =
129         pot_profile_index & PROFILE_ID_MASK;
130       pot_profile_incr_usage_stats(pot_profile);
131     } 
132   else 
133     { /* Non encap node */
134       if (PREDICT_FALSE(pot0->reserved_profile_id != 
135                         pot_profile_index || pot_profile == 0)) 
136         {
137           /* New profile announced by encap node. */
138           new_profile =
139             pot_profile_find(pot0->reserved_profile_id); 
140           if (PREDICT_FALSE(new_profile == 0 ||
141                             new_profile->valid == 0)) 
142             {
143               ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROFILE_MISS, 1);
144               return(-1);
145             } 
146           else 
147             {
148               pot_profile_index = pot0->reserved_profile_id;
149               pot_profile = new_profile;
150               pot_profile_set_active(pot_profile_index);
151               pot_profile_reset_usage_stats(pot_profile);
152             }
153         }
154       pot_profile_incr_usage_stats(pot_profile);
155     }
156
157   if (pot0->random == 0) 
158     {
159       pot0->random = clib_host_to_net_u64(pot_generate_random(pot_profile));
160       pot0->cumulative = 0;
161     }
162   random = clib_net_to_host_u64(pot0->random);
163   cumulative = clib_net_to_host_u64(pot0->cumulative);
164   pot0->cumulative = clib_host_to_net_u64(
165                                           pot_update_cumulative(pot_profile,
166                                                                 cumulative,
167                                                                 random));
168   ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PROCESSED, 1);
169
170   return (rv);
171 }
172
173 int
174 ip6_hbh_ioam_proof_of_transit_pop_handler (vlib_buffer_t *b, ip6_header_t *ip,
175                                            ip6_hop_by_hop_option_t *opt0)
176 {
177   ioam_pot_option_t * pot0;
178   u64 random = 0;
179   u64 cumulative = 0;
180   int rv = 0;
181   pot_profile *pot_profile = 0;
182   u8 result = 0;
183   
184   pot0 = (ioam_pot_option_t *) opt0;
185   random = clib_net_to_host_u64(pot0->random);
186   cumulative = clib_net_to_host_u64(pot0->cumulative);
187   pot_profile = pot_profile_get_active();
188   result =  pot_validate (pot_profile,
189                           cumulative, random);
190           
191   if (result == 1) 
192     {
193       ip6_ioam_stats_increment_counter (IP6_IOAM_POT_PASSED, 1);
194     }
195   else 
196     {
197       ip6_ioam_stats_increment_counter (IP6_IOAM_POT_FAILED, 1);
198     }
199   return (rv);
200 }
201
202 int ip6_hop_by_hop_ioam_pot_rewrite_handler (u8 *rewrite_string, u8 *rewrite_size)
203 {
204   ioam_pot_option_t * pot_option;
205   if (rewrite_string && *rewrite_size == sizeof(ioam_pot_option_t))
206     {
207       pot_option = (ioam_pot_option_t *)rewrite_string;
208       pot_option->hdr.type = HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
209         | HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
210       pot_option->hdr.length = sizeof (ioam_pot_option_t) - 
211         sizeof (ip6_hop_by_hop_option_t);
212       return(0);
213     }
214   return(-1);
215 }
216
217 static clib_error_t *
218 ip6_show_ioam_pot_cmd_fn (vlib_main_t * vm,
219                           unformat_input_t * input,
220                           vlib_cli_command_t * cmd)
221 {
222   ip6_hop_by_hop_ioam_pot_main_t *hm = &ip6_hop_by_hop_ioam_pot_main;
223   u8 *s = 0;
224   int i = 0;
225
226   for ( i = 0; i < IP6_IOAM_POT_N_STATS; i++)
227     {
228       s = format(s, " %s - %lu\n", ip6_hop_by_hop_ioam_pot_stats_strings[i],
229                hm->counters[i]);
230     }
231
232   vlib_cli_output(vm, "%v", s);
233   vec_free(s);
234   return 0;
235 }
236
237
238 VLIB_CLI_COMMAND (ip6_show_ioam_pot_cmd, static) = {
239   .path = "show ioam pot",
240   .short_help = "iOAM pot statistics",
241   .function = ip6_show_ioam_pot_cmd_fn,
242 };
243
244
245 static clib_error_t *
246 ip6_hop_by_hop_ioam_pot_init (vlib_main_t * vm)
247 {
248   ip6_hop_by_hop_ioam_pot_main_t * hm = &ip6_hop_by_hop_ioam_pot_main;
249   clib_error_t * error;
250
251   if ((error = vlib_call_init_function (vm, ip6_hop_by_hop_ioam_init)))
252     return(error);
253
254   hm->vlib_main = vm;
255   hm->vnet_main = vnet_get_main();
256   memset(hm->counters, 0, sizeof(hm->counters));
257   
258   if (ip6_hbh_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT, ip6_hbh_ioam_proof_of_transit_handler,
259                               ip6_hbh_ioam_proof_of_transit_trace_handler) < 0)
260     return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT failed"));
261
262   if (ip6_hbh_add_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
263                                   sizeof(ioam_pot_option_t),
264                                   ip6_hop_by_hop_ioam_pot_rewrite_handler) < 0)
265     return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT for rewrite failed"));
266
267   if (ip6_hbh_pop_register_option(HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT,
268                                   ip6_hbh_ioam_proof_of_transit_pop_handler) < 0)
269     return (clib_error_create("registration of HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT POP failed"));
270
271   return (0);
272 }
273
274 VLIB_INIT_FUNCTION (ip6_hop_by_hop_ioam_pot_init);
275
276