2 * scv_util.h -- Service chain validation/Proof Of Transit Utility Header
4 * Copyright (c) 2015 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #ifndef include_vnet_scv_util_h
19 #define include_vnet_scv_util_h
21 #include <vnet/ip/ip6_hop_by_hop.h>
22 #define MAXDEGREE 1024
23 #define MAXTOKENLEN 128
24 #define debug_ioam debug_ioam_fn
25 #define MAX_SERVICE_NODES 10
26 /* Dont change this size 256. This is there across multiple components */
27 #define PATH_NAME_SIZE 256
29 /* Ring size. this should be same as the one in ODL. Do not change this
30 without change in ODL. */
31 #define MAX_SERVICE_PROFILES 16
36 * On any [service] node that participates in Service / Path verfication:
38 * Step 1: Initialize this library by calling scv_init()
39 * Step 2: Setup a Service chain validation profile that contains all the parameters needed to compute cumulative:
40 * Call these functions:
43 * scv_profile_set_bit_mask - To setup how large we want the numbers used in the computation and random number <= 64 bits
44 * Step 2a: For validator do this:
46 * Step 3a: At the initial Service node to generate Random number that will be read by all other nodes:
48 * Step 3b: At all service nodes including initial and verifier call this to compute cumulative:
49 * scv_update_cumulative
50 * Step 4: At the verifier:
55 typedef struct scv_profile_
69 // struct hlist_node my_hash_list; when this gets added to hashtbale
72 extern scv_profile *pow_profile;
73 extern u16 pow_profile_index;
74 extern u64 total_pkts_using_this_profile;
75 extern u8 chain_path_name[PATH_NAME_SIZE];
76 extern u16 invalid_profile_start_index;
77 extern u8 number_of_invalid_profiles;
78 extern f64 next_time_to_send;
79 extern u32 time_exponent;
82 * Initialize Service chain
84 void scv_init(u8 * path_name, u8 max, u8 indx);
87 * Get maximum number of profiles configured for this chain.
89 u8 scv_get_max_profiles(void);
92 * Find a SC profile by ID
94 scv_profile *scv_profile_find(u16 id);
96 static inline u16 scv_profile_get_id(scv_profile * profile)
100 return (profile->id);
105 /* setup and clean up profile */
106 void scv_profile_create(scv_profile * profile, u64 prime,
107 u64 poly2, u64 lpc, u64 secret_share, u64 validity);
109 * Setup profile as a validator
111 void scv_set_validator(scv_profile * profile, u64 key);
112 void scv_profile_cleanup(scv_profile * profile);
115 * Setup max bits to be used for random number generation
118 void scv_profile_set_bit_mask(scv_profile * profile, u16 bits);
121 * Given a random and cumulative compute the new cumulative for a given profile
123 u64 scv_update_cumulative(scv_profile * profile, u64 cumulative, u64 random);
126 * return True if the cumulative matches secret from a profile
128 u8 scv_validate(scv_profile * profile, u64 cumulative, u64 random);
131 * Utility function to get random number per pack
133 u64 scv_generate_random(scv_profile * profile);
135 int scv_profile_to_str(scv_profile * profile, char *buf, int n);
137 extern void clear_ioam_scv_profiles();
139 static inline u8 scv_get_profile_in_use(void)
141 return pow_profile_index;
145 void scv_notification_reset(u16 start_index_recvd, u8 num_profiles_recvd)
147 /* Profiles recevied w/o notn. Nothing to do. */
148 if (number_of_invalid_profiles == 0)
151 /* Most likely case. Got all requested profiles */
152 if (PREDICT_TRUE(num_profiles_recvd == number_of_invalid_profiles &&
153 start_index_recvd == invalid_profile_start_index))
155 number_of_invalid_profiles = 0;
156 invalid_profile_start_index = 0;
160 /* Received partial list */
161 if (num_profiles_recvd < number_of_invalid_profiles)
163 ASSERT(start_index_recvd == invalid_profile_start_index);
164 invalid_profile_start_index = (start_index_recvd + num_profiles_recvd)
165 % scv_get_max_profiles();
166 number_of_invalid_profiles -= num_profiles_recvd;
172 int __attribute__ ((weak)) scv_profile_renew(u8 * path_name,
173 u8 start_index, u8 num_profiles);
174 int __attribute__ ((weak)) scv_profile_refresh(u8 * path_name,
175 u8 start_index, u8 num_profiles);
177 static inline u8 scv_is_decap(scv_profile * p)
179 return (p->validator == 1);
182 static inline u16 scv_get_next_profile_id(vlib_main_t * vm, u16 id)
184 int next_id, num_profiles = 0;
188 max = scv_get_max_profiles();
192 /* Check for new profile in the ring buffer until a valid one. Exclude
193 checking for the one already in use. */
194 for (num_profiles = 0; num_profiles < max - 1; num_profiles++)
196 next_id = (next_id + 1) % max;
197 p = scv_profile_find(next_id);
198 if (p->validity != 0)
200 vlib_cli_output(vm, "Current id: %d, New id: %d\n", id, next_id);
209 scv_profile_invalidate(vlib_main_t * vm, ip6_hop_by_hop_ioam_main_t * hm,
212 scv_profile *p = scv_profile_find(id);
219 /* If there are alredy profiles waiting. If so, use existing start_index.
221 if (!number_of_invalid_profiles)
222 invalid_profile_start_index = id;
224 max = scv_get_max_profiles();
226 /* Check whether the id is already included in existing list */
227 if (!(id >= invalid_profile_start_index &&
228 id <= (invalid_profile_start_index +
229 number_of_invalid_profiles - 1) % max))
231 number_of_invalid_profiles++;
234 if (number_of_invalid_profiles > scv_get_max_profiles())
235 number_of_invalid_profiles = scv_get_max_profiles();
237 now = (f64) (((f64) hm->unix_time_0) +
238 (vlib_time_now(hm->vlib_main) - hm->vlib_time_0));
239 if (now <= next_time_to_send)
244 rc = scv_profile_renew(chain_path_name,
245 (u8) invalid_profile_start_index, number_of_invalid_profiles);
248 "Renew notification- id start:%d, num %d failed. rc: %d\n",
249 invalid_profile_start_index, number_of_invalid_profiles, rc);
252 "Renew notification- id start:%d num %d sent. \n",
253 invalid_profile_start_index, number_of_invalid_profiles);
258 /* Non encap node. Send refresh notification for now. Later set a
259 timer and if there is no profile even after the timeout send
260 refresh notification. */
261 rc = scv_profile_refresh(chain_path_name,
262 (u8) invalid_profile_start_index, number_of_invalid_profiles);
265 "Refresh notification- id start:%d, num %d failed. rc: %d\n",
266 invalid_profile_start_index, number_of_invalid_profiles, rc);
269 "Refresh notification- id start:%d num %d sent. \n",
270 invalid_profile_start_index, number_of_invalid_profiles);
272 next_time_to_send = now + time_exponent;
273 time_exponent <<= 1; /* backoff time is power of 2 seconds */