Add support for LCAF Instance ID
[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 = gid_address_parse (vlib_buffer_get_current (b), eid);
153   if (len != ~0)
154     vlib_buffer_pull (b, len);
155   return len;
156 }
157
158 u32
159 lisp_msg_parse_eid_rec (vlib_buffer_t * b, gid_address_t * eid)
160 {
161   eid_record_hdr_t * h = vlib_buffer_get_current (b);
162   u32 len = gid_address_parse (EID_REC_ADDR(h), eid);
163   if (len == ~0)
164     return len;
165
166   gid_address_ippref_len(eid) = EID_REC_MLEN(h);
167   vlib_buffer_pull (b, len + sizeof(eid_record_hdr_t));
168
169   return len + sizeof(eid_record_hdr_t);
170 }
171
172 u32
173 lisp_msg_parse_itr_rlocs (vlib_buffer_t * b, gid_address_t ** rlocs,
174                           u8 rloc_count)
175 {
176   gid_address_t tloc;
177   u32 i, len = 0, tlen = 0;
178
179   //MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1
180   for (i = 0; i < rloc_count; i++)
181     {
182       len = lisp_msg_parse_addr (b, &tloc);
183       if (len == ~0)
184         return len;
185       vec_add1(*rlocs, tloc);
186       tlen += len;
187     }
188   return tlen;
189 }
190
191 u32
192 lisp_msg_parse_loc (vlib_buffer_t * b, locator_t * loc)
193 {
194   int len;
195
196   len = locator_parse (vlib_buffer_get_current (b), loc);
197   if (len == ~0)
198       return ~0;
199
200   vlib_buffer_pull (b, len);
201
202   return len;
203 }
204
205 u32
206 lisp_msg_parse_mapping_record (vlib_buffer_t * b, gid_address_t * eid,
207                                locator_t ** locs, locator_t * probed_)
208 {
209   void * h = 0, * loc_hdr = 0;
210   locator_t loc, * probed = 0;
211   int i = 0, len = 0, llen = 0;
212
213   h = vlib_buffer_get_current (b);
214   vlib_buffer_pull (b, sizeof(mapping_record_hdr_t));
215
216   len = gid_address_parse (vlib_buffer_get_current (b), eid);
217   if (len == ~0)
218     return len;
219
220   vlib_buffer_pull (b, len);
221   gid_address_ippref_len(eid) = MAP_REC_EID_PLEN(h);
222
223   for (i = 0; i < MAP_REC_LOC_COUNT(h); i++)
224     {
225       loc_hdr = vlib_buffer_get_current (b);
226
227       llen = lisp_msg_parse_loc (b, &loc);
228       if (llen == ~0)
229         return llen;
230       vec_add1(*locs, loc);
231       len += llen;
232
233       if (LOC_PROBED(loc_hdr))
234         {
235           if (probed != 0)
236             clib_warning("Multiple locators probed! Probing only the first!");
237           else
238             probed = &loc;
239         }
240     }
241   /* XXX */
242   if (probed_ != 0 && probed)
243     *probed_ = *probed;
244
245   return len + sizeof(map_reply_hdr_t);
246 }