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