From 4521afa9a643983c789b6b3a77b14c0a95d5e0b2 Mon Sep 17 00:00:00 2001 From: Pablo Camarillo Date: Thu, 16 Mar 2017 10:43:05 +0100 Subject: Bugfixing and documentation for SRv6 - Fixed three coverity issues - Linked SRv6 docs - Moved sample plugin to examples folder - Fixed bug with hash. Now everything is using mhash. Potentially in the future we want to do bihash. Change-Id: Ie03a13c8fecb1e315e67d0596cbd23220779aaf2 Signed-off-by: Pablo Camarillo --- doxygen/Makefile | 6 +- doxygen/user_doc.md | 13 +- src/configure.ac | 1 - src/examples/srv6-sample-localsid/node.c | 200 +++++++++++++++++++++ .../srv6-sample-localsid/srv6_localsid_sample.c | 179 ++++++++++++++++++ .../srv6-sample-localsid/srv6_localsid_sample.h | 61 +++++++ .../srv6_sample_localsid_doc.md | 30 ++++ src/plugins/Makefile.am | 4 - src/plugins/sample_srv6_localsid.am | 23 --- src/plugins/srv6-localsid/node.c | 200 --------------------- src/plugins/srv6-localsid/srv6_localsid_sample.c | 179 ------------------ src/plugins/srv6-localsid/srv6_localsid_sample.h | 61 ------- .../srv6-localsid/srv6_sample_localsid_doc.md | 38 ---- src/vnet/sr/sr.h | 30 +--- src/vnet/sr/sr_doc.md | 132 ++------------ src/vnet/sr/sr_localsid.c | 18 +- src/vnet/sr/sr_localsid.md | 58 ++++++ src/vnet/sr/sr_policy.md | 56 ++++++ src/vnet/sr/sr_policy_rewrite.c | 28 ++- src/vnet/sr/sr_steering.c | 59 +++--- src/vnet/sr/sr_steering.md | 11 ++ 21 files changed, 672 insertions(+), 715 deletions(-) create mode 100644 src/examples/srv6-sample-localsid/node.c create mode 100755 src/examples/srv6-sample-localsid/srv6_localsid_sample.c create mode 100644 src/examples/srv6-sample-localsid/srv6_localsid_sample.h create mode 100644 src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md delete mode 100644 src/plugins/sample_srv6_localsid.am delete mode 100644 src/plugins/srv6-localsid/node.c delete mode 100755 src/plugins/srv6-localsid/srv6_localsid_sample.c delete mode 100644 src/plugins/srv6-localsid/srv6_localsid_sample.h delete mode 100644 src/plugins/srv6-localsid/srv6_sample_localsid_doc.md create mode 100644 src/vnet/sr/sr_localsid.md create mode 100644 src/vnet/sr/sr_policy.md create mode 100644 src/vnet/sr/sr_steering.md diff --git a/doxygen/Makefile b/doxygen/Makefile index 973ca07facc..9caa4079980 100644 --- a/doxygen/Makefile +++ b/doxygen/Makefile @@ -53,7 +53,8 @@ DOXY_SRC_DIRECTORIES = \ $(DOXY_SRC)/vlibsocket \ $(DOXY_SRC)/vnet \ $(DOXY_SRC)/vpp \ - $(DOXY_SRC)/vpp-api + $(DOXY_SRC)/vpp-api \ + $(DOXY_SRC)/examples # Input directories and files DOXY_INPUT ?= \ @@ -72,9 +73,8 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT)) # These must be left-anchored paths for the regexp below to work. DOXY_EXCLUDE ?= \ $(DOXY_SRC)/vlib/vlib/buffer.c \ - $(DOXY_SRC)/vlib/example \ $(DOXY_SRC)/vpp-api/lua \ - plugins/sample-plugin + $(DOXY_SRC)/examples/sample-plugin # Generate a regexp for filenames to exclude DOXY_EXCLUDE_REGEXP = ($(subst .,\.,$(shell echo '$(strip $(DOXY_EXCLUDE))' | sed -e 's/ /|/g'))) diff --git a/doxygen/user_doc.md b/doxygen/user_doc.md index 40303439a81..29df6156cd9 100644 --- a/doxygen/user_doc.md +++ b/doxygen/user_doc.md @@ -4,13 +4,14 @@ User Documentation {#user_doc} Several modules provide operational, dataplane-user focused documentation. - [GUI guided user demo](https://wiki.fd.io/view/VPP_Sandbox/vpp-userdemo) -- @subpage qos_doc -- @subpage ipsec_gre_doc -- @subpage dpdk_crypto_ipsec_doc -- @subpage map_doc -- @subpage lldp_doc +- @subpage bfd_doc - @subpage ioam_plugin_doc +- @subpage ipsec_gre_doc - @subpage lb_plugin_doc +- @subpage lldp_doc +- @subpage map_doc +- @subpage dpdk_crypto_ipsec_doc - @subpage flowperpkt_plugin_doc +- @subpage qos_doc - @subpage span_doc -- @subpage bfd_doc +- @subpage srv6_doc diff --git a/src/configure.ac b/src/configure.ac index 0ca1af110b3..581b0968d10 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -154,7 +154,6 @@ PLUGIN_ENABLED(lb) PLUGIN_ENABLED(memif) PLUGIN_ENABLED(sixrd) PLUGIN_ENABLED(snat) -PLUGIN_DISABLED(srv6sample) ############################################################################### # Dependency checks diff --git a/src/examples/srv6-sample-localsid/node.c b/src/examples/srv6-sample-localsid/node.c new file mode 100644 index 00000000000..7bae9cd7c55 --- /dev/null +++ b/src/examples/srv6-sample-localsid/node.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015 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 +#include +#include +#include +#include + +typedef struct { + u32 localsid_index; +} srv6_localsid_sample_trace_t; + +/* packet trace format function */ +static u8 * format_srv6_localsid_sample_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 *); + srv6_localsid_sample_trace_t * t = va_arg (*args, srv6_localsid_sample_trace_t *); + s = format (s, "SRv6-sample-localsid: localsid_index %d\n", + t->localsid_index); + return s; +} + +vlib_node_registration_t srv6_localsid_sample_node; + +#define foreach_srv6_localsid_counter \ +_(PROCESSED, "srv6-sample-localsid processed packets") \ +_(NO_SRH, "(Error) No SRH.") + +typedef enum { +#define _(sym,str) SRV6_LOCALSID_COUNTER_##sym, + foreach_srv6_localsid_counter +#undef _ + SRV6_LOCALSID_N_COUNTERS, +} srv6_localsid_sample_counters; + +static char * srv6_localsid_counter_strings[] = { +#define _(sym,string) string, + foreach_srv6_localsid_counter +#undef _ +}; + +typedef enum { + SRV6_SAMPLE_LOCALSID_NEXT_ERROR, + SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP, + SRV6_SAMPLE_LOCALSID_N_NEXT, +} srv6_localsid_sample_next_t; + +/** + * @brief Function doing End processing. + */ +//Fixme: support OAM (hop-by-hop header) here! +static_always_inline void +end_srh_processing (vlib_node_runtime_t * node, + vlib_buffer_t * b0, + ip6_header_t * ip0, + ip6_sr_header_t * sr0, + u32 * next0) +{ + ip6_address_t *new_dst0; + + if(PREDICT_TRUE(ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)) + { + if(PREDICT_TRUE(sr0->type == ROUTING_HEADER_TYPE_SR)) + { + if(PREDICT_TRUE(sr0->segments_left != 0)) + { + sr0->segments_left -= 1; + new_dst0 = (ip6_address_t *)(sr0->segments); + new_dst0 += sr0->segments_left; + ip0->dst_address.as_u64[0] = new_dst0->as_u64[0]; + ip0->dst_address.as_u64[1] = new_dst0->as_u64[1]; + } + else + { + *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; + b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; + } + } + else + { + /* Error. Routing header of type != SR */ + *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; + b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; + } + } +} + +/* + * @brief SRv6 Sample Localsid graph node + * WARNING: YOU MUST DO THE DUAL LOOP + */ +static uword +srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, * from, * to_next; + u32 next_index; + u32 pkts_swapped = 0; + + ip6_sr_main_t * sm = &sr_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + u32 cpu_index = os_get_cpu_number (); + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, + to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t * b0; + ip6_header_t * ip0 = 0; + ip6_sr_header_t * sr0; + u32 next0 = SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP; + ip6_sr_localsid_t *ls0; + srv6_localsid_sample_per_sid_memory_t *ls0_mem; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + ip0 = vlib_buffer_get_current (b0); + sr0 = (ip6_sr_header_t *)(ip0+1); + + /* Lookup the SR End behavior based on IP DA (adj) */ + ls0 = pool_elt_at_index (sm->localsids, vnet_buffer(b0)->ip.adj_index[VLIB_TX]); + ls0_mem = ls0->plugin_mem; + + /* SRH processing */ + end_srh_processing (node, b0, ip0, sr0, &next0); + + /* ==================================================================== */ + /* INSERT CODE HERE */ + /* Example starts here */ + //In this example we are changing the next VRF table by the one in CLI + vnet_buffer(b0)->sw_if_index[VLIB_TX] = ls0_mem->fib_table; + /* Example finishes here */ + /* ==================================================================== */ + + if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) + { + srv6_localsid_sample_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); + tr->localsid_index = ls0 - sm->localsids; + } + + /* This increments the SRv6 per LocalSID counters.*/ + vlib_increment_combined_counter + (((next0 == SRV6_SAMPLE_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : &(sm->sr_ls_valid_counters)), + cpu_index, + ls0 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b0)); + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + + pkts_swapped ++; + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + + } + + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (srv6_localsid_sample_node) = { + .function = srv6_localsid_sample_fn, + .name = "srv6-localsid-sample", + .vector_size = sizeof (u32), + .format_trace = format_srv6_localsid_sample_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = SRV6_LOCALSID_N_COUNTERS, + .error_strings = srv6_localsid_counter_strings, + .n_next_nodes = SRV6_SAMPLE_LOCALSID_N_NEXT, + .next_nodes = { + [SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP] = "ip6-lookup", + [SRV6_SAMPLE_LOCALSID_NEXT_ERROR] = "error-drop", + }, +}; diff --git a/src/examples/srv6-sample-localsid/srv6_localsid_sample.c b/src/examples/srv6-sample-localsid/srv6_localsid_sample.c new file mode 100755 index 00000000000..ec16547eebf --- /dev/null +++ b/src/examples/srv6-sample-localsid/srv6_localsid_sample.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2015 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. + */ +/* + *------------------------------------------------------------------ + * srv6_localsid_sample.c - Simple SRv6 LocalSID + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +unsigned char srv6_localsid_name[32] = "Sample-SRv6-LocalSID-plugin"; +unsigned char keyword_str[32] = "new_srv6_localsid"; +unsigned char def_str[64] = "This is a definition of a sample new_srv6_localsid"; +unsigned char params_str[32] = ""; + +/*****************************************/ +/* SRv6 LocalSID instantiation and removal functions */ +static int +srv6_localsid_creation_fn (ip6_sr_localsid_t *localsid) +{ + /* + * Do you want to do anything fancy upon localsid instantiation? + * You can do it here + * (If return != 0 the localsid creation will be cancelled.) + */ + /* As an example Im going to do a +1 to the fib table inserted by the user */ + srv6_localsid_sample_per_sid_memory_t *ls_mem = localsid->plugin_mem; + ls_mem->fib_table += 1; + return 0; +} + +static int +srv6_localsid_removal_fn (ip6_sr_localsid_t *localsid) +{ + /* Do you want to do anything fancy upon localsid removal? + * You can do it here + * (If return != 0 the localsid removal will be cancelled.) + */ + /* + * BTW if you stored something in localsid->plugin_mem you should clean it now + */ + + //In this example we are only cleaning the memory allocated per localsid + clib_mem_free(localsid->plugin_mem); + return 0; +} + +/**********************************/ +/* SRv6 LocalSID format functions */ +/* + * Prints nicely the parameters of a localsid + * Example: print "Table 5" + */ +u8 * +format_srv6_localsid_sample (u8 * s, va_list * args) +{ + srv6_localsid_sample_per_sid_memory_t *ls_mem = va_arg (*args, void *); + return (format (s, "Table: %u", ls_mem->fib_table)); +} + +/* + * Process the parameters of a localsid + * Example: process from: + * sr localsid address cafe::1 behavior new_srv6_localsid 5 + * everything from behavior on... so in this case 'new_srv6_localsid 5' + * Notice that it MUST match the keyword_str and params_str defined above. + */ +uword +unformat_srv6_localsid_sample (unformat_input_t * input, va_list * args) +{ + void **plugin_mem = va_arg (*args, void **); + srv6_localsid_sample_per_sid_memory_t *ls_mem; + u32 table_id; + if (unformat (input, "new_srv6_localsid %u", &table_id)) + { + /* Allocate a portion of memory */ + ls_mem = clib_mem_alloc_aligned_at_offset ( + sizeof(srv6_localsid_sample_per_sid_memory_t), 0, 0, 1); + + /* Set to zero the memory */ + memset (ls_mem, 0, sizeof(srv6_localsid_sample_per_sid_memory_t)); + + /* Our brand-new car is ready */ + ls_mem->fib_table = table_id; + + /* Dont forget to add it to the localsid */ + *plugin_mem = ls_mem; + return 1; + } + return 0; +} + +/*************************/ +/* SRv6 LocalSID FIB DPO */ +static u8 * +format_srv6_localsid_sample_dpo (u8 * s, va_list * args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED (u32 indent) = va_arg (*args, u32); + + return (format (s, "SR: localsid_sample_index:[%u]", index)); +} + +void +srv6_localsid_sample_dpo_lock (dpo_id_t * dpo) +{ +} + +void +srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo) +{ +} + +const static dpo_vft_t srv6_localsid_sample_vft = { + .dv_lock = srv6_localsid_sample_dpo_lock, + .dv_unlock = srv6_localsid_sample_dpo_unlock, + .dv_format = format_srv6_localsid_sample_dpo, +}; + +const static char *const srv6_localsid_sample_ip6_nodes[] = { + "srv6-localsid-sample", + NULL, +}; + +const static char *const *const srv6_localsid_sample_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP6] = srv6_localsid_sample_ip6_nodes, +}; + +/**********************/ +static clib_error_t * srv6_localsid_sample_init (vlib_main_t * vm) +{ + srv6_localsid_sample_main_t * sm = &srv6_localsid_sample_main; + int rv = 0; + /* Create DPO */ + sm->srv6_localsid_sample_dpo_type = dpo_register_new_type ( + &srv6_localsid_sample_vft, srv6_localsid_sample_nodes); + + /* Register SRv6 LocalSID */ + rv = sr_localsid_register_function (vm, + srv6_localsid_name, + keyword_str, + def_str, + params_str, + &sm->srv6_localsid_sample_dpo_type, + format_srv6_localsid_sample, + unformat_srv6_localsid_sample, + srv6_localsid_creation_fn, + srv6_localsid_removal_fn); + if (rv < 0) + clib_error_return (0, "SRv6 LocalSID function could not be registered."); + else + sm->srv6_localsid_behavior_id = rv; + + return 0; +} + +VLIB_INIT_FUNCTION (srv6_localsid_sample_init); + +VLIB_PLUGIN_REGISTER () = { + .version = "1.0", +}; diff --git a/src/examples/srv6-sample-localsid/srv6_localsid_sample.h b/src/examples/srv6-sample-localsid/srv6_localsid_sample.h new file mode 100644 index 00000000000..474b5de2d49 --- /dev/null +++ b/src/examples/srv6-sample-localsid/srv6_localsid_sample.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 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. + */ +#ifndef __included_srv6_localsid_sample_h__ +#define __included_srv6_localsid_sample_h__ + +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + /* API message ID base */ + u16 msg_id_base; + + /* convenience */ + vlib_main_t * vlib_main; + vnet_main_t * vnet_main; + + /* DPO type */ + dpo_type_t srv6_localsid_sample_dpo_type; + + /* SRv6 LocalSID behavior number */ + u32 srv6_localsid_behavior_id; + +} srv6_localsid_sample_main_t; + +/* + * This is the memory that will be stored per each localsid + * the user instantiates + */ +typedef struct { + u32 fib_table; /* Stupid index used as an example.. */ +} srv6_localsid_sample_per_sid_memory_t ; + +srv6_localsid_sample_main_t srv6_localsid_sample_main; + +format_function_t format_srv6_localsid_sample; +unformat_function_t unformat_srv6_localsid_sample; + +void srv6_localsid_sample_dpo_lock (dpo_id_t * dpo); +void srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo); + +extern vlib_node_registration_t srv6_localsid_sample_node; + +#endif /* __included_sample_h__ */ diff --git a/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md b/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md new file mode 100644 index 00000000000..78e91ab3a7f --- /dev/null +++ b/src/examples/srv6-sample-localsid/srv6_sample_localsid_doc.md @@ -0,0 +1,30 @@ +# Sample SRv6 LocalSID documentation {#srv6_plugin_doc} + +## Introduction + +This plugin is an example of how an user can create a new SRv6 LocalSID behavior by using VPP plugins with the appropiate API calls to the existing SR code. + +This **example** plugin registers a new localsid behavior, with cli keyword 'new_srv6_localsid' which only takes one parameter, a fib-table. Upon recival of a packet, this plugin will enforce the next IP6 lookup in the specific fib-table specified by the user. (Indeed it will do the lookup in the fib_table n+1 (since for the shake of the example we increment the fib-table.) + +Notice that the plugin only 'defines' a new SRv6 LocalSID behavior, but the existing SR code in VNET is the one actually instantiating new LocalSIDs. Notice that there are callback functions such that when you create or remove a LocalSID you can actually setup specific parameters through the functions in this plugin. + +## Variables to watch for + +* srv6_localsid_name: This variable is the name (used as a unique key) identifying this SR LocalSID plugin. +* keyword_str: This is the CLI keyword to be used for the plugin. In this example 'new_srv6_localsid'. (i.e. sr localsid address cafe::1 behavior new_srv6_localsid ) +* def_str: This is a definition of this SR behavior. This is printed when you do 'show sr localsid behaviors'. +* params_str: This is a definition of the parameters of this localsid. This is printed when you do 'show sr localsid behaviors'. + +## Functions to watch for + +* srv6_localsid_creation_fn: This function will be called every time a new SR LocalSID is instantiated with the behavior defined in this plugin. +* srv6_localsid_removal_fn: This function will be called every time a new SR LocalSID is removed with the behavior defined in this plugin. This function tends to be used for freeing up all the memory created in the previous function. +* format_srv6_localsid_sample: This function prints nicely the parameters of every SR LocalSID using this behavior. +* unformat_srv6_localsid_sample: This function parses the CLI command when initialising a new SR LocalSID using this behavior. It parses all the parameters and ensures that the parameters are correct. +* format_srv6_localsid_sample_dpo: This function formats the 'show ip6 fib' message for the SR LocalSIDs created with this plugin behavior. + +## Graph node + +The current graph node uses the function 'end_srh_processing' to do the Segment Routing Endpoint behavior. Notice that it does not allow the cleanup of a Segment Routing header (as per the SRv6 behavior specs). +This function is identical to the one found in /src/vnet/sr/sr_localsid.c +In case that by some other reason you want to do decapsulation, or SRH clean_up you can use the functions 'end_decaps_srh_processing' or 'end_psp_srh_processing' respectively. diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 6713a9e25a3..623892e7066 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -69,10 +69,6 @@ if ENABLE_SNAT_PLUGIN include snat.am endif -if ENABLE_SRV6SAMPLE_PLUGIN -include sample_srv6_localsid.am -endif - include ../suffix-rules.mk # Remove *.la files diff --git a/src/plugins/sample_srv6_localsid.am b/src/plugins/sample_srv6_localsid.am deleted file mode 100644 index a820ab25bab..00000000000 --- a/src/plugins/sample_srv6_localsid.am +++ /dev/null @@ -1,23 +0,0 @@ - -# Copyright (c) -# 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. - -vppplugins_LTLIBRARIES += sample_srv6_localsid_plugin.la - -sample_srv6_localsid_plugin_la_SOURCES = \ - srv6-localsid/node.c \ - srv6-localsid/srv6_localsid_sample.c - -noinst_HEADERS += srv6-localsid/srv6_localsid_sample.h - -# vi:syntax=automake diff --git a/src/plugins/srv6-localsid/node.c b/src/plugins/srv6-localsid/node.c deleted file mode 100644 index 7bae9cd7c55..00000000000 --- a/src/plugins/srv6-localsid/node.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2015 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 -#include -#include -#include -#include - -typedef struct { - u32 localsid_index; -} srv6_localsid_sample_trace_t; - -/* packet trace format function */ -static u8 * format_srv6_localsid_sample_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 *); - srv6_localsid_sample_trace_t * t = va_arg (*args, srv6_localsid_sample_trace_t *); - s = format (s, "SRv6-sample-localsid: localsid_index %d\n", - t->localsid_index); - return s; -} - -vlib_node_registration_t srv6_localsid_sample_node; - -#define foreach_srv6_localsid_counter \ -_(PROCESSED, "srv6-sample-localsid processed packets") \ -_(NO_SRH, "(Error) No SRH.") - -typedef enum { -#define _(sym,str) SRV6_LOCALSID_COUNTER_##sym, - foreach_srv6_localsid_counter -#undef _ - SRV6_LOCALSID_N_COUNTERS, -} srv6_localsid_sample_counters; - -static char * srv6_localsid_counter_strings[] = { -#define _(sym,string) string, - foreach_srv6_localsid_counter -#undef _ -}; - -typedef enum { - SRV6_SAMPLE_LOCALSID_NEXT_ERROR, - SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP, - SRV6_SAMPLE_LOCALSID_N_NEXT, -} srv6_localsid_sample_next_t; - -/** - * @brief Function doing End processing. - */ -//Fixme: support OAM (hop-by-hop header) here! -static_always_inline void -end_srh_processing (vlib_node_runtime_t * node, - vlib_buffer_t * b0, - ip6_header_t * ip0, - ip6_sr_header_t * sr0, - u32 * next0) -{ - ip6_address_t *new_dst0; - - if(PREDICT_TRUE(ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)) - { - if(PREDICT_TRUE(sr0->type == ROUTING_HEADER_TYPE_SR)) - { - if(PREDICT_TRUE(sr0->segments_left != 0)) - { - sr0->segments_left -= 1; - new_dst0 = (ip6_address_t *)(sr0->segments); - new_dst0 += sr0->segments_left; - ip0->dst_address.as_u64[0] = new_dst0->as_u64[0]; - ip0->dst_address.as_u64[1] = new_dst0->as_u64[1]; - } - else - { - *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; - b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; - } - } - else - { - /* Error. Routing header of type != SR */ - *next0 = SRV6_SAMPLE_LOCALSID_NEXT_ERROR; - b0->error = node->errors[SRV6_LOCALSID_COUNTER_NO_SRH]; - } - } -} - -/* - * @brief SRv6 Sample Localsid graph node - * WARNING: YOU MUST DO THE DUAL LOOP - */ -static uword -srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, * from, * to_next; - u32 next_index; - u32 pkts_swapped = 0; - - ip6_sr_main_t * sm = &sr_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, - to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t * b0; - ip6_header_t * ip0 = 0; - ip6_sr_header_t * sr0; - u32 next0 = SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP; - ip6_sr_localsid_t *ls0; - srv6_localsid_sample_per_sid_memory_t *ls0_mem; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip0 = vlib_buffer_get_current (b0); - sr0 = (ip6_sr_header_t *)(ip0+1); - - /* Lookup the SR End behavior based on IP DA (adj) */ - ls0 = pool_elt_at_index (sm->localsids, vnet_buffer(b0)->ip.adj_index[VLIB_TX]); - ls0_mem = ls0->plugin_mem; - - /* SRH processing */ - end_srh_processing (node, b0, ip0, sr0, &next0); - - /* ==================================================================== */ - /* INSERT CODE HERE */ - /* Example starts here */ - //In this example we are changing the next VRF table by the one in CLI - vnet_buffer(b0)->sw_if_index[VLIB_TX] = ls0_mem->fib_table; - /* Example finishes here */ - /* ==================================================================== */ - - if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) - { - srv6_localsid_sample_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); - tr->localsid_index = ls0 - sm->localsids; - } - - /* This increments the SRv6 per LocalSID counters.*/ - vlib_increment_combined_counter - (((next0 == SRV6_SAMPLE_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : &(sm->sr_ls_valid_counters)), - cpu_index, - ls0 - sm->localsids, - 1, vlib_buffer_length_in_chain (vm, b0)); - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - - pkts_swapped ++; - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - - } - - return frame->n_vectors; -} - -VLIB_REGISTER_NODE (srv6_localsid_sample_node) = { - .function = srv6_localsid_sample_fn, - .name = "srv6-localsid-sample", - .vector_size = sizeof (u32), - .format_trace = format_srv6_localsid_sample_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = SRV6_LOCALSID_N_COUNTERS, - .error_strings = srv6_localsid_counter_strings, - .n_next_nodes = SRV6_SAMPLE_LOCALSID_N_NEXT, - .next_nodes = { - [SRV6_SAMPLE_LOCALSID_NEXT_IP6LOOKUP] = "ip6-lookup", - [SRV6_SAMPLE_LOCALSID_NEXT_ERROR] = "error-drop", - }, -}; diff --git a/src/plugins/srv6-localsid/srv6_localsid_sample.c b/src/plugins/srv6-localsid/srv6_localsid_sample.c deleted file mode 100755 index ec16547eebf..00000000000 --- a/src/plugins/srv6-localsid/srv6_localsid_sample.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2015 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. - */ -/* - *------------------------------------------------------------------ - * srv6_localsid_sample.c - Simple SRv6 LocalSID - *------------------------------------------------------------------ - */ - -#include -#include -#include - -#include -#include -#include - -unsigned char srv6_localsid_name[32] = "Sample-SRv6-LocalSID-plugin"; -unsigned char keyword_str[32] = "new_srv6_localsid"; -unsigned char def_str[64] = "This is a definition of a sample new_srv6_localsid"; -unsigned char params_str[32] = ""; - -/*****************************************/ -/* SRv6 LocalSID instantiation and removal functions */ -static int -srv6_localsid_creation_fn (ip6_sr_localsid_t *localsid) -{ - /* - * Do you want to do anything fancy upon localsid instantiation? - * You can do it here - * (If return != 0 the localsid creation will be cancelled.) - */ - /* As an example Im going to do a +1 to the fib table inserted by the user */ - srv6_localsid_sample_per_sid_memory_t *ls_mem = localsid->plugin_mem; - ls_mem->fib_table += 1; - return 0; -} - -static int -srv6_localsid_removal_fn (ip6_sr_localsid_t *localsid) -{ - /* Do you want to do anything fancy upon localsid removal? - * You can do it here - * (If return != 0 the localsid removal will be cancelled.) - */ - /* - * BTW if you stored something in localsid->plugin_mem you should clean it now - */ - - //In this example we are only cleaning the memory allocated per localsid - clib_mem_free(localsid->plugin_mem); - return 0; -} - -/**********************************/ -/* SRv6 LocalSID format functions */ -/* - * Prints nicely the parameters of a localsid - * Example: print "Table 5" - */ -u8 * -format_srv6_localsid_sample (u8 * s, va_list * args) -{ - srv6_localsid_sample_per_sid_memory_t *ls_mem = va_arg (*args, void *); - return (format (s, "Table: %u", ls_mem->fib_table)); -} - -/* - * Process the parameters of a localsid - * Example: process from: - * sr localsid address cafe::1 behavior new_srv6_localsid 5 - * everything from behavior on... so in this case 'new_srv6_localsid 5' - * Notice that it MUST match the keyword_str and params_str defined above. - */ -uword -unformat_srv6_localsid_sample (unformat_input_t * input, va_list * args) -{ - void **plugin_mem = va_arg (*args, void **); - srv6_localsid_sample_per_sid_memory_t *ls_mem; - u32 table_id; - if (unformat (input, "new_srv6_localsid %u", &table_id)) - { - /* Allocate a portion of memory */ - ls_mem = clib_mem_alloc_aligned_at_offset ( - sizeof(srv6_localsid_sample_per_sid_memory_t), 0, 0, 1); - - /* Set to zero the memory */ - memset (ls_mem, 0, sizeof(srv6_localsid_sample_per_sid_memory_t)); - - /* Our brand-new car is ready */ - ls_mem->fib_table = table_id; - - /* Dont forget to add it to the localsid */ - *plugin_mem = ls_mem; - return 1; - } - return 0; -} - -/*************************/ -/* SRv6 LocalSID FIB DPO */ -static u8 * -format_srv6_localsid_sample_dpo (u8 * s, va_list * args) -{ - index_t index = va_arg (*args, index_t); - CLIB_UNUSED (u32 indent) = va_arg (*args, u32); - - return (format (s, "SR: localsid_sample_index:[%u]", index)); -} - -void -srv6_localsid_sample_dpo_lock (dpo_id_t * dpo) -{ -} - -void -srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo) -{ -} - -const static dpo_vft_t srv6_localsid_sample_vft = { - .dv_lock = srv6_localsid_sample_dpo_lock, - .dv_unlock = srv6_localsid_sample_dpo_unlock, - .dv_format = format_srv6_localsid_sample_dpo, -}; - -const static char *const srv6_localsid_sample_ip6_nodes[] = { - "srv6-localsid-sample", - NULL, -}; - -const static char *const *const srv6_localsid_sample_nodes[DPO_PROTO_NUM] = { - [DPO_PROTO_IP6] = srv6_localsid_sample_ip6_nodes, -}; - -/**********************/ -static clib_error_t * srv6_localsid_sample_init (vlib_main_t * vm) -{ - srv6_localsid_sample_main_t * sm = &srv6_localsid_sample_main; - int rv = 0; - /* Create DPO */ - sm->srv6_localsid_sample_dpo_type = dpo_register_new_type ( - &srv6_localsid_sample_vft, srv6_localsid_sample_nodes); - - /* Register SRv6 LocalSID */ - rv = sr_localsid_register_function (vm, - srv6_localsid_name, - keyword_str, - def_str, - params_str, - &sm->srv6_localsid_sample_dpo_type, - format_srv6_localsid_sample, - unformat_srv6_localsid_sample, - srv6_localsid_creation_fn, - srv6_localsid_removal_fn); - if (rv < 0) - clib_error_return (0, "SRv6 LocalSID function could not be registered."); - else - sm->srv6_localsid_behavior_id = rv; - - return 0; -} - -VLIB_INIT_FUNCTION (srv6_localsid_sample_init); - -VLIB_PLUGIN_REGISTER () = { - .version = "1.0", -}; diff --git a/src/plugins/srv6-localsid/srv6_localsid_sample.h b/src/plugins/srv6-localsid/srv6_localsid_sample.h deleted file mode 100644 index 474b5de2d49..00000000000 --- a/src/plugins/srv6-localsid/srv6_localsid_sample.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2015 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. - */ -#ifndef __included_srv6_localsid_sample_h__ -#define __included_srv6_localsid_sample_h__ - -#include -#include -#include -#include - -#include -#include -#include - -typedef struct { - /* API message ID base */ - u16 msg_id_base; - - /* convenience */ - vlib_main_t * vlib_main; - vnet_main_t * vnet_main; - - /* DPO type */ - dpo_type_t srv6_localsid_sample_dpo_type; - - /* SRv6 LocalSID behavior number */ - u32 srv6_localsid_behavior_id; - -} srv6_localsid_sample_main_t; - -/* - * This is the memory that will be stored per each localsid - * the user instantiates - */ -typedef struct { - u32 fib_table; /* Stupid index used as an example.. */ -} srv6_localsid_sample_per_sid_memory_t ; - -srv6_localsid_sample_main_t srv6_localsid_sample_main; - -format_function_t format_srv6_localsid_sample; -unformat_function_t unformat_srv6_localsid_sample; - -void srv6_localsid_sample_dpo_lock (dpo_id_t * dpo); -void srv6_localsid_sample_dpo_unlock (dpo_id_t * dpo); - -extern vlib_node_registration_t srv6_localsid_sample_node; - -#endif /* __included_sample_h__ */ diff --git a/src/plugins/srv6-localsid/srv6_sample_localsid_doc.md b/src/plugins/srv6-localsid/srv6_sample_localsid_doc.md deleted file mode 100644 index b60ab5da29f..00000000000 --- a/src/plugins/srv6-localsid/srv6_sample_localsid_doc.md +++ /dev/null @@ -1,38 +0,0 @@ -# SRv6 Sample LocalSID documentation {#srv6_plugin_doc} - -## Disclaimer - -This is a memo intended to contain documentation for the sample SRv6 LocalSID behavior plugin -Everything that is not directly obvious should come here. -For any feedback on content that should be explained please mailto:pcamaril@cisco.com - -This plugin refers to Segment Routing. Please read the SR documentation first. - -## Introduction - -This plugin is an example of how an user can create a new SRv6 LocalSID behavior by using VPP plugins with the appropiate API calls to the existing SR code. - -This **example** plugin registers a new localsid behavior, with cli keyword 'new_srv6_localsid' which only takes one parameter, a fib-table. Upon recival of a packet, this plugin will enforce the next IP6 lookup in the specific fib-table specified by the user. (Indeed it will do the lookup in the fib_table n+1 (since for the shake of the example we increment the fib-table.) - -Notice that the plugin only 'defines' a new SRv6 LocalSID behavior, but the existing SR code in VNET is the one actually instantiating new LocalSIDs. Notice that there are callback functions such that when you create or remove a LocalSID you can actually setup specific parameters through the functions in this plugin. - -## Variables to watch for - -* srv6_localsid_name: This variable is the name (used as a unique key) identifying this SR LocalSID plugin. -* keyword_str: This is the CLI keyword to be used for the plugin. In this example 'new_srv6_localsid'. (i.e. sr localsid address cafe::1 behavior new_srv6_localsid ) -* def_str: This is a definition of this SR behavior. This is printed when you do 'show sr localsid behaviors'. -* params_str: This is a definition of the parameters of this localsid. This is printed when you do 'show sr localsid behaviors'. - -## Functions to watch for - -* srv6_localsid_creation_fn: This function will be called every time a new SR LocalSID is instantiated with the behavior defined in this plugin. -* srv6_localsid_removal_fn: This function will be called every time a new SR LocalSID is removed with the behavior defined in this plugin. This function tends to be used for freeing up all the memory created in the previous function. -* format_srv6_localsid_sample: This function prints nicely the parameters of every SR LocalSID using this behavior. -* unformat_srv6_localsid_sample: This function parses the CLI command when initialising a new SR LocalSID using this behavior. It parses all the parameters and ensures that the parameters are correct. -* format_srv6_localsid_sample_dpo: This function formats the 'show ip6 fib' message for the SR LocalSIDs created with this plugin behavior. - -## Graph node - -The current graph node uses the function 'end_srh_processing' to do the Segment Routing Endpoint behavior. Notice that it does not allow the cleanup of a Segment Routing header (as per the SRv6 behavior specs). -This function is identical to the one found in /src/vnet/sr/sr_localsid.c -In case that by some other reason you want to do decapsulation, or SRH clean_up you can use the functions 'end_decaps_srh_processing' or 'end_psp_srh_processing' respectively. diff --git a/src/vnet/sr/sr.h b/src/vnet/sr/sr.h index 5efeb4dd06a..b832c0fc365 100755 --- a/src/vnet/sr/sr.h +++ b/src/vnet/sr/sr.h @@ -173,6 +173,7 @@ typedef struct } l2; }; u8 traffic_type; /**< Traffic type (IPv4, IPv6, L2) */ + u8 padding[3]; } sr_steering_key_t; typedef struct @@ -186,46 +187,29 @@ typedef struct */ typedef struct { - /* ip6-lookup next index for imposition FIB entries */ - u32 ip6_lookup_sr_next_index; - - /* ip6-replicate next index for multicast tunnel */ - u32 ip6_lookup_sr_spray_index; - - /* IP4-lookup -> SR rewrite next index */ - u32 ip4_lookup_sr_policy_rewrite_encaps_index; - u32 ip4_lookup_sr_policy_rewrite_insert_index; - - /* IP6-lookup -> SR rewrite next index */ - u32 ip6_lookup_sr_policy_rewrite_encaps_index; - u32 ip6_lookup_sr_policy_rewrite_insert_index; - /* L2-input -> SR rewrite next index */ u32 l2_sr_policy_rewrite_index; - /* IP6-lookup -> SR LocalSID (SR End processing) index */ - u32 ip6_lookup_sr_localsid_index; - /* SR SID lists */ ip6_sr_sl_t *sid_lists; /* SR policies */ ip6_sr_policy_t *sr_policies; - /* Find an SR policy by its BindingSID */ - ip6_address_t *sr_policy_index_by_key; + /* Hash table mapping BindingSID to SR policy */ + mhash_t sr_policies_index_hash; /* Pool of SR localsid instances */ ip6_sr_localsid_t *localsids; - /* Find a SR localsid instance based on its functionID */ - ip6_address_t *localsids_index_by_key; + /* Hash table mapping LOC:FUNC to SR LocalSID instance */ + mhash_t sr_localsids_index_hash; /* Pool of SR steer policies instances */ ip6_sr_steering_policy_t *steer_policies; - /* Find a steer policy based on its classifier */ - sr_steering_key_t *steer_policies_index_by_key; + /* Hash table mapping steering rules to SR steer instance */ + mhash_t sr_steer_policies_hash; /* L2 steering ifaces - sr_policies */ u32 *sw_iface_sr_policies; diff --git a/src/vnet/sr/sr_doc.md b/src/vnet/sr/sr_doc.md index a72206309af..fd92bdf2268 100644 --- a/src/vnet/sr/sr_doc.md +++ b/src/vnet/sr/sr_doc.md @@ -1,6 +1,6 @@ -# SRv6: Segment Routing for IPv6 {#sr_doc} +# SRv6: Segment Routing for IPv6 {#srv6_doc} -This is a memo intended to contain documentation of the VPP SRv6 implementation +This is a memo intended to contain documentation of the VPP SRv6 implementation. Everything that is not directly obvious should come here. For any feedback on content that should be explained please mailto:pcamaril@cisco.com @@ -27,135 +27,29 @@ Segment routing can operate with either an MPLS or an IPv6 data plane. All the c * Local SID: is a SID associated with a processing function on the local node, which may go from advancing to the next SID in the SRH, to complex user-defined behaviors. When a FIB lookup, either in the main FIB or in a specific VRF, returns a match on a local SID, the associated function is performed. * BindingSID: a BindingSID is a SID (only one) associated one-one with an SR Policy. If a packet arrives with an IPv6 DA corresponding to a BindingSID, then the SR policy will be applied to such packet. -## Creating an SR LocalSID +## SRv6 Features in VPP -A local SID is associated to a Segment Routing behavior -or function- on the current node. +The SRv6 Network Programming (*draft-filsfils-spring-srv6-network-programming*) defines the SRv6 architecture. -The most basic behavior is called END. It simply activates the next SID in the current packet, by decrementing the Segments Left value and updating the IPv6 DA. +VPP supports the following SRv6 LocalSID functions: End, End.X, End.DX6, End.DT6, End.DX4, End.DT4, End.DX2, End.B6, End.B6.Encaps. -A local END SID is instantiated using the following CLI: +For further information and how to configure each specific function: @subpage srv6_localsid_doc - sr localsid (del) address XX::YY behavior end -This creates a new entry in the main FIB for IPv6 address XX::YY. All packets whose IPv6 DA matches this FIB entry are redirected to the sr-localsid node, where they are processed as described above. +The Segment Routing Policy (*draft-filsfils-spring-segment-routing-policy*) defines SR Policies. -Other examples of local SIDs are the following: +VPP supports SRv6 Policies with T.Insert and T.Encaps behaviors. - sr localsid (del) address XX::YY behavior end (psp) - sr localsid (del) address XX::YY behavior end.x GE0/1/0 2001::a (psp) - sr localsid (del) address XX::YY behavior end.dx6 GE0/1/0 2001::a - sr localsid (del) address XX::YY behavior end.dx4 GE0/1/0 10.0.0.1 - sr localsid (del) address XX::YY behavior end.dx2 GigabitE0/11/0 - sr localsid (del) address XX::YY behavior end.dt6 5 - sr localsid (del) address XX::YY behavior end.dt6 5 +For further information on how to create SR Policies: @subpage srv6_policy_doc -Note that all of these behaviors match the specifications in **TODO REF NET PGM**. Please refer to this document for a detailed description of each behavior. +For further information on how to steer traffic into SR Policies: @subpage srv6_steering_doc -Help on the available local SID behaviors and their usage can be obtained with: - - help sr localsid +## SRv6 LocalSID development framework -Alternatively they can be obtained using. - - show sr localsids behavior - -The difference in between those two commands is that the first one will only display the SR LocalSID behaviors that are built-in VPP, while the latter will display those behaviors plus the ones added with the SR LocalSID Development Framework. - - -VPP keeps a 'My LocalSID Table' where it stores all the SR local SIDs instantiated as well as their parameters. Every time a new local SID is instantiated, a new entry is added to this table. In addition, counters for correctly and incorrectly processed traffic are maintained for each local SID. The counters store both the number of packets and bytes. - -The contents of the 'My LocalSID Table' is shown with: - - vpp# show sr localsid - SRv6 - My LocalSID Table: - ========================= - Address: c3::1 - Behavior: DX6 (Endpoint with decapsulation and IPv6 cross-connect) - Iface: GigabitEthernet0/5/0 - Next hop: b:c3::b - Good traffic: [51277 packets : 5332808 bytes] - Bad traffic: [0 packets : 0 bytes] - -------------------- - -The traffic counters can be reset with: - - vpp# clear sr localsid counters - -## Creating a SR Policy - -An SR Policy is defined by a Binding SID and a weighted set of Segment Lists. - -A new SR policy is created with a first SID list using: - - sr policy add bsid 2001::1 next A1:: next B1:: next C1:: (weight 5) (fib-table 3) - -* The weight parameter is only used if more than one SID list is associated with the policy. -* The fib-table parameter specifies in which table (VRF) the Binding SID is to be installed. - -An SR policy is deleted with: - - sr policy del bsid 2001::1 - sr policy del index 1 - -The existing SR policies are listed with: - - show sr policies - -### Adding/Removing SID Lists from an SR policy - -An additional SID list is associated with an existing SR policy with: - - sr policy mod bsid 2001::1 add sl next A2:: next B2:: next C2:: (weight 3) - sr policy mod index 3 add sl next A2:: next B2:: next C2:: (weight 3) - -Conversely, a SID list can be removed from an SR policy with: - - sr policy mod bsid 2001::1 del sl index 1 - sr policy mod index 3 del sl index 1 - -Note that this cannot be used to remove the last SID list of a policy. - -The weight of a SID list can also be modified with: - - sr policy mod bsid 2001::1 mod sl index 1 weight 4 - sr policy mod index 3 mod sl index 1 weight 4 - -### SR Policies: Spray policies - -Spray policies are a specific type of SR policies where the packet is replicated on all the SID lists, rather than load-balanced among them. - -SID list weights are ignored with this type of policies. - -A Spray policy is instantiated by appending the keyword **spray** to a regular SR policy command, as in: - - sr policy add bsid 2001::1 next A1:: next B1:: next C1:: spray - -Spray policies are used for removing multicast state from a network core domain, and instead send a linear unicast copy to every access node. The last SID in each list accesses the multicast tree within the access node. - -### Encapsulation SR policies - -In case the user decides to create an SR policy an IPv6 Source Address must be specified for the encapsulated traffic. In order to do so the user might use the following command: - - set sr encaps source addr XXXX::YYYY - -## Steering packets into a SR Policy - -To steer packets in Transit into an SR policy (T.Insert, T.Encaps and T.Encaps.L2 behaviors), the user needs to create an 'sr steering policy'. - - sr steer l3 2001::/64 via sr policy index 1 - sr steer l3 2001::/64 via sr policy bsid cafe::1 - sr steer l3 2001::/64 via sr policy bsid cafe::1 fib-table 3 - sr steer l3 10.0.0.0/16 via sr policy bsid cafe::1 - sr steer l2 TenGE0/1/0 via sr policy bsid cafe::1 - -Disclaimer: The T.Encaps.L2 will steer L2 frames into an SR Policy. Notice that creating an SR steering policy for L2 frames will actually automatically *puts the interface into promiscous mode*. - -## SR LocalSID development framework - -One of the * 'key' * concepts about SRv6 is regarding network programmability. This is why an SRv6 LocalSID is associated with an specific function. +One of the *'key'* concepts about SRv6 is network programmability. This is why an SRv6 LocalSID is associated with an specific function. However, the trully way to enable network programmability is allowing any developer **easily** create his own SRv6 LocalSID function. That is the reason why we have added some API calls such that any developer can code his own SRv6 LocalSID behaviors as plugins an add them to the running SRv6 code. The principle is that the developer only codes the behavior -the graph node-. However all the FIB handling, SR LocalSID instantiation and so on are done by the VPP SRv6 code. -For more information please refer to the documentation *SRv6 Sample SR LocalSID plugin*. +For more information please refer to: @subpage srv6_plugin_doc diff --git a/src/vnet/sr/sr_localsid.c b/src/vnet/sr/sr_localsid.c index 610bb7ffbea..2e3d56de80b 100755 --- a/src/vnet/sr/sr_localsid.c +++ b/src/vnet/sr/sr_localsid.c @@ -72,18 +72,16 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, int rv; ip6_sr_localsid_t *ls = 0; - ip6_address_t *key_copy; dpo_id_t dpo = DPO_INVALID; /* Search for the item */ - p = hash_get_mem (sm->localsids_index_by_key, localsid_addr); + p = mhash_get (&sm->sr_localsids_index_hash, localsid_addr); if (p) { if (is_del) { - hash_pair_t *hp; /* Retrieve localsid */ ls = pool_elt_at_index (sm->localsids, p[0]); /* Delete FIB entry */ @@ -116,10 +114,7 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, /* Delete localsid registry */ pool_put (sm->localsids, ls); - hp = hash_get_pair (sm->localsids_index_by_key, localsid_addr); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->localsids_index_by_key, localsid_addr); - vec_free (key_copy); + mhash_unset (&sm->sr_localsids_index_hash, localsid_addr, NULL); return 1; } else /* create with function already existing; complain */ @@ -232,9 +227,8 @@ sr_cli_localsid (char is_del, ip6_address_t * localsid_addr, } /* Set hash key for searching localsid by address */ - key_copy = vec_new (ip6_address_t, 1); - clib_memcpy (key_copy, localsid_addr, sizeof (ip6_address_t)); - hash_set_mem (sm->localsids_index_by_key, key_copy, ls - sm->localsids); + mhash_set (&sm->sr_localsids_index_hash, localsid_addr, ls - sm->localsids, + NULL); fib_table_entry_special_dpo_add (fib_index, &pfx, FIB_SOURCE_SR, FIB_ENTRY_FLAG_EXCLUSIVE, &dpo); @@ -1476,8 +1470,8 @@ sr_localsids_init (vlib_main_t * vm) { /* Init memory for function keys */ ip6_sr_main_t *sm = &sr_main; - sm->localsids_index_by_key = - hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword)); + mhash_init (&sm->sr_localsids_index_hash, sizeof (uword), + sizeof (ip6_address_t)); /* Init SR behaviors DPO type */ sr_localsid_dpo_type = dpo_register_new_type (&sr_loc_vft, sr_loc_nodes); /* Init SR behaviors DPO type */ diff --git a/src/vnet/sr/sr_localsid.md b/src/vnet/sr/sr_localsid.md new file mode 100644 index 00000000000..340af4a31b0 --- /dev/null +++ b/src/vnet/sr/sr_localsid.md @@ -0,0 +1,58 @@ +# SR LocalSIDs {#srv6_localsid_doc} + +A local SID is associated to a Segment Routing behavior -or function- on the current node. + +The most basic behavior is called END. It simply activates the next SID in the current packet, by decrementing the Segments Left value and updating the IPv6 DA. + +A local END SID is instantiated using the following CLI: + + sr localsid (del) address XX::YY behavior end + +This creates a new entry in the main FIB for IPv6 address XX::YY. All packets whose IPv6 DA matches this FIB entry are redirected to the sr-localsid node, where they are processed as described above. + +Other examples of local SIDs are the following: + + sr localsid (del) address XX::YY behavior end + sr localsid (del) address XX::YY behavior end.x GE0/1/0 2001::a + sr localsid (del) address XX::YY behavior end.dx6 GE0/1/0 2001::a + sr localsid (del) address XX::YY behavior end.dx4 GE0/1/0 10.0.0.1 + sr localsid (del) address XX::YY behavior end.dx2 GigabitE0/11/0 + sr localsid (del) address XX::YY behavior end.dt6 5 + sr localsid (del) address XX::YY behavior end.dt6 5 + +Note that all of these behaviors match the definitions of the SRv6 architecture (*draft-filsfils-spring-srv6-network-programming*). Please refer to this document for a detailed description of each behavior. + +Note also that you can configure the PSP flavor of the End and End.X behaviors by typing: + + sr localsid (del) address XX::YY behavior end psp + sr localsid (del) address XX::YY behavior end.x GE0/1/0 2001::a psp + +Help on the available local SID behaviors and their usage can be obtained with: + + help sr localsid + +Alternatively they can be obtained using. + + show sr localsids behavior + +The difference in between those two commands is that the first one will only display the SR LocalSID behaviors that are built-in VPP, while the latter will display those behaviors plus the ones added with the SR LocalSID Development Framework. + + +VPP keeps a 'My LocalSID Table' where it stores all the SR local SIDs instantiated as well as their parameters. Every time a new local SID is instantiated, a new entry is added to this table. In addition, counters for correctly and incorrectly processed traffic are maintained for each local SID. The counters store both the number of packets and bytes. + +The contents of the 'My LocalSID Table' is shown with: + + vpp# show sr localsid + SRv6 - My LocalSID Table: + ========================= + Address: c3::1 + Behavior: DX6 (Endpoint with decapsulation and IPv6 cross-connect) + Iface: GigabitEthernet0/5/0 + Next hop: b:c3::b + Good traffic: [51277 packets : 5332808 bytes] + Bad traffic: [0 packets : 0 bytes] + -------------------- + +The traffic counters can be reset with: + + vpp# clear sr localsid counters diff --git a/src/vnet/sr/sr_policy.md b/src/vnet/sr/sr_policy.md new file mode 100644 index 00000000000..521b84616c0 --- /dev/null +++ b/src/vnet/sr/sr_policy.md @@ -0,0 +1,56 @@ +# Creating a SR Policy {#srv6_policy_doc} + +An SR Policy is defined by a Binding SID and a weighted set of Segment Lists. + +A new SR policy is created with a first SID list using: + + sr policy add bsid 2001::1 next A1:: next B1:: next C1:: (weight 5) (fib-table 3) + +* The weight parameter is only used if more than one SID list is associated with the policy. +* The fib-table parameter specifies in which table (VRF) the Binding SID is to be installed. + +An SR policy is deleted with: + + sr policy del bsid 2001::1 + sr policy del index 1 + +The existing SR policies are listed with: + + show sr policies + +## Adding/Removing SID Lists from an SR policy + +An additional SID list is associated with an existing SR policy with: + + sr policy mod bsid 2001::1 add sl next A2:: next B2:: next C2:: (weight 3) + sr policy mod index 3 add sl next A2:: next B2:: next C2:: (weight 3) + +Conversely, a SID list can be removed from an SR policy with: + + sr policy mod bsid 2001::1 del sl index 1 + sr policy mod index 3 del sl index 1 + +Note that this cannot be used to remove the last SID list of a policy. + +The weight of a SID list can also be modified with: + + sr policy mod bsid 2001::1 mod sl index 1 weight 4 + sr policy mod index 3 mod sl index 1 weight 4 + +## SR Policies: Spray policies + +Spray policies are a specific type of SR policies where the packet is replicated on all the SID lists, rather than load-balanced among them. + +SID list weights are ignored with this type of policies. + +A Spray policy is instantiated by appending the keyword **spray** to a regular SR policy command, as in: + + sr policy add bsid 2001::1 next A1:: next B1:: next C1:: spray + +Spray policies are used for removing multicast state from a network core domain, and instead send a linear unicast copy to every access node. The last SID in each list accesses the multicast tree within the access node. + +## Encapsulation SR policies + +In case the user decides to create an SR policy an IPv6 Source Address must be specified for the encapsulated traffic. In order to do so the user might use the following command: + + set sr encaps source addr XXXX::YYYY diff --git a/src/vnet/sr/sr_policy_rewrite.c b/src/vnet/sr/sr_policy_rewrite.c index dfdd7950597..de6c1616704 100755 --- a/src/vnet/sr/sr_policy_rewrite.c +++ b/src/vnet/sr/sr_policy_rewrite.c @@ -349,6 +349,7 @@ update_lb (ip6_sr_policy_t * sr_policy) ip6_sr_sl_t *segment_list; ip6_sr_main_t *sm = &sr_main; load_balance_path_t path; + path.path_index = FIB_NODE_INDEX_INVALID; load_balance_path_t *ip4_path_vector = 0; load_balance_path_t *ip6_path_vector = 0; load_balance_path_t *b_path_vector = 0; @@ -447,6 +448,7 @@ update_replicate (ip6_sr_policy_t * sr_policy) ip6_sr_sl_t *segment_list; ip6_sr_main_t *sm = &sr_main; load_balance_path_t path; + path.path_index = FIB_NODE_INDEX_INVALID; load_balance_path_t *b_path_vector = 0; load_balance_path_t *ip6_path_vector = 0; load_balance_path_t *ip4_path_vector = 0; @@ -548,11 +550,10 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments, { ip6_sr_main_t *sm = &sr_main; ip6_sr_policy_t *sr_policy = 0; - ip6_address_t *key_copy; uword *p; /* Search for existing keys (BSID) */ - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) { /* Add SR policy that already exists; complain */ @@ -592,10 +593,8 @@ sr_policy_add (ip6_address_t * bsid, ip6_address_t * segments, sr_policy->is_encap = is_encap; /* Copy the key */ - key_copy = vec_new (ip6_address_t, 1); - clib_memcpy (key_copy, bsid, sizeof (ip6_address_t)); - hash_set_mem (sm->sr_policy_index_by_key, key_copy, - sr_policy - sm->sr_policies); + mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies, + NULL); /* Create a segment list and add the index to the SR policy */ create_sl (sr_policy, segments, weight, is_encap); @@ -635,14 +634,12 @@ sr_policy_del (ip6_address_t * bsid, u32 index) ip6_sr_main_t *sm = &sr_main; ip6_sr_policy_t *sr_policy = 0; ip6_sr_sl_t *segment_list; - ip6_address_t *key_copy; u32 *sl_index; uword *p; - hash_pair_t *hp; if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -692,14 +689,11 @@ sr_policy_del (ip6_address_t * bsid, u32 index) } /* Remove SR policy entry */ - hp = hash_get_pair (sm->sr_policy_index_by_key, &sr_policy->bsid); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->sr_policy_index_by_key, &sr_policy->bsid); - vec_free (key_copy); + mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL); pool_put (sm->sr_policies, sr_policy); /* If FIB empty unlock it */ - if (!pool_elts (sm->sr_policies)) + if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies)) { fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6); fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6); @@ -741,7 +735,7 @@ sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table, if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -3208,8 +3202,8 @@ sr_policy_rewrite_init (vlib_main_t * vm) ip6_sr_main_t *sm = &sr_main; /* Init memory for sr policy keys (bsid <-> ip6_address_t) */ - sm->sr_policy_index_by_key = hash_create_mem (0, sizeof (ip6_address_t), - sizeof (uword)); + mhash_init (&sm->sr_policies_index_hash, sizeof (uword), + sizeof (ip6_address_t)); /* Init SR VPO DPOs type */ sr_pr_encaps_dpo_type = diff --git a/src/vnet/sr/sr_steering.c b/src/vnet/sr/sr_steering.c index 86d6f27cbe1..be1bb7ade29 100755 --- a/src/vnet/sr/sr_steering.c +++ b/src/vnet/sr/sr_steering.c @@ -62,14 +62,14 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, u32 sw_if_index, u8 traffic_type) { ip6_sr_main_t *sm = &sr_main; - sr_steering_key_t key, *key_copy; + sr_steering_key_t key; ip6_sr_steering_policy_t *steer_pl; fib_prefix_t pfx = { 0 }; ip6_sr_policy_t *sr_policy = 0; uword *p = 0; - hash_pair_t *hp; + memset (&key, 0, sizeof (sr_steering_key_t)); /* Compute the steer policy key */ if (prefix) @@ -78,6 +78,8 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, key.l3.prefix.as_u64[1] = prefix->as_u64[1]; key.l3.mask_width = mask_width; key.l3.fib_table = (table_id != (u32) ~ 0 ? table_id : 0); + if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6) + return -1; } else { @@ -92,12 +94,14 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, vnet_get_sw_interface (sm->vnet_main, sw_if_index); if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE) return -3; + if (traffic_type != SR_STEER_L2) + return -1; } key.traffic_type = traffic_type; /* Search for the item */ - p = hash_get_mem (sm->steer_policies_index_by_key, &key); + p = mhash_get (&sm->sr_steer_policies_hash, &key); if (p) { @@ -152,10 +156,17 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Delete SR steering policy entry */ pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); + + /* If no more SR policies or steering policies */ + if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies)) + { + fib_table_unlock (sm->fib_table_ip6, FIB_PROTOCOL_IP6); + fib_table_unlock (sm->fib_table_ip4, FIB_PROTOCOL_IP6); + sm->fib_table_ip6 = (u32) ~ 0; + sm->fib_table_ip4 = (u32) ~ 0; + } + return 1; } else /* It means user requested to update an existing SR steering policy */ @@ -163,7 +174,7 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Retrieve SR steering policy */ if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -192,7 +203,6 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Create a new one */ goto update_fib; - } else if (steer_pl->classify.traffic_type == SR_STEER_IPV4) { @@ -224,7 +234,7 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, /* Retrieve SR policy */ if (bsid) { - p = hash_get_mem (sm->sr_policy_index_by_key, bsid); + p = mhash_get (&sm->sr_policies_index_hash, bsid); if (p) sr_policy = pool_elt_at_index (sm->sr_policies, p[0]); else @@ -255,19 +265,14 @@ sr_steering_policy (int is_del, ip6_address_t * bsid, u32 sr_policy_index, { /* Incorrect API usage. Should never get here */ pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); return -1; } steer_pl->sr_policy = sr_policy - sm->sr_policies; /* Create and store key */ - key_copy = vec_new (sr_steering_key_t, 1); - clib_memcpy (key_copy, &key, sizeof (sr_steering_key_t)); - hash_set_mem (sm->steer_policies_index_by_key, - key_copy, steer_pl - sm->steer_policies); + mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies, + NULL); if (traffic_type == SR_STEER_L2) { @@ -345,18 +350,12 @@ update_fib: cleanup_error_encap: pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); return -5; cleanup_error_redirection: pool_put (sm->steer_policies, steer_pl); - hp = hash_get_pair (sm->steer_policies_index_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (sm->steer_policies_index_by_key, &key); - vec_free (key_copy); + mhash_unset (&sm->sr_steer_policies_hash, &key, NULL); return -3; } @@ -379,6 +378,8 @@ sr_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, u8 sr_policy_set = 0; + memset (&prefix, 0, sizeof (ip46_address_t)); + int rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -450,7 +451,7 @@ sr_steer_policy_command_fn (vlib_main_t * vm, unformat_input_t * input, "Unable to do SW redirect. Incorrect interface."); case -4: return clib_error_return (0, - "The requested SR policy could not be deleted. Review the BSID/index."); + "The requested SR steering policy could not be deleted."); case -5: return clib_error_return (0, "The SR policy is not an encapsulation one."); @@ -541,8 +542,8 @@ sr_steering_init (vlib_main_t * vm) ip6_sr_main_t *sm = &sr_main; /* Init memory for function keys */ - sm->steer_policies_index_by_key = - hash_create_mem (0, sizeof (sr_steering_key_t), sizeof (uword)); + mhash_init (&sm->sr_steer_policies_hash, sizeof (uword), + sizeof (sr_steering_key_t)); sm->sw_iface_sr_policies = 0; diff --git a/src/vnet/sr/sr_steering.md b/src/vnet/sr/sr_steering.md new file mode 100644 index 00000000000..cf446f8171e --- /dev/null +++ b/src/vnet/sr/sr_steering.md @@ -0,0 +1,11 @@ +# Steering packets into a SR Policy {#srv6_steering_doc} + +To steer packets in Transit into an SR policy (T.Insert, T.Encaps and T.Encaps.L2 behaviors), the user needs to create an 'sr steering policy'. + + sr steer l3 2001::/64 via sr policy index 1 + sr steer l3 2001::/64 via sr policy bsid cafe::1 + sr steer l3 2001::/64 via sr policy bsid cafe::1 fib-table 3 + sr steer l3 10.0.0.0/16 via sr policy bsid cafe::1 + sr steer l2 TenGE0/1/0 via sr policy bsid cafe::1 + +Disclaimer: The T.Encaps.L2 will steer L2 frames into an SR Policy. Notice that creating an SR steering policy for L2 frames will actually automatically *put the interface into promiscous mode*. -- cgit 1.2.3-korg