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