summaryrefslogtreecommitdiffstats
path: root/src/vlibmemory
AgeCommit message (Collapse)AuthorFilesLines
2019-01-23Initialize gc_mark_timestamp to zero to avoid garbage values.Brian Nesbitt1-0/+1
Change-Id: Ib3f030e906da9828fdad27e19b9efb0c349b0734 Signed-off-by: Brian Nesbitt <brian.nesbitt@owmobility.com>
2019-01-05socket API: Use pool index instead of handle in sock_delete handlerOle Troan1-1/+1
The socket API used the socket index handle directly in the sock_delete handler, resulting in "unknown client id" warnings, and a failure in return for socket clients. Change-Id: Ia69f740ce0f834cd9b62b7157243a1f42bcad765 Signed-off-by: Ole Troan <ot@cisco.com>
2019-01-02Fixes for buliding for 32bit targets:David Johnson1-4/+4
* u32/u64/uword mismatches * pointer-to-int fixes * printf formatting issues * issues with incorrect "ULL" and related suffixes * structure alignment and padding issues Change-Id: I70b989007758755fe8211c074f651150680f60b4 Signed-off-by: David Johnson <davijoh3@cisco.com>
2018-12-31binary api clients: wait for vpp to startDave Barach1-0/+29
Change-Id: I740a7423327b724e88fdfa35d90cb1285e9f9746 Signed-off-by: Dave Barach <dbarach@cisco.com>
2018-12-22bapi/vat: fix socket transport for vatFlorin Coras1-2/+9
Change-Id: I8e39df129f80c8d3d73181fc5d3ac60ae382a6b6 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-12-05bapi: add options to have vpp cleanup client registrationFlorin Coras4-20/+28
A client can send a memclnt delete message and ask vpp to cleanup the shared memory queue. Obviously, in this case no delete reply is sent back to the client. Change-Id: I9c8375093f8607680ad498a6bed0690ba02a7c3b Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-12-03vcl: handle worker process exitFlorin Coras2-7/+15
Change-Id: Ife05d25fd736ae3064f01e974e5aecc5b48de924 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-12-01Delete shared memory segment files when vpp startsDave Barach1-0/+22
Should have been done this way years ago. My bad. Change-Id: Ic7bf937fb6c4dc5c1b6ae64f2ecf8608b62e7039 Signed-off-by: Dave Barach <dave@barachs.net>
2018-11-18Complain if a client binary API queue is fullDave Barach1-0/+8
Definitely indicates a client binary API queue handling issue. We can't simply turf the message, or we'll end up with a more subtle derivative misbehavior. Change-Id: I6363fda1430b0a9ec33ad69badc1e0072fe20fa8 Signed-off-by: Dave Barach <dave@barachs.net>
2018-11-14Remove c-11 memcpy checks from perf-critical codeDave Barach3-5/+5
Change-Id: Id4f37f5d4a03160572954a416efa1ef9b3d79ad1 Signed-off-by: Dave Barach <dave@barachs.net>
2018-11-13vlib rename vlib_frame_args(...) to vlib_frame_scalar_args(..)Damjan Marion1-2/+2
Typically we have scalar_size == 0, so it doesn't matter but vlib_frame_args was providing pointer to scalar frame data, not vector data. To avoid future confusion function is renamed to vlib_frame_scalar_args(...) Change-Id: I48b75523b46d487feea24f3f3cb10c528dde516f Signed-off-by: Damjan Marion <damarion@cisco.com>
2018-11-01Move RPC calls off the binary API input queueDave Barach3-29/+50
Change-Id: I2476e3e916a42b41d1e66bfc1ec4f8c4264c1720 Signed-off-by: Dave Barach <dbarach@cisco.com>
2018-10-25Revert "Keep RPC traffic off the shared-memory API queue"Florin Coras3-38/+29
This reverts commit 71615399e194847d7833b744caedab9b841733e5. There seems to be an issue with ARPs when running with multiple workers. Change-Id: Iaa68081512362945a9caf24dcb8d70fc7c5b75df Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-10-24Keep RPC traffic off the shared-memory API queueDave Barach3-29/+38
Change-Id: Ib5c346641463768cf33eaf8cb5fab5b63171398d Signed-off-by: Dave Barach <dave@barachs.net>
2018-10-23c11 safe string handling supportDave Barach7-30/+30
Change-Id: Ied34720ca5a6e6e717eea4e86003e854031b6eab Signed-off-by: Dave Barach <dave@barachs.net>
2018-10-03sock api: fix registrations and client readsFlorin Coras5-28/+69
- When clients connect, instead of returing registration indicies return handles. By convention socket registrations will have the MSB set to 1. This makes it easy to distinguish them from shm registrations. - Fix client reads to allow for messages larger than 4kB (needed for the creat reply wherein the message table is provided). Change-Id: I7bc0a072d066dffbf2e3ad9ba3ed50291231af9d Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-10-02PAPI: Use UNIX domain sockets instead of shared memoryOle Troan5-39/+94
Adds support for running the API purely across Unix domain sockets. Usage: vpp = VPP(use_socket=True) Change-Id: Iafc1301e03dd3edc3f4d702dd6c0b98d3b50b69e Signed-off-by: Ole Troan <ot@cisco.com>
2018-09-19socket api: do not delay sending of messagesFlorin Coras2-64/+35
Instead of relying on main epoll loop to send messages, try to send as soon as possible. Change-Id: I27c0b4076f3599ad6e968df4746881a6717d4299 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-09-11remove libvlib from libvlibmemoryclient libsMatthew Smith1-1/+1
On CentOS 7, having libvlibmemoryclient link libvlib causes a SEGV when a program or library is run which links against libvlibmemoryclient and dlopen() is called. This is because dlopen() executes any functions with __attribute((constructor)) set. The VLIB_CLI_COMMAND macro creates CLI registration functions that have this attribute set. So CLI registration functions end up being run by applications which are clients of the VPP API. This doesn't occur on ubuntu 16.04, because ld seems to omit shared libraries that were listed on the command line if they are not used to resolve any symbols. Removing the link to libvlib on vlibmemoryclient to fix this problem results in another problem. Tests of libvcl_preload fail when running 'make test'. This happens because libvcl_preload calls dlopen but does not link against libdl. When libvlibmemoryclient had libvlib linked, these errors did not occur since libvlib links libdl. Adjusted the build of libvcl_preload to explicitly link libdl. Change-Id: I271ba2f9226ce1602e1f6c1525f3b093bb0345ed Signed-off-by: Matthew Smith <mgsmith@netgate.com>
2018-08-26cmake: add add_vpp_library and add_vpp_executable macrosDamjan Marion1-14/+13
Change-Id: I1382021a6f616571b4b3243ba8c8999239d10815 Signed-off-by: Damjan Marion <damarion@cisco.com>
2018-08-25cmake: add more headers to the install listDamjan Marion1-0/+11
Change-Id: I3a0f48381232fcac1727034aa6d2504a8d1edb04 Signed-off-by: Damjan Marion <damarion@cisco.com>
2018-08-20CMake: generate .json from .api filesNeale Ranns1-2/+3
Change-Id: Ic18aa0fb42a72b5e0ebbfbebdefc7582cb46b5ea Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
2018-08-17CMake as an alternative to autotools (experimental)Damjan Marion1-0/+41
Change-Id: Ibc59323e849810531dd0963e85493efad3b86857 Signed-off-by: Damjan Marion <damarion@cisco.com>
2018-08-17vlibapi: validate private segment rotor prior to useFlorin Coras1-1/+1
If the dead client scan removes the rotor position we're about to check next, we end up outside the private registration pool's bounds. Change-Id: If4e715593deeac4c06ae6b3fededc1965b042094 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-15Remove client_index field from replies in APIOndrej Fabry1-2/+0
- replies should not need to contain client_index since it is used to identify sender of requests to VPP Change-Id: Iece3853b3f020054ee1652b149d0cf8d9580db4e Signed-off-by: Ondrej Fabry <ofabry@cisco.com>
2018-08-10vcl: support for eventfd mq signalingFlorin Coras1-2/+2
- support eventfd based mq signaling. Based on configuration, vcl epoll/select can use either condvars or epoll on mq eventfds. - add vcl support for memfd segments - vpp explicitly registers cut-through segments with apps/vcl - if using eventfd, make ldp allow one call to libc_epoll_create. Needed for the message queue epfd - update svm_queue_t to allow blocking calls with eventfd signaling. Change-Id: I064151ac370bbe29bb16c968bf4e3659c8286bea Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-09Fix "Old Style VLA" build warningsJuraj Sloboda1-2/+3
Change-Id: I8d42f6ed58ec34298d41edcb3d783e7e9ded3eec Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
2018-08-07api: compute msg table for private registrationsFlorin Coras1-2/+7
Change-Id: Ibaa236c09c2eeea72ee8a8cc603d407217b4af23 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-04socket api: multiple fds in one msgFlorin Coras5-20/+22
Change-Id: I77a6e092a42290eed7201ad4a62e0d00ef997d2b Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-08-03svm: add support for eventfd signaling to queueFlorin Coras2-11/+9
Support the use of eventfds to signal queue updates between consumer and producer pairs. Change-Id: Idb6133be2b731fff78ed520daf9d2e0399642aab Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-07-05VPP-1335 vapi crash when memclnt_keepalive receivedKlement Sekera1-4/+4
Change-Id: If33a7cc6c76147fd3ea9d8118370e7a508819b81 Signed-off-by: Klement Sekera <ksekera@cisco.com>
2018-06-27gcc8 and Wstringop-truncationMarco Varlese1-4/+6
gcc8 introduced a new warning (Wstringop-truncation) which in our case is being treated as error. Disabling the warning globally might introduce bugs related to string truncation which are not desired by the developer (e.g. bug). Instead, this patch disables the warning only for those occurences which have been verified to be non-bugs but the desired behaviour as per developer will. Change-Id: I0f04ff6b4fad44061e80a65af633fd7e0148a0c5 Signed-off-by: Marco Varlese <marco.varlese@suse.com>
2018-06-26Fix api trace replay of handler to pass vm parameterJohn Lo1-2/+2
I suppose most API handlers do not use vm parameter so it has not been a problem so far. Now vl_api_vnet_set_ip6_ethernet_neighbor() was crashing when called from api trace replay because either of ip_neighbor_add_del_t_handler() vnet_arp_set_ip4_over_ethernet() need vm to be correct when it calls vlin_time_now() to update the neighbor timestamp. Change-Id: Iffb2084a7c90f92c4b86b339ea11800dd41117eb Signed-off-by: John Lo <loj@cisco.com>
2018-06-14Use __attribute__((weak)) references where necessaryDave Barach1-5/+1
It should be possible to use vlib without the vlibmemory library, etc. Change-Id: Ic2316b93d7dbb728fb4ff42a3ca8b0d747c9425e Signed-off-by: Dave Barach <dave@barachs.net>
2018-06-08export counters in a memfd segmentDave Barach2-6/+16
also export per-node error counters directory entries implement object types Change-Id: I8ce8e0a754e1be9de895c44ed9be6533b4ecef0f Signed-off-by: Dave Barach <dave@barachs.net>
2018-06-05VPP API: Memory traceOle Troan2-16/+28
if you plan to put a hash into shared memory, the key sum and key equal functions MUST be set to constants such as KEY_FUNC_STRING, KEY_FUNC_MEM, etc. -lvppinfra is PIC, which means that the process which set up the hash won't have the same idea where the key sum and key compare functions live in other processes. Change-Id: Ib3b5963a0d2fb467b91e1f16274df66ac74009e9 Signed-off-by: Ole Troan <ot@cisco.com> Signed-off-by: Dave Barach <dave@barachs.net> Signed-off-by: Ole Troan <ot@cisco.com>
2018-05-10Remove the historical memfd api segment bootstrapDave Barach2-88/+28
Clean up default and vpp_api_test custom private api segment allocator ring configurations. Change-Id: I145b6d64ba0a6315b5ccb07909c8256eeb772146 Signed-off-by: Dave Barach <dave@barachs.net>
2018-04-18typo fix: UNKOWN -> UNKNOWNAndrey "Zed" Zaikin1-1/+1
Change-Id: I008a4d7ad7160d1f07e7ceef712a5318a9368308 Signed-off-by: Andrey "Zed" Zaikin <zed.0xff@gmail.com>
2018-03-06API: Add service definitions for events and singleton messages (second attempt)Marek Gradzki1-0/+10
Based on https://gerrit.fd.io/r/#/c/10920/ Updates service definition in stats.api with correct reply message names. Change-Id: I3282bee5304e667e23bc1fab3f43d967a50d880d Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
2018-03-05Revert "API: Add service definitions for events and singleton messages."Ole Trøan1-10/+0
This reverts commit f7b7fa53b7eaec81d8c00c1023fb7d01f1f9761f. Change-Id: I87496342943248e94f01ada31459f387c0a3a610 Signed-off-by: Ole Troan <ot@cisco.com>
2018-03-05API: Add service definitions for events and singleton messages.Ole Troan1-0/+10
Change-Id: I7de987c30b263d43521e6280c5273f30b5f6e11c Signed-off-by: Ole Troan <ot@cisco.com>
2018-02-02vlmemory/svm: fix client detach from svm regionFlorin Coras4-8/+23
Clients cannot know at svm region detach time if the shm backing files have been recreated (e.g., if vpp restarts) and therefore should not try to unlink them. Otherwise, terminating clients attached to previous instantiations of a re-allocated region end up making the new instance un-mappable by removing its backing file. Change-Id: Idcd0cab776e63fd75b821bc9f0fac58217b9ccbe Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-01-25session: add support for memfd segmentsFlorin Coras11-86/+219
- update segment manager and session api to work with both flavors of ssvm segments - added generic ssvm slave/master init and del functions - cleanup/refactor tcp_echo - fixed uses of svm fifo pool as vector Change-Id: Ieee8b163faa407da6e77e657a2322de213a9d2a0 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-01-23VPPAPIGEN: vppapigen replacement in Python PLY.Ole Troan1-1/+1
This is a version of the VPP API generator in Python PLY. It supports the existing language, and has a plugin architecture for generators. Currently C and JSON are supported. Changes: - vl_api_version to option version = "major.minor.patch" - enum support - Added error checking and reporting - import support (removed the C pre-processor) - services (tying request/reply together) Version: option version = "1.0.0"; Enum: enum colours { RED, BLUE = 50, }; define foo { vl_api_colours_t colours; }; Services: service { rpc foo returns foo_reply; rpc foo_dump returns stream foo_details; rpc want_stats returns want_stats_reply events ip4_counters, ip6_counters; }; Future planned features: - unions - bool, text - array support (including length) - proto3 output plugin - Refactor C/C++ generator as a plugin - Refactor Java generator as a plugin Change-Id: Ifa289966c790e1b1a8e2938a91e69331e3a58bdf Signed-off-by: Ole Troan <ot@cisco.com>
2018-01-22svm: queue sub: Add conditional timed waitMohsin Kazmi2-3/+3
On reviece side svm queue only permits blocking and non-blocking calls. This patch adds timed wait blocking functionality which returns either on signal/event or on given time out. It also preserves the original behavior, so it will not hurt client applications which are using svm queue. Change-Id: Ic10632170330a80afb8bc781d4ccddfe4da2c69a Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
2018-01-15svm: refactor memfd and remove ssvm_ethFlorin Coras5-12/+15
Change-Id: Icde296e956eb89ea3a17d547f04a833916ec6440 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-01-11api: fix handlers that explicitly depend on svm queueFlorin Coras3-0/+16
Fixes the remainig apis that explicitly check svm queue length. Change-Id: I6055c7c50050affee3098e162e15fb12c205e5db Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-01-11api: remove transport specific code from handlersFlorin Coras1-4/+4
This does not update api client code. In other words, if the client assumes the transport is shmem based, this patch does not change that. Furthermore, code that checks queue size, for tail dropping, is not updated. Done for the following apis: Plugins - acl - gtpu - memif - nat - pppoe VNET - bfd - bier - tapv2 - vhost user - dhcp - flow - geneve - ip - punt - ipsec/ipsec-gre - l2 - l2tp - lisp-cp/one-cp - lisp-gpe - map - mpls - policer - session - span - udp - tap - vxlan/vxlan-gpe - interface VPP - api/api.c OAM - oam_api.c Stats - stats.c Change-Id: I0e33ecefb2bdab0295698c0add948068a5a83345 Signed-off-by: Florin Coras <fcoras@cisco.com>
2018-01-10svm: calc base address on AArch64 based on autodetected VA space sizeDamjan Marion1-1/+1
Change-Id: I7487eb74b8deebff849d662b55a6708566ccd9ef Signed-off-by: Damjan Marion <damarion@cisco.com>
2018-01-09api: refactor vlibmemoryFlorin Coras17-3718/+3400
- separate client/server code for both memory and socket apis - separate memory api code from generic vlib api code - move unix_shared_memory_fifo to svm and rename to svm_fifo_t - overall declutter Change-Id: I90cdd98ff74d0787d58825b914b0f1eafcfa4dc2 Signed-off-by: Florin Coras <fcoras@cisco.com>
t_half_ip6_address (u8 * s, va_list * va) { u64 v = clib_net_to_host_u64 (va_arg (*va, u64)); return format (s, "%04x:%04x:%04x:%04x", v >> 48, (v >> 32) & 0xffff, (v >> 16) & 0xffff, v & 0xffff); } u8 * format_ila_direction (u8 * s, va_list * args) { ila_direction_t t = va_arg (*args, ila_direction_t); #define _(i,n,st) \ if (t == ILA_DIR_##i) \ return format(s, st); ila_foreach_direction #undef _ return format (s, "invalid_ila_direction"); } static u8 * format_csum_mode (u8 * s, va_list * va) { ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t); char *txt; switch (csum_mode) { #define _(i,n,st) \ case ILA_CSUM_MODE_##i: \ txt = st; \ break; ila_csum_foreach_type #undef _ default: txt = "invalid_ila_csum_mode"; break; } return format (s, txt); } u8 * format_ila_type (u8 * s, va_list * args) { ila_type_t t = va_arg (*args, ila_type_t); #define _(i,n,st) \ if (t == ILA_TYPE_##i) \ return format(s, st); ila_foreach_type #undef _ return format (s, "invalid_ila_type"); } static u8 * format_ila_entry (u8 * s, va_list * va) { vnet_main_t *vnm = va_arg (*va, vnet_main_t *); ila_entry_t *e = va_arg (*va, ila_entry_t *); if (!e) { return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address", "ILA Address", "Checksum Mode", "Direction", "Next DPO"); } else if (vnm) { if (ip6_address_is_zero(&e->next_hop)) { return format (s, "%-15U%=40U%=40U%18U%11U%s", format_ila_type, e->type, format_ip6_address, &e->sir_address, format_ip6_address, &e->ila_address, format_csum_mode, e->csum_mode, format_ila_direction, e->dir, "n/a"); } else { return format (s, "%-15U%=40U%=40U%18U%11U%U", format_ila_type, e->type, format_ip6_address, &e->sir_address, format_ip6_address, &e->ila_address, format_csum_mode, e->csum_mode, format_ila_direction, e->dir, format_dpo_id, &e->ila_dpo, 0); } } return NULL; } u8 * format_ila_ila2sir_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ila_ila2sir_trace_t *t = va_arg (*args, ila_ila2sir_trace_t *); return format (s, "ILA -> SIR adj index: %d entry index: %d initial_dst: %U", t->adj_index, t->ila_index, format_ip6_address, &t->initial_dst); } static uword unformat_ila_direction (unformat_input_t * input, va_list * args) { ila_direction_t *result = va_arg (*args, ila_direction_t *); #define _(i,n,s) \ if (unformat(input, s)) \ { \ *result = ILA_DIR_##i; \ return 1;\ } ila_foreach_direction #undef _ return 0; } static uword unformat_ila_type (unformat_input_t * input, va_list * args) { ila_type_t *result = va_arg (*args, ila_type_t *); #define _(i,n,s) \ if (unformat(input, s)) \ { \ *result = ILA_TYPE_##i; \ return 1;\ } ila_foreach_type #undef _ return 0; } static uword unformat_ila_csum_mode (unformat_input_t * input, va_list * args) { ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *); if (unformat (input, "none") || unformat (input, "no-action")) { *result = ILA_CSUM_MODE_NO_ACTION; return 1; } if (unformat (input, "neutral-map")) { *result = ILA_CSUM_MODE_NEUTRAL_MAP; return 1; } if (unformat (input, "adjust-transport")) { *result = ILA_CSUM_MODE_ADJUST_TRANSPORT; return 1; } return 0; } static uword unformat_half_ip6_address (unformat_input_t * input, va_list * args) { u64 *result = va_arg (*args, u64 *); u32 a[4]; if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3])) return 0; if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF) return 0; *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) | (((u64) a[1]) << 32) | (((u64) a[2]) << 16) | (((u64) a[3]))); return 1; } static vlib_node_registration_t ila_ila2sir_node; static uword ila_ila2sir (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_left_from, *from, next_index, *to_next, n_left_to_next; ila_main_t *ilm = &ila_main; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; while (n_left_from > 0) { vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from >= 4 && n_left_to_next >= 2) { u32 pi0, pi1; vlib_buffer_t *p0, *p1; ila_entry_t *ie0, *ie1; ip6_header_t *ip60, *ip61; ip6_address_t *sir_address0, *sir_address1; { vlib_buffer_t *p2, *p3; p2 = vlib_get_buffer (vm, from[2]); p3 = vlib_get_buffer (vm, from[3]); vlib_prefetch_buffer_header (p2, LOAD); vlib_prefetch_buffer_header (p3, LOAD); CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD); CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); } pi0 = to_next[0] = from[0]; pi1 = to_next[1] = from[1]; from += 2; n_left_from -= 2; to_next += 2; n_left_to_next -= 2; p0 = vlib_get_buffer (vm, pi0); p1 = vlib_get_buffer (vm, pi1); ip60 = vlib_buffer_get_current (p0); ip61 = vlib_buffer_get_current (p1); sir_address0 = &ip60->dst_address; sir_address1 = &ip61->dst_address; ie0 = pool_elt_at_index (ilm->entries, vnet_buffer (p0)->ip.adj_index[VLIB_TX]); ie1 = pool_elt_at_index (ilm->entries, vnet_buffer (p1)->ip.adj_index[VLIB_TX]); if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) { ila_ila2sir_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr)); tr->ila_index = ie0 - ilm->entries; tr->initial_dst = ip60->dst_address; tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; } if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) { ila_ila2sir_trace_t *tr = vlib_add_trace (vm, node, p1, sizeof (*tr)); tr->ila_index = ie1 - ilm->entries; tr->initial_dst = ip61->dst_address; tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX]; } sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; sir_address1 = (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1; ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; ip61->dst_address.as_u64[0] = sir_address1->as_u64[0]; ip61->dst_address.as_u64[1] = sir_address1->as_u64[1]; vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_dpo.dpoi_index; vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, pi0, pi1, ie0->ila_dpo.dpoi_next_node, ie1->ila_dpo.dpoi_next_node); } /* Single loop */ while (n_left_from > 0 && n_left_to_next > 0) { u32 pi0; vlib_buffer_t *p0; ila_entry_t *ie0; ip6_header_t *ip60; ip6_address_t *sir_address0; pi0 = to_next[0] = from[0]; from += 1; n_left_from -= 1; to_next += 1; n_left_to_next -= 1; p0 = vlib_get_buffer (vm, pi0); ip60 = vlib_buffer_get_current (p0); sir_address0 = &ip60->dst_address; ie0 = pool_elt_at_index (ilm->entries, vnet_buffer (p0)->ip.adj_index[VLIB_TX]); if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) { ila_ila2sir_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr)); tr->ila_index = ie0 - ilm->entries; tr->initial_dst = ip60->dst_address; tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; } sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, ie0->ila_dpo.dpoi_next_node); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } return frame->n_vectors; } /** *INDENT-OFF* */ VLIB_REGISTER_NODE (ila_ila2sir_node, static) = { .function = ila_ila2sir, .name = "ila-to-sir", .vector_size = sizeof (u32), .format_trace = format_ila_ila2sir_trace, .n_errors = ILA_N_ERROR, .error_strings = ila_error_strings, .n_next_nodes = ILA_ILA2SIR_N_NEXT, .next_nodes = { [ILA_ILA2SIR_NEXT_DROP] = "error-drop" }, }; /** *INDENT-ON* */ typedef enum { ILA_SIR2ILA_NEXT_DROP, ILA_SIR2ILA_N_NEXT, } ila_sir2ila_next_t; typedef struct { u32 ila_index; ip6_address_t initial_dst; } ila_sir2ila_trace_t; u8 * format_ila_sir2ila_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ila_sir2ila_trace_t *t = va_arg (*args, ila_sir2ila_trace_t *); return format (s, "SIR -> ILA entry index: %d initial_dst: %U", t->ila_index, format_ip6_address, &t->initial_dst); } static vlib_node_registration_t ila_sir2ila_node; static uword ila_sir2ila (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_left_from, *from, next_index, *to_next, n_left_to_next; ila_main_t *ilm = &ila_main; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; while (n_left_from > 0) { vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); while (n_left_from >= 4 && n_left_to_next >= 2) { u32 pi0, pi1; vlib_buffer_t *p0, *p1; ip6_header_t *ip60, *ip61; u32 next0 = ILA_SIR2ILA_NEXT_DROP; u32 next1 = ILA_SIR2ILA_NEXT_DROP; BVT (clib_bihash_kv) kv0, value0; BVT (clib_bihash_kv) kv1, value1; ila_entry_t *ie0 = &ila_sir2ila_default_entry; ila_entry_t *ie1 = &ila_sir2ila_default_entry; ip6_address_t *ila_address0, *ila_address1; { vlib_buffer_t *p2, *p3; p2 = vlib_get_buffer (vm, from[2]); p3 = vlib_get_buffer (vm, from[3]); vlib_prefetch_buffer_header (p2, LOAD); vlib_prefetch_buffer_header (p3, LOAD); CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD); CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); } pi0 = to_next[0] = from[0]; pi1 = to_next[1] = from[1]; from += 2; n_left_from -= 2; to_next += 2; n_left_to_next -= 2; p0 = vlib_get_buffer (vm, pi0); p1 = vlib_get_buffer (vm, pi1); ip60 = vlib_buffer_get_current (p0); ip61 = vlib_buffer_get_current (p1); ila_address0 = &ip60->dst_address; ila_address1 = &ip61->dst_address; kv0.key[0] = ip60->dst_address.as_u64[0]; kv0.key[1] = ip60->dst_address.as_u64[1]; kv0.key[2] = 0; kv1.key[0] = ip61->dst_address.as_u64[0]; kv1.key[1] = ip61->dst_address.as_u64[1]; kv1.key[2] = 0; if (PREDICT_TRUE((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { ie0 = &ilm->entries[value0.value]; ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; } if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv1, &value1)) == 0) { ie1 = &ilm->entries[value1.value]; ila_address1 = (ie1->dir != ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1; } if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) { ila_sir2ila_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr)); tr->ila_index = (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; tr->initial_dst = ip60->dst_address; } if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) { ila_sir2ila_trace_t *tr = vlib_add_trace (vm, node, p1, sizeof (*tr)); tr->ila_index = (ie1 != &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0; tr->initial_dst = ip61->dst_address; } ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; ip61->dst_address.as_u64[0] = ila_address1->as_u64[0]; ip61->dst_address.as_u64[1] = ila_address1->as_u64[1]; vnet_feature_next (&next0, p0); vnet_feature_next (&next1, p1); vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, pi0, pi1, next0, next1); } /* Single loop */ while (n_left_from > 0 && n_left_to_next > 0) { u32 pi0; vlib_buffer_t *p0; ip6_header_t *ip60; u32 next0 = ILA_SIR2ILA_NEXT_DROP; BVT (clib_bihash_kv) kv0, value0; ila_entry_t *ie0 = &ila_sir2ila_default_entry; ip6_address_t *ila_address0; pi0 = to_next[0] = from[0]; from += 1; n_left_from -= 1; to_next += 1; n_left_to_next -= 1; p0 = vlib_get_buffer (vm, pi0); ip60 = vlib_buffer_get_current (p0); ila_address0 = &ip60->dst_address; kv0.key[0] = ip60->dst_address.as_u64[0]; kv0.key[1] = ip60->dst_address.as_u64[1]; kv0.key[2] = 0; if (PREDICT_TRUE((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { ie0 = &ilm->entries[value0.value]; ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; } if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) { ila_sir2ila_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr)); tr->ila_index = (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; tr->initial_dst = ip60->dst_address; } //This operation should do everything for any type (except vnid4 obviously) ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; vnet_feature_next (&next0, p0); vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } return frame->n_vectors; } /** *INDENT-OFF* */ VLIB_REGISTER_NODE (ila_sir2ila_node, static) = { .function = ila_sir2ila,.name = "sir-to-ila", .vector_size = sizeof (u32), .format_trace = format_ila_sir2ila_trace, .n_errors = ILA_N_ERROR, .error_strings = ila_error_strings, .n_next_nodes = ILA_SIR2ILA_N_NEXT, .next_nodes = { [ILA_SIR2ILA_NEXT_DROP] = "error-drop" }, }; /** *INDENT-ON* */ /** *INDENT-OFF* */ VNET_FEATURE_INIT (ila_sir2ila, static) = { .arc_name = "ip6-unicast", .node_name = "sir-to-ila", .runs_before = VNET_FEATURES ("ip6-lookup"), }; /** *INDENT-ON* */ static void ila_entry_stack (ila_entry_t *ie) { /* * restack on the next-hop's FIB entry */ dpo_stack(ila_dpo_type, DPO_PROTO_IP6, &ie->ila_dpo, fib_entry_contribute_ip_forwarding( ie->next_hop_fib_entry_index)); } int ila_add_del_entry (ila_add_del_entry_args_t * args) { ila_main_t *ilm = &ila_main; BVT (clib_bihash_kv) kv, value; //Sanity check if (args->type == ILA_TYPE_IID || args->type == ILA_TYPE_LUID) { if ((args->sir_address.as_u8[8] >> 5) != args->type) { clib_warning ("Incorrect SIR address (ILA type mismatch %d %d)", args->sir_address.as_u8[8] >> 1, args->type); return -1; } if (args->sir_address.as_u8[8] & 0x10) { clib_warning ("Checksum bit should not be set in SIR address"); return -1; } } else if (args->type == ILA_TYPE_VNIDM) { if (args->sir_address.as_u8[0] != 0xff || (args->sir_address.as_u8[1] & 0xf0) != 0xf0) { clib_warning ("SIR multicast address must start with fff"); return -1; } if (args->sir_address.as_u16[1] || args->sir_address.as_u16[2] || args->sir_address.as_u16[3] || args->sir_address.as_u16[4] || args->sir_address.as_u16[5] || (args->sir_address.as_u8[12] & 0xf0)) { clib_warning ("SIR multicast address must start with fff"); return -1; } } if (!args->is_del) { ila_entry_t *e; pool_get (ilm->entries, e); e->type = args->type; e->sir_address = args->sir_address; e->next_hop = args->next_hop_address; e->csum_mode = args->csum_mode; e->dir = args->dir; //Construct ILA address switch (e->type) { case ILA_TYPE_IID: e->ila_address = e->sir_address; break; case ILA_TYPE_LUID: e->ila_address.as_u64[0] = args->locator; e->ila_address.as_u64[1] = args->sir_address.as_u64[1]; break; case ILA_TYPE_VNID6: e->ila_address.as_u64[0] = args->locator; e->ila_address.as_u8[8] = (ILA_TYPE_VNID6 << 1); e->ila_address.as_u32[2] |= args->vnid; e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; break; case ILA_TYPE_VNIDM: e->ila_address.as_u64[0] = args->locator; e->ila_address.as_u8[8] = (ILA_TYPE_VNIDM << 1); e->ila_address.as_u32[2] |= args->vnid; e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; e->ila_address.as_u8[12] |= args->sir_address.as_u8[2] << 4; break; case ILA_TYPE_VNID4: clib_warning ("ILA type '%U' is not supported", format_ila_type, e->type); return -1; } //Modify ILA checksum if necessary if (e->csum_mode == ILA_CSUM_MODE_NEUTRAL_MAP) { ip_csum_t csum = e->ila_address.as_u16[7]; int i; for (i = 0; i < 4; i++) { csum = ip_csum_sub_even (csum, e->sir_address.as_u32[i]); csum = ip_csum_add_even (csum, e->ila_address.as_u32[i]); } csum = ip_csum_add_even (csum, clib_host_to_net_u16 (0x1000)); e->ila_address.as_u16[7] = ip_csum_fold (csum); e->ila_address.as_u8[8] |= 0x10; } //Create entry with the sir address kv.key[0] = e->sir_address.as_u64[0]; kv.key[1] = e->sir_address.as_u64[1]; kv.key[2] = 0; kv.value = e - ilm->entries; BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, 1 /* is_add */ ); if (!ip6_address_is_zero(&e->next_hop)) { /* * become a child of the FIB netry for the next-hop * so we are informed when its forwarding changes */ fib_prefix_t next_hop = { .fp_addr = { .ip6 = e->next_hop, }, .fp_len = 128, .fp_proto = FIB_PROTOCOL_IP6, }; e->next_hop_fib_entry_index = fib_table_entry_special_add(0, &next_hop, FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE); e->next_hop_child_index = fib_entry_child_add(e->next_hop_fib_entry_index, ila_fib_node_type, e - ilm->entries); /* * Create a route that results in the ILA entry */ dpo_id_t dpo = DPO_INVALID; fib_prefix_t pfx = { .fp_addr = { .ip6 = e->ila_address, }, .fp_len = 128, .fp_proto = FIB_PROTOCOL_IP6, }; dpo_set(&dpo, ila_dpo_type, DPO_PROTO_IP6, e - ilm->entries); fib_table_entry_special_dpo_add(0, &pfx, ila_fib_src, FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); dpo_reset(&dpo); /* * finally stack the ILA entry so it will forward to the next-hop */ ila_entry_stack (e); } } else { ila_entry_t *e; kv.key[0] = args->sir_address.as_u64[0]; kv.key[1] = args->sir_address.as_u64[1]; kv.key[2] = 0; if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) < 0)) { return -1; } e = &ilm->entries[value.value]; if (!ip6_address_is_zero(&e->next_hop)) { fib_prefix_t pfx = { .fp_addr = { .ip6 = e->ila_address, }, .fp_len = 128, .fp_proto = FIB_PROTOCOL_IP6, }; fib_table_entry_special_remove(0, &pfx, ila_fib_src); /* * remove this ILA entry as child of the FIB netry for the next-hop */ fib_entry_child_remove(e->next_hop_fib_entry_index, e->next_hop_child_index); fib_table_entry_delete_index(e->next_hop_fib_entry_index, FIB_SOURCE_RR); e->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; } dpo_reset (&e->ila_dpo); BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, 0 /* is_add */ ); pool_put (ilm->entries, e); } return 0; } int ila_interface (u32 sw_if_index, u8 disable) { vnet_feature_enable_disable ("ip4-unicast", "sir-to-ila", sw_if_index, !disable, 0, 0); return 0; } /* *INDENT-OFF* */ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Identifier Locator Addressing (ILA) for IPv6", }; /* *INDENT-ON* */ u8 *format_ila_dpo (u8 * s, va_list * va) { index_t index = va_arg (*va, index_t); CLIB_UNUSED(u32 indent) = va_arg (*va, u32); ila_main_t *ilm = &ila_main; ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); return format(s, "ILA: idx:%d sir:%U", index, format_ip6_address, &ie->sir_address); } /** * @brief no-op lock function. * The lifetime of the ILA entry is managed by the control plane */ static void ila_dpo_lock (dpo_id_t *dpo) { } /** * @brief no-op unlock function. * The lifetime of the ILA entry is managed by the control plane */ static void ila_dpo_unlock (dpo_id_t *dpo) { } const static dpo_vft_t ila_vft = { .dv_lock = ila_dpo_lock, .dv_unlock = ila_dpo_unlock, .dv_format = format_ila_dpo, }; const static char* const ila_ip6_nodes[] = { "ila-to-sir", NULL, }; const static char* const * const ila_nodes[DPO_PROTO_NUM] = { [DPO_PROTO_IP6] = ila_ip6_nodes, }; static fib_node_t * ila_fib_node_get_node (fib_node_index_t index) { ila_main_t *ilm = &ila_main; ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); return (&ie->ila_fib_node); } /** * @brief no-op unlock function. * The lifetime of the ILA entry is managed by the control plane */ static void ila_fib_node_last_lock_gone (fib_node_t *node) { } static ila_entry_t * ila_entry_from_fib_node (fib_node_t *node) { return ((ila_entry_t*)(((char*)node) - STRUCT_OFFSET_OF(ila_entry_t, ila_fib_node))); } /** * @brief * Callback function invoked when the forwarding changes for the ILA next-hop */ static fib_node_back_walk_rc_t ila_fib_node_back_walk_notify (fib_node_t *node, fib_node_back_walk_ctx_t *ctx) { ila_entry_stack(ila_entry_from_fib_node(node)); return (FIB_NODE_BACK_WALK_CONTINUE); } /* * ILA's FIB graph node virtual function table */ static const fib_node_vft_t ila_fib_node_vft = { .fnv_get = ila_fib_node_get_node, .fnv_last_lock = ila_fib_node_last_lock_gone, .fnv_back_walk = ila_fib_node_back_walk_notify, }; clib_error_t * ila_init (vlib_main_t * vm) { ila_main_t *ilm = &ila_main; ilm->entries = NULL; ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS; ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets); ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE; BV (clib_bihash_init) (&ilm->id_to_entry_table, "ila id to entry index table", ilm->lookup_table_nbuckets, ilm->lookup_table_size); ila_dpo_type = dpo_register_new_type(&ila_vft, ila_nodes); ila_fib_node_type = fib_node_register_new_type ("ila", &ila_fib_node_vft); ila_fib_src = fib_source_allocate("ila", FIB_SOURCE_PRIORITY_HI, FIB_SOURCE_BH_SIMPLE); return NULL; } VLIB_INIT_FUNCTION (ila_init); static clib_error_t * ila_entry_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; ila_add_del_entry_args_t args = { 0 }; u8 next_hop_set = 0; int ret; clib_error_t *error = 0; args.type = ILA_TYPE_IID; args.csum_mode = ILA_CSUM_MODE_NO_ACTION; args.local_adj_index = ~0; args.dir = ILA_DIR_BIDIR; if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "type %U", unformat_ila_type, &args.type)) ; else if (unformat (line_input, "sir-address %U", unformat_ip6_address, &args.sir_address)) ; else if (unformat (line_input, "locator %U", unformat_half_ip6_address, &args.locator)) ; else if (unformat (line_input, "csum-mode %U", unformat_ila_csum_mode, &args.csum_mode)) ; else if (unformat (line_input, "vnid %x", &args.vnid)) ; else if (unformat (line_input, "next-hop %U", unformat_ip6_address, &args.next_hop_address)) ; else if (unformat (line_input, "direction %U", unformat_ila_direction, &args.dir)) next_hop_set = 1; else if (unformat (line_input, "del")) args.is_del = 1; else { error = clib_error_return (0, "parse error: '%U'", format_unformat_error, line_input); goto done; } } if (!next_hop_set) { error = clib_error_return (0, "Specified a next hop"); goto done; } if ((ret = ila_add_del_entry (&args))) { error = clib_error_return (0, "ila_add_del_entry returned error %d", ret); goto done; } done: unformat_free (line_input); return error; } VLIB_CLI_COMMAND (ila_entry_command, static) = { .path = "ila entry", .short_help = "ila entry [type <type>] [sir-address <address>] [locator <locator>] [vnid <hex-vnid>]" " [adj-index <adj-index>] [next-hop <next-hop>] [direction (bidir|sir2ila|ila2sir)]" " [csum-mode (no-action|neutral-map|transport-adjust)] [del]", .function = ila_entry_command_fn, }; static clib_error_t * ila_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { vnet_main_t *vnm = vnet_get_main (); u32 sw_if_index = ~0; u8 disable = 0; if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) { return clib_error_return (0, "Invalid interface name"); } if (unformat (input, "disable")) { disable = 1; } int ret; if ((ret = ila_interface (sw_if_index, disable))) return clib_error_return (0, "ila_interface returned error %d", ret); return NULL; } VLIB_CLI_COMMAND (ila_interface_command, static) = { .path = "ila interface", .short_help = "ila interface <interface-name> [disable]", .function = ila_interface_command_fn, }; static clib_error_t * ila_show_entries_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { vnet_main_t *vnm = vnet_get_main (); ila_main_t *ilm = &ila_main; ila_entry_t *e; vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, NULL); pool_foreach (e, ilm->entries) { vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, e); } return NULL; } VLIB_CLI_COMMAND (ila_show_entries_command, static) = { .path = "show ila entries", .short_help = "show ila entries", .function = ila_show_entries_command_fn, };