session: fix ho cleanup on forced reset
[vpp.git] / src / plugins / lisp / lisp-cp / lisp_msg_serdes.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 #include <lisp/lisp-cp/lisp_msg_serdes.h>
17 #include <lisp/lisp-cp/packets.h>
18 #include <vppinfra/time.h>
19
20 void *lisp_msg_put_gid (vlib_buffer_t * b, gid_address_t * gid);
21
22 static void
23 lisp_msg_put_locators (vlib_buffer_t * b, locator_t * locators)
24 {
25   locator_t *loc;
26
27   vec_foreach (loc, locators)
28   {
29     u8 *p = vlib_buffer_put_uninit (b, sizeof (locator_hdr_t));
30     clib_memset (p, 0, sizeof (locator_hdr_t));
31     LOC_PRIORITY (p) = loc->priority;
32     LOC_MPRIORITY (p) = loc->mpriority;
33     LOC_WEIGHT (p) = loc->weight;
34     LOC_MWEIGHT (p) = loc->mweight;
35     LOC_LOCAL (p) = loc->local;
36     LOC_PROBED (p) = loc->probed ? 1 : 0;
37     LOC_REACHABLE (p) = loc->state ? 1 : 0;
38     lisp_msg_put_gid (b, &loc->address);
39   }
40 }
41
42 static void
43 lisp_msg_put_mapping_record (vlib_buffer_t * b, mapping_t * record)
44 {
45   mapping_record_hdr_t *p =
46     vlib_buffer_put_uninit (b, sizeof (mapping_record_hdr_t));
47   gid_address_t *eid = &record->eid;
48
49   clib_memset (p, 0, sizeof (*p));
50   MAP_REC_EID_PLEN (p) = gid_address_len (eid);
51   MAP_REC_TTL (p) = clib_host_to_net_u32 (MAP_REGISTER_DEFAULT_TTL);
52   MAP_REC_AUTH (p) = record->authoritative ? 1 : 0;
53   MAP_REC_LOC_COUNT (p) = vec_len (record->locators);
54
55   lisp_msg_put_gid (b, eid);
56   lisp_msg_put_locators (b, record->locators);
57 }
58
59 static void
60 lisp_msg_put_mreg_records (vlib_buffer_t * b, mapping_t * records)
61 {
62   u32 i;
63   for (i = 0; i < vec_len (records); i++)
64     lisp_msg_put_mapping_record (b, &records[i]);
65 }
66
67 void *
68 lisp_msg_put_gid (vlib_buffer_t * b, gid_address_t * gid)
69 {
70   u8 *p = 0;
71   if (!gid)
72     {
73       /* insert only src-eid-afi field set to 0 */
74       p = vlib_buffer_put_uninit (b, sizeof (u16));
75       *(u16 *) p = 0;
76     }
77   else
78     {
79       p = vlib_buffer_put_uninit (b, gid_address_size_to_put (gid));
80       gid_address_put (p, gid);
81     }
82   return p;
83 }
84
85 static void *
86 lisp_msg_put_itr_rlocs (lisp_cp_main_t * lcm, vlib_buffer_t * b,
87                         gid_address_t * rlocs, u8 * locs_put)
88 {
89   u8 *bp, count = 0;
90   u32 i;
91
92   bp = vlib_buffer_get_current (b);
93   for (i = 0; i < vec_len (rlocs); i++)
94     {
95       lisp_msg_put_gid (b, &rlocs[i]);
96       count++;
97     }
98
99   *locs_put = count - 1;
100   return bp;
101 }
102
103 void *
104 lisp_msg_put_eid_rec (vlib_buffer_t * b, gid_address_t * eid)
105 {
106   eid_record_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (*h));
107
108   clib_memset (h, 0, sizeof (*h));
109   EID_REC_MLEN (h) = gid_address_len (eid);
110   lisp_msg_put_gid (b, eid);
111   return h;
112 }
113
114 u64
115 nonce_build (u32 seed)
116 {
117   u64 nonce;
118   u32 nonce_lower;
119   u32 nonce_upper;
120   struct timespec ts;
121
122   /* Put nanosecond clock in lower 32-bits and put an XOR of the nanosecond
123    * clock with the second clock in the upper 32-bits. */
124   syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
125   nonce_lower = ts.tv_nsec;
126   nonce_upper = ts.tv_sec ^ clib_host_to_net_u32 (nonce_lower);
127
128   /* OR in a caller provided seed to the low-order 32-bits. */
129   nonce_lower |= seed;
130
131   /* Return 64-bit nonce. */
132   nonce = nonce_upper;
133   nonce = (nonce << 32) | nonce_lower;
134   return nonce;
135 }
136
137 void *
138 lisp_msg_put_map_reply (vlib_buffer_t * b, mapping_t * records, u64 nonce,
139                         u8 probe_bit)
140 {
141   map_reply_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (h[0]));
142
143   clib_memset (h, 0, sizeof (h[0]));
144   MREP_TYPE (h) = LISP_MAP_REPLY;
145   MREP_NONCE (h) = nonce;
146   MREP_REC_COUNT (h) = 1;
147   MREP_RLOC_PROBE (h) = probe_bit;
148
149   lisp_msg_put_mreg_records (b, records);
150   return h;
151 }
152
153 void *
154 lisp_msg_put_map_register (vlib_buffer_t * b, mapping_t * records,
155                            u8 want_map_notify, u16 auth_data_len, u64 * nonce,
156                            u32 * msg_len)
157 {
158   u8 *auth_data = 0;
159
160   /* Basic header init */
161   map_register_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (h[0]));
162
163   clib_memset (h, 0, sizeof (h[0]));
164   MREG_TYPE (h) = LISP_MAP_REGISTER;
165   MREG_NONCE (h) = nonce_build (0);
166   MREG_WANT_MAP_NOTIFY (h) = want_map_notify ? 1 : 0;
167   MREG_REC_COUNT (h) = vec_len (records);
168
169   auth_data = vlib_buffer_put_uninit (b, auth_data_len);
170   clib_memset (auth_data, 0, auth_data_len);
171
172   /* Put map register records */
173   lisp_msg_put_mreg_records (b, records);
174
175   nonce[0] = MREG_NONCE (h);
176   msg_len[0] = vlib_buffer_get_tail (b) - (u8 *) h;
177   return h;
178 }
179
180 void *
181 lisp_msg_put_mreq (lisp_cp_main_t * lcm, vlib_buffer_t * b,
182                    gid_address_t * seid, gid_address_t * deid,
183                    gid_address_t * rlocs, u8 is_smr_invoked,
184                    u8 rloc_probe_set, u64 * nonce)
185 {
186   u8 loc_count = 0;
187
188   /* Basic header init */
189   map_request_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (h[0]));
190
191   clib_memset (h, 0, sizeof (h[0]));
192   MREQ_TYPE (h) = LISP_MAP_REQUEST;
193   MREQ_NONCE (h) = nonce_build (0);
194   MREQ_SMR_INVOKED (h) = is_smr_invoked ? 1 : 0;
195   MREQ_RLOC_PROBE (h) = rloc_probe_set ? 1 : 0;
196
197   /* We're adding one eid record */
198   increment_record_count (h);
199
200   /* Fill source eid */
201   lisp_msg_put_gid (b, seid);
202
203   /* Put itr rlocs */
204   lisp_msg_put_itr_rlocs (lcm, b, rlocs, &loc_count);
205   MREQ_ITR_RLOC_COUNT (h) = loc_count;
206
207   /* Put eid record */
208   lisp_msg_put_eid_rec (b, deid);
209
210   nonce[0] = MREQ_NONCE (h);
211   return h;
212 }
213
214 void *
215 lisp_msg_push_ecm (vlib_main_t * vm, vlib_buffer_t * b, int lp, int rp,
216                    gid_address_t * la, gid_address_t * ra)
217 {
218   ecm_hdr_t *h;
219   ip_address_t _src_ip, *src_ip = &_src_ip, _dst_ip, *dst_ip = &_dst_ip;
220   if (gid_address_type (la) != GID_ADDR_IP_PREFIX)
221     {
222       /* empty ip4 */
223       clib_memset (src_ip, 0, sizeof (src_ip[0]));
224       clib_memset (dst_ip, 0, sizeof (dst_ip[0]));
225     }
226   else
227     {
228       src_ip = &gid_address_ip (la);
229       dst_ip = &gid_address_ip (ra);
230     }
231
232   /* Push inner ip and udp */
233   pkt_push_udp_and_ip (vm, b, lp, rp, src_ip, dst_ip, 0);
234
235   /* Push lisp ecm hdr */
236   h = pkt_push_ecm_hdr (b);
237
238   return h;
239 }
240
241 static u32
242 msg_type_to_hdr_len (lisp_msg_type_e type)
243 {
244   switch (type)
245     {
246     case LISP_MAP_REQUEST:
247       return (sizeof (map_request_hdr_t));
248     case LISP_MAP_REPLY:
249       return (sizeof (map_reply_hdr_t));
250     default:
251       return (0);
252     }
253 }
254
255 void *
256 lisp_msg_pull_hdr (vlib_buffer_t * b, lisp_msg_type_e type)
257 {
258   return vlib_buffer_pull (b, msg_type_to_hdr_len (type));
259 }
260
261 u32
262 lisp_msg_parse_addr (vlib_buffer_t * b, gid_address_t * eid)
263 {
264   u32 len;
265   clib_memset (eid, 0, sizeof (*eid));
266   len = gid_address_parse (vlib_buffer_get_current (b), eid);
267   if ((len != ~0) && vlib_buffer_pull (b, len))
268     {
269       return len;
270     }
271   else
272     {
273       return ~0;
274     }
275 }
276
277 u32
278 lisp_msg_parse_eid_rec (vlib_buffer_t * b, gid_address_t * eid)
279 {
280   eid_record_hdr_t *h = vlib_buffer_get_current (b);
281   u32 len;
282   clib_memset (eid, 0, sizeof (*eid));
283   len = gid_address_parse (EID_REC_ADDR (h), eid);
284   if (len == ~0)
285     return len;
286
287   gid_address_ippref_len (eid) = EID_REC_MLEN (h);
288   if (!vlib_buffer_pull (b, len + sizeof (eid_record_hdr_t)))
289     {
290       return ~0;
291     }
292
293   return len + sizeof (eid_record_hdr_t);
294 }
295
296 u32
297 lisp_msg_parse_itr_rlocs (vlib_buffer_t * b, gid_address_t ** rlocs,
298                           u8 rloc_count)
299 {
300   gid_address_t tloc;
301   u32 i, len = 0, tlen = 0;
302
303   //MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1
304   for (i = 0; i < rloc_count; i++)
305     {
306       len = lisp_msg_parse_addr (b, &tloc);
307       if (len == ~0)
308         return len;
309       vec_add1 (*rlocs, tloc);
310       tlen += len;
311     }
312   return tlen;
313 }
314
315 u32
316 lisp_msg_parse_loc (vlib_buffer_t * b, locator_t * loc)
317 {
318   int len;
319
320   len = locator_parse (vlib_buffer_get_current (b), loc);
321   if (len == ~0)
322     return ~0;
323
324   if (!vlib_buffer_has_space (b, sizeof (len)))
325     return ~0;
326   vlib_buffer_pull (b, len);
327
328   return len;
329 }
330
331 u32
332 lisp_msg_parse_mapping_record (vlib_buffer_t * b, gid_address_t * eid,
333                                locator_t ** locs, locator_t * probed_)
334 {
335   void *h = 0, *loc_hdr = 0;
336   locator_t loc, *probed = 0;
337   int i = 0, len = 0, llen = 0;
338
339   h = vlib_buffer_get_current (b);
340   if (!vlib_buffer_has_space (b, sizeof (mapping_record_hdr_t)))
341     return ~0;
342
343   vlib_buffer_pull (b, sizeof (mapping_record_hdr_t));
344
345   clib_memset (eid, 0, sizeof (*eid));
346   len = gid_address_parse (vlib_buffer_get_current (b), eid);
347   if (len == ~0)
348     return len;
349
350   if (!vlib_buffer_has_space (b, sizeof (len)))
351     return ~0;
352
353   vlib_buffer_pull (b, len);
354   if (GID_ADDR_IP_PREFIX == gid_address_type (eid))
355     gid_address_ippref_len (eid) = MAP_REC_EID_PLEN (h);
356
357   for (i = 0; i < MAP_REC_LOC_COUNT (h); i++)
358     {
359       loc_hdr = vlib_buffer_get_current (b);
360
361       llen = lisp_msg_parse_loc (b, &loc);
362       if (llen == ~0)
363         return llen;
364       vec_add1 (*locs, loc);
365       len += llen;
366
367       if (LOC_PROBED (loc_hdr))
368         {
369           if (probed != 0)
370             clib_warning
371               ("Multiple locators probed! Probing only the first!");
372           else
373             probed = &loc;
374         }
375     }
376   /* XXX */
377   if (probed_ != 0 && probed)
378     *probed_ = *probed;
379
380   return len + sizeof (map_reply_hdr_t);
381 }
382
383 /*
384  * fd.io coding-style-patch-verification: ON
385  *
386  * Local Variables:
387  * eval: (c-set-style "gnu")
388  * End:
389  */