Add unit test infrastructure for LISP protocol
[vpp.git] / vnet / vnet / 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 <vnet/lisp-cp/lisp_msg_serdes.h>
17 #include <vnet/lisp-cp/packets.h>
18 #include <vppinfra/time.h>
19
20 void *
21 lisp_msg_put_gid (vlib_buffer_t * b, gid_address_t * gid)
22 {
23   u8 * p = vlib_buffer_put_uninit (b, gid_address_size_to_put (gid));
24   gid_address_put (p, gid);
25   return p;
26 }
27
28 void *
29 lisp_msg_put_itr_rlocs (lisp_cp_main_t * lcm, vlib_buffer_t * b,
30                         ip_address_t * rlocs, u8 * locs_put)
31 {
32   u8 * p, * bp, count = 0;
33   u32 i;
34   ip_address_t * addr;
35
36   bp = vlib_buffer_get_current(b);
37   for (i = 0; i < vec_len(rlocs); i++)
38   {
39     addr = &rlocs[i];
40     switch (ip_addr_version(addr))
41     {
42     case IP4:
43       p = vlib_buffer_put_uninit (b, ip4_address_size_to_put());
44       ip4_address_put (p, &ip_addr_v4(addr));
45       count++;
46       break;
47     case IP6:
48       p = vlib_buffer_put_uninit (b, ip6_address_size_to_put());
49       ip6_address_put (p, &ip_addr_v6(addr));
50       count++;
51       break;
52     }
53   }
54
55   *locs_put = count-1;
56   return bp;
57 }
58
59 void *
60 lisp_msg_put_eid_rec (vlib_buffer_t * b, gid_address_t * eid)
61 {
62   eid_record_hdr_t * h = vlib_buffer_put_uninit (b, sizeof (*h));
63
64   memset(h, 0, sizeof (*h));
65   EID_REC_MLEN (h) = gid_address_len (eid);
66   lisp_msg_put_gid (b, eid);
67   return h;
68 }
69
70 u64
71 nonce_build (u32 seed)
72 {
73   u64 nonce;
74   u32 nonce_lower;
75   u32 nonce_upper;
76   struct timespec ts;
77
78   /* Put nanosecond clock in lower 32-bits and put an XOR of the nanosecond
79    * clock with the seond clock in the upper 32-bits. */
80   syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
81   nonce_lower = ts.tv_nsec;
82   nonce_upper = ts.tv_sec ^ clib_host_to_net_u32(nonce_lower);
83
84   /* OR in a caller provided seed to the low-order 32-bits. */
85   nonce_lower |= seed;
86
87   /* Return 64-bit nonce. */
88   nonce = nonce_upper;
89   nonce = (nonce << 32) | nonce_lower;
90   return nonce;
91 }
92
93 void *
94 lisp_msg_put_mreq (lisp_cp_main_t * lcm, vlib_buffer_t * b,
95                    gid_address_t * seid, gid_address_t * deid,
96                    ip_address_t * rlocs, u8 is_smr_invoked, u64 * nonce)
97 {
98   u8 loc_count = 0;
99
100   /* Basic header init */
101   map_request_hdr_t * h = vlib_buffer_put_uninit (b, sizeof(h[0]));
102
103   memset(h, 0, sizeof(h[0]));
104   MREQ_TYPE(h) = LISP_MAP_REQUEST;
105   MREQ_NONCE(h) = nonce_build(0);
106   MREQ_SMR_INVOKED(h) = is_smr_invoked ? 1 : 0;
107
108   /* We're adding one eid record */
109   increment_record_count (h);
110
111   /* Fill source eid */
112   lisp_msg_put_gid (b, seid);
113
114   /* Put itr rlocs */
115   lisp_msg_put_itr_rlocs(lcm, b, rlocs, &loc_count);
116   MREQ_ITR_RLOC_COUNT(h) = loc_count;
117
118   /* Put eid record */
119   lisp_msg_put_eid_rec(b, deid);
120
121   nonce[0] = MREQ_NONCE(h);
122   return h;
123 }
124
125 void *
126 lisp_msg_push_ecm (vlib_main_t * vm, vlib_buffer_t *b, int lp, int rp,
127                    gid_address_t *la, gid_address_t *ra)
128 {
129   ecm_hdr_t *h;
130   ASSERT(gid_address_type(la) == IP_PREFIX);
131
132   /* Push inner ip and udp */
133   pkt_push_udp_and_ip (vm, b, lp, rp, &gid_address_ip(la),
134                               &gid_address_ip(ra));
135
136   /* Push lisp ecm hdr */
137   h = pkt_push_ecm_hdr (b);
138
139   return h;
140 }
141
142 static u32
143 msg_type_to_hdr_len (lisp_msg_type_e type)
144 {
145   switch (type)
146     {
147     case LISP_MAP_REQUEST:
148       return (sizeof(map_request_hdr_t));
149     case LISP_MAP_REPLY:
150       return (sizeof(map_reply_hdr_t));
151     default:
152       return (0);
153     }
154 }
155
156 void *
157 lisp_msg_pull_hdr (vlib_buffer_t * b, lisp_msg_type_e type)
158 {
159   return vlib_buffer_pull (b, msg_type_to_hdr_len (type));
160 }
161
162 u32
163 lisp_msg_parse_addr (vlib_buffer_t * b, gid_address_t * eid)
164 {
165   u32 len = gid_address_parse (vlib_buffer_get_current (b), eid);
166   if (len != ~0)
167     vlib_buffer_pull (b, len);
168   return len;
169 }
170
171 u32
172 lisp_msg_parse_eid_rec (vlib_buffer_t * b, gid_address_t * eid)
173 {
174   eid_record_hdr_t * h = vlib_buffer_get_current (b);
175   u32 len = gid_address_parse (EID_REC_ADDR(h), eid);
176   if (len == ~0)
177     return len;
178
179   gid_address_ippref_len(eid) = EID_REC_MLEN(h);
180   vlib_buffer_pull (b, len + sizeof(eid_record_hdr_t));
181
182   return len + sizeof(eid_record_hdr_t);
183 }
184
185 u32
186 lisp_msg_parse_itr_rlocs (vlib_buffer_t * b, gid_address_t ** rlocs,
187                           u8 rloc_count)
188 {
189   gid_address_t tloc;
190   u32 i, len = 0, tlen = 0;
191
192   //MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1
193   for (i = 0; i < rloc_count; i++)
194     {
195       len = lisp_msg_parse_addr (b, &tloc);
196       if (len == ~0)
197         return len;
198       vec_add1(*rlocs, tloc);
199       tlen += len;
200     }
201   return tlen;
202 }
203
204 u32
205 lisp_msg_parse_loc (vlib_buffer_t * b, locator_t * loc)
206 {
207   int len;
208
209   len = locator_parse (vlib_buffer_get_current (b), loc);
210   if (len == ~0)
211       return ~0;
212
213   vlib_buffer_pull (b, len);
214
215   return len;
216 }
217
218 u32
219 lisp_msg_parse_mapping_record (vlib_buffer_t * b, gid_address_t * eid,
220                                locator_t ** locs, locator_t * probed_)
221 {
222   void * h = 0, * loc_hdr = 0;
223   locator_t loc, * probed = 0;
224   int i = 0, len = 0, llen = 0;
225
226   h = vlib_buffer_get_current (b);
227   vlib_buffer_pull (b, sizeof(mapping_record_hdr_t));
228
229   len = gid_address_parse (vlib_buffer_get_current (b), eid);
230   if (len == ~0)
231     return len;
232
233   vlib_buffer_pull (b, len);
234   gid_address_ippref_len(eid) = MAP_REC_EID_PLEN(h);
235
236   for (i = 0; i < MAP_REC_LOC_COUNT(h); i++)
237     {
238       loc_hdr = vlib_buffer_get_current (b);
239
240       llen = lisp_msg_parse_loc (b, &loc);
241       if (llen == ~0)
242         return llen;
243       vec_add1(*locs, loc);
244       len += llen;
245
246       if (LOC_PROBED(loc_hdr))
247         {
248           if (probed != 0)
249             clib_warning("Multiple locators probed! Probing only the first!");
250           else
251             probed = &loc;
252         }
253     }
254   /* XXX */
255   if (probed_ != 0 && probed)
256     *probed_ = *probed;
257
258   return len + sizeof(map_reply_hdr_t);
259 }