diff options
Diffstat (limited to 'src/plugins/lisp/lisp-cp/lisp_msg_serdes.c')
-rw-r--r-- | src/plugins/lisp/lisp-cp/lisp_msg_serdes.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/src/plugins/lisp/lisp-cp/lisp_msg_serdes.c b/src/plugins/lisp/lisp-cp/lisp_msg_serdes.c new file mode 100644 index 00000000000..14d90982d4f --- /dev/null +++ b/src/plugins/lisp/lisp-cp/lisp_msg_serdes.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <lisp/lisp-cp/lisp_msg_serdes.h> +#include <lisp/lisp-cp/packets.h> +#include <vppinfra/time.h> + +void *lisp_msg_put_gid (vlib_buffer_t * b, gid_address_t * gid); + +static void +lisp_msg_put_locators (vlib_buffer_t * b, locator_t * locators) +{ + locator_t *loc; + + vec_foreach (loc, locators) + { + u8 *p = vlib_buffer_put_uninit (b, sizeof (locator_hdr_t)); + clib_memset (p, 0, sizeof (locator_hdr_t)); + LOC_PRIORITY (p) = loc->priority; + LOC_MPRIORITY (p) = loc->mpriority; + LOC_WEIGHT (p) = loc->weight; + LOC_MWEIGHT (p) = loc->mweight; + LOC_LOCAL (p) = loc->local; + LOC_PROBED (p) = loc->probed ? 1 : 0; + LOC_REACHABLE (p) = loc->state ? 1 : 0; + lisp_msg_put_gid (b, &loc->address); + } +} + +static void +lisp_msg_put_mapping_record (vlib_buffer_t * b, mapping_t * record) +{ + mapping_record_hdr_t *p = + vlib_buffer_put_uninit (b, sizeof (mapping_record_hdr_t)); + gid_address_t *eid = &record->eid; + + clib_memset (p, 0, sizeof (*p)); + MAP_REC_EID_PLEN (p) = gid_address_len (eid); + MAP_REC_TTL (p) = clib_host_to_net_u32 (MAP_REGISTER_DEFAULT_TTL); + MAP_REC_AUTH (p) = record->authoritative ? 1 : 0; + MAP_REC_LOC_COUNT (p) = vec_len (record->locators); + + lisp_msg_put_gid (b, eid); + lisp_msg_put_locators (b, record->locators); +} + +static void +lisp_msg_put_mreg_records (vlib_buffer_t * b, mapping_t * records) +{ + u32 i; + for (i = 0; i < vec_len (records); i++) + lisp_msg_put_mapping_record (b, &records[i]); +} + +void * +lisp_msg_put_gid (vlib_buffer_t * b, gid_address_t * gid) +{ + u8 *p = 0; + if (!gid) + { + /* insert only src-eid-afi field set to 0 */ + p = vlib_buffer_put_uninit (b, sizeof (u16)); + *(u16 *) p = 0; + } + else + { + p = vlib_buffer_put_uninit (b, gid_address_size_to_put (gid)); + gid_address_put (p, gid); + } + return p; +} + +static void * +lisp_msg_put_itr_rlocs (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * rlocs, u8 * locs_put) +{ + u8 *bp, count = 0; + u32 i; + + bp = vlib_buffer_get_current (b); + for (i = 0; i < vec_len (rlocs); i++) + { + lisp_msg_put_gid (b, &rlocs[i]); + count++; + } + + *locs_put = count - 1; + return bp; +} + +void * +lisp_msg_put_eid_rec (vlib_buffer_t * b, gid_address_t * eid) +{ + eid_record_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (*h)); + + clib_memset (h, 0, sizeof (*h)); + EID_REC_MLEN (h) = gid_address_len (eid); + lisp_msg_put_gid (b, eid); + return h; +} + +u64 +nonce_build (u32 seed) +{ + u64 nonce; + u32 nonce_lower; + u32 nonce_upper; + struct timespec ts; + + /* Put nanosecond clock in lower 32-bits and put an XOR of the nanosecond + * clock with the second clock in the upper 32-bits. */ + syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts); + nonce_lower = ts.tv_nsec; + nonce_upper = ts.tv_sec ^ clib_host_to_net_u32 (nonce_lower); + + /* OR in a caller provided seed to the low-order 32-bits. */ + nonce_lower |= seed; + + /* Return 64-bit nonce. */ + nonce = nonce_upper; + nonce = (nonce << 32) | nonce_lower; + return nonce; +} + +void * +lisp_msg_put_map_reply (vlib_buffer_t * b, mapping_t * records, u64 nonce, + u8 probe_bit) +{ + map_reply_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (h[0])); + + clib_memset (h, 0, sizeof (h[0])); + MREP_TYPE (h) = LISP_MAP_REPLY; + MREP_NONCE (h) = nonce; + MREP_REC_COUNT (h) = 1; + MREP_RLOC_PROBE (h) = probe_bit; + + lisp_msg_put_mreg_records (b, records); + return h; +} + +void * +lisp_msg_put_map_register (vlib_buffer_t * b, mapping_t * records, + u8 want_map_notify, u16 auth_data_len, u64 * nonce, + u32 * msg_len) +{ + u8 *auth_data = 0; + + /* Basic header init */ + map_register_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (h[0])); + + clib_memset (h, 0, sizeof (h[0])); + MREG_TYPE (h) = LISP_MAP_REGISTER; + MREG_NONCE (h) = nonce_build (0); + MREG_WANT_MAP_NOTIFY (h) = want_map_notify ? 1 : 0; + MREG_REC_COUNT (h) = vec_len (records); + + auth_data = vlib_buffer_put_uninit (b, auth_data_len); + clib_memset (auth_data, 0, auth_data_len); + + /* Put map register records */ + lisp_msg_put_mreg_records (b, records); + + nonce[0] = MREG_NONCE (h); + msg_len[0] = vlib_buffer_get_tail (b) - (u8 *) h; + return h; +} + +void * +lisp_msg_put_mreq (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * seid, gid_address_t * deid, + gid_address_t * rlocs, u8 is_smr_invoked, + u8 rloc_probe_set, u64 * nonce) +{ + u8 loc_count = 0; + + /* Basic header init */ + map_request_hdr_t *h = vlib_buffer_put_uninit (b, sizeof (h[0])); + + clib_memset (h, 0, sizeof (h[0])); + MREQ_TYPE (h) = LISP_MAP_REQUEST; + MREQ_NONCE (h) = nonce_build (0); + MREQ_SMR_INVOKED (h) = is_smr_invoked ? 1 : 0; + MREQ_RLOC_PROBE (h) = rloc_probe_set ? 1 : 0; + + /* We're adding one eid record */ + increment_record_count (h); + + /* Fill source eid */ + lisp_msg_put_gid (b, seid); + + /* Put itr rlocs */ + lisp_msg_put_itr_rlocs (lcm, b, rlocs, &loc_count); + MREQ_ITR_RLOC_COUNT (h) = loc_count; + + /* Put eid record */ + lisp_msg_put_eid_rec (b, deid); + + nonce[0] = MREQ_NONCE (h); + return h; +} + +void * +lisp_msg_push_ecm (vlib_main_t * vm, vlib_buffer_t * b, int lp, int rp, + gid_address_t * la, gid_address_t * ra) +{ + ecm_hdr_t *h; + ip_address_t _src_ip, *src_ip = &_src_ip, _dst_ip, *dst_ip = &_dst_ip; + if (gid_address_type (la) != GID_ADDR_IP_PREFIX) + { + /* empty ip4 */ + clib_memset (src_ip, 0, sizeof (src_ip[0])); + clib_memset (dst_ip, 0, sizeof (dst_ip[0])); + } + else + { + src_ip = &gid_address_ip (la); + dst_ip = &gid_address_ip (ra); + } + + /* Push inner ip and udp */ + pkt_push_udp_and_ip (vm, b, lp, rp, src_ip, dst_ip, 0); + + /* Push lisp ecm hdr */ + h = pkt_push_ecm_hdr (b); + + return h; +} + +static u32 +msg_type_to_hdr_len (lisp_msg_type_e type) +{ + switch (type) + { + case LISP_MAP_REQUEST: + return (sizeof (map_request_hdr_t)); + case LISP_MAP_REPLY: + return (sizeof (map_reply_hdr_t)); + default: + return (0); + } +} + +void * +lisp_msg_pull_hdr (vlib_buffer_t * b, lisp_msg_type_e type) +{ + return vlib_buffer_pull (b, msg_type_to_hdr_len (type)); +} + +u32 +lisp_msg_parse_addr (vlib_buffer_t * b, gid_address_t * eid) +{ + u32 len; + clib_memset (eid, 0, sizeof (*eid)); + len = gid_address_parse (vlib_buffer_get_current (b), eid); + if (len != ~0) + vlib_buffer_pull (b, len); + return len; +} + +u32 +lisp_msg_parse_eid_rec (vlib_buffer_t * b, gid_address_t * eid) +{ + eid_record_hdr_t *h = vlib_buffer_get_current (b); + u32 len; + clib_memset (eid, 0, sizeof (*eid)); + len = gid_address_parse (EID_REC_ADDR (h), eid); + if (len == ~0) + return len; + + gid_address_ippref_len (eid) = EID_REC_MLEN (h); + vlib_buffer_pull (b, len + sizeof (eid_record_hdr_t)); + + return len + sizeof (eid_record_hdr_t); +} + +u32 +lisp_msg_parse_itr_rlocs (vlib_buffer_t * b, gid_address_t ** rlocs, + u8 rloc_count) +{ + gid_address_t tloc; + u32 i, len = 0, tlen = 0; + + //MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1 + for (i = 0; i < rloc_count; i++) + { + len = lisp_msg_parse_addr (b, &tloc); + if (len == ~0) + return len; + vec_add1 (*rlocs, tloc); + tlen += len; + } + return tlen; +} + +u32 +lisp_msg_parse_loc (vlib_buffer_t * b, locator_t * loc) +{ + int len; + + len = locator_parse (vlib_buffer_get_current (b), loc); + if (len == ~0) + return ~0; + + if (!vlib_buffer_has_space (b, sizeof (len))) + return ~0; + vlib_buffer_pull (b, len); + + return len; +} + +u32 +lisp_msg_parse_mapping_record (vlib_buffer_t * b, gid_address_t * eid, + locator_t ** locs, locator_t * probed_) +{ + void *h = 0, *loc_hdr = 0; + locator_t loc, *probed = 0; + int i = 0, len = 0, llen = 0; + + h = vlib_buffer_get_current (b); + if (!vlib_buffer_has_space (b, sizeof (mapping_record_hdr_t))) + return ~0; + + vlib_buffer_pull (b, sizeof (mapping_record_hdr_t)); + + clib_memset (eid, 0, sizeof (*eid)); + len = gid_address_parse (vlib_buffer_get_current (b), eid); + if (len == ~0) + return len; + + if (!vlib_buffer_has_space (b, sizeof (len))) + return ~0; + + vlib_buffer_pull (b, len); + if (GID_ADDR_IP_PREFIX == gid_address_type (eid)) + gid_address_ippref_len (eid) = MAP_REC_EID_PLEN (h); + + for (i = 0; i < MAP_REC_LOC_COUNT (h); i++) + { + loc_hdr = vlib_buffer_get_current (b); + + llen = lisp_msg_parse_loc (b, &loc); + if (llen == ~0) + return llen; + vec_add1 (*locs, loc); + len += llen; + + if (LOC_PROBED (loc_hdr)) + { + if (probed != 0) + clib_warning + ("Multiple locators probed! Probing only the first!"); + else + probed = &loc; + } + } + /* XXX */ + if (probed_ != 0 && probed) + *probed_ = *probed; + + return len + sizeof (map_reply_hdr_t); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |