From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vppinfra/format.h | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 src/vppinfra/format.h (limited to 'src/vppinfra/format.h') diff --git a/src/vppinfra/format.h b/src/vppinfra/format.h new file mode 100644 index 00000000..bc0d6d15 --- /dev/null +++ b/src/vppinfra/format.h @@ -0,0 +1,331 @@ +/* + * 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. + */ +/* + Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef included_format_h +#define included_format_h + +#include + +#include /* for CLIB_UNIX, etc. */ +#include +#include /* for ASSERT */ +#include + +typedef u8 *(format_function_t) (u8 * s, va_list * args); + +u8 *va_format (u8 * s, const char *format, va_list * args); +u8 *format (u8 * s, const char *format, ...); + +#ifdef CLIB_UNIX + +#include + +#else /* ! CLIB_UNIX */ + +/* We're not Unix and have not stdio.h */ +#define FILE void +#define stdin ((FILE *) 0) +#define stdout ((FILE *) 1) +#define stderr ((FILE *) 2) + +#endif + +word va_fformat (FILE * f, char *fmt, va_list * va); +word fformat (FILE * f, char *fmt, ...); +word fdformat (int fd, char *fmt, ...); + +always_inline uword +format_get_indent (u8 * s) +{ + uword indent = 0; + u8 *nl; + + if (!s) + return indent; + + nl = vec_end (s) - 1; + while (nl >= s) + { + if (*nl-- == '\n') + break; + indent++; + } + return indent; +} + +#define _(f) u8 * f (u8 * s, va_list * va) + +/* Standard user-defined formats. */ +_(format_vec32); +_(format_vec_uword); +_(format_ascii_bytes); +_(format_hex_bytes); +_(format_white_space); +_(format_f64); +_(format_time_interval); + +#ifdef CLIB_UNIX +/* Unix specific formats. */ +_(format_address_family); +_(format_unix_arphrd); +_(format_unix_interface_flags); +_(format_network_address); +_(format_network_protocol); +_(format_network_port); +_(format_sockaddr); +_(format_ip4_tos_byte); +_(format_ip4_packet); +_(format_icmp4_type_and_code); +_(format_ethernet_packet); +_(format_hostname); +_(format_timeval); +_(format_time_float); +_(format_signal); +_(format_ucontext_pc); +#endif + +#undef _ + +/* Unformat. */ + +typedef struct _unformat_input_t +{ + /* Input buffer (vector). */ + u8 *buffer; + + /* Current index in input buffer. */ + uword index; + + /* Vector of buffer marks. Used to delineate pieces of the buffer + for error reporting and for parse recovery. */ + uword *buffer_marks; + + /* User's function to fill the buffer when its empty + (and argument). */ + uword (*fill_buffer) (struct _unformat_input_t * i); + + /* Return values for fill buffer function which indicate whether not + input has been exhausted. */ +#define UNFORMAT_END_OF_INPUT (~0) +#define UNFORMAT_MORE_INPUT 0 + + /* User controlled argument to fill buffer function. */ + void *fill_buffer_arg; +} unformat_input_t; + +always_inline void +unformat_init (unformat_input_t * i, + uword (*fill_buffer) (unformat_input_t *), + void *fill_buffer_arg) +{ + memset (i, 0, sizeof (i[0])); + i->fill_buffer = fill_buffer; + i->fill_buffer_arg = fill_buffer_arg; +} + +always_inline void +unformat_free (unformat_input_t * i) +{ + vec_free (i->buffer); + vec_free (i->buffer_marks); + memset (i, 0, sizeof (i[0])); +} + +always_inline uword +unformat_check_input (unformat_input_t * i) +{ + /* Low level fill input function. */ + extern uword _unformat_fill_input (unformat_input_t * i); + + if (i->index >= vec_len (i->buffer) && i->index != UNFORMAT_END_OF_INPUT) + _unformat_fill_input (i); + + return i->index; +} + +/* Return true if input is exhausted */ +always_inline uword +unformat_is_eof (unformat_input_t * input) +{ + return unformat_check_input (input) == UNFORMAT_END_OF_INPUT; +} + +/* Return next element in input vector, + possibly calling fill input to get more. */ +always_inline uword +unformat_get_input (unformat_input_t * input) +{ + uword i = unformat_check_input (input); + if (i < vec_len (input->buffer)) + { + input->index = i + 1; + i = input->buffer[i]; + } + return i; +} + +/* Back up input pointer by one. */ +always_inline void +unformat_put_input (unformat_input_t * input) +{ + input->index -= 1; +} + +/* Peek current input character without advancing. */ +always_inline uword +unformat_peek_input (unformat_input_t * input) +{ + uword c = unformat_get_input (input); + if (c != UNFORMAT_END_OF_INPUT) + unformat_put_input (input); + return c; +} + +/* Skip current input line. */ +always_inline void +unformat_skip_line (unformat_input_t * i) +{ + uword c; + + while ((c = unformat_get_input (i)) != UNFORMAT_END_OF_INPUT && c != '\n') + ; +} + +uword unformat_skip_white_space (unformat_input_t * input); + +/* Unformat function. */ +typedef uword (unformat_function_t) (unformat_input_t * input, + va_list * args); + +/* External functions. */ + +/* General unformatting function with programmable input stream. */ +uword unformat (unformat_input_t * i, char *fmt, ...); + +/* Call user defined parse function. + unformat_user (i, f, ...) is equivalent to unformat (i, "%U", f, ...) */ +uword unformat_user (unformat_input_t * input, unformat_function_t * func, + ...); + +/* Alternate version which allows for extensions. */ +uword va_unformat (unformat_input_t * i, char *fmt, va_list * args); + +/* Setup for unformat of Unix style command line. */ +void unformat_init_command_line (unformat_input_t * input, char *argv[]); + +/* Setup for unformat of given string. */ +void unformat_init_string (unformat_input_t * input, + char *string, int string_len); + +always_inline void +unformat_init_cstring (unformat_input_t * input, char *string) +{ + unformat_init_string (input, string, strlen (string)); +} + +/* Setup for unformat of given vector string; vector will be freed by unformat_string. */ +void unformat_init_vector (unformat_input_t * input, u8 * vector_string); + +/* Format function for unformat input usable when an unformat error + has occurred. */ +u8 *format_unformat_error (u8 * s, va_list * va); + +#define unformat_parse_error(input) \ + clib_error_return (0, "parse error `%U'", format_unformat_error, input) + +/* Print all input: not just error context. */ +u8 *format_unformat_input (u8 * s, va_list * va); + +/* Unformat (parse) function which reads a %s string and converts it + to and unformat_input_t. */ +unformat_function_t unformat_input; + +/* Parse a line ending with \n and return it. */ +unformat_function_t unformat_line; + +/* Parse a line ending with \n and return it as an unformat_input_t. */ +unformat_function_t unformat_line_input; + +/* Parse a token containing given set of characters. */ +unformat_function_t unformat_token; + +/* Parses a hexstring into a vector of bytes. */ +unformat_function_t unformat_hex_string; + +/* Returns non-zero match if input is exhausted. + Useful to ensure that the entire input matches with no trailing junk. */ +unformat_function_t unformat_eof; + +/* Parse memory size e.g. 100, 100k, 100m, 100g. */ +unformat_function_t unformat_memory_size; + +/* Unparse memory size e.g. 100, 100k, 100m, 100g. */ +u8 *format_memory_size (u8 * s, va_list * va); + +/* Format c identifier: e.g. a_name -> "a name". */ +u8 *format_c_identifier (u8 * s, va_list * va); + +/* Format hexdump with both hex and printable chars - compatible with text2pcap */ +u8 *format_hexdump (u8 * s, va_list * va); + +/* Unix specific formats. */ +#ifdef CLIB_UNIX +/* Setup input from Unix file. */ +void unformat_init_unix_file (unformat_input_t * input, int file_descriptor); + +/* Take input from Unix environment variable; returns + 1 if variable exists zero otherwise. */ +uword unformat_init_unix_env (unformat_input_t * input, char *var); +#endif /* CLIB_UNIX */ + +/* Test code. */ +int test_format_main (unformat_input_t * input); +int test_unformat_main (unformat_input_t * input); + +/* This is not the right place for this, but putting it in vec.h +created circular dependency problems. */ +int test_vec_main (unformat_input_t * input); + +#endif /* included_format_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 32e1c010b0c34fd0984f7fc45fae648a182025c5 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 22 Nov 2016 17:07:28 +0000 Subject: IP Multicast FIB (mfib) - IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match - Replication represented via a new replicate DPO. - RPF configuration and data-plane checking - data-plane signals sent to listening control planes. The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast. 'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests. Updated applications to use the new MIFB functions; - IPv6 NS/RA. - DHCPv6 unit tests for these are undated accordingly. Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961 Signed-off-by: Neale Ranns --- src/scripts/vnet/mcast/ip4 | 22 + src/vat/api_format.c | 173 +++++ src/vnet.am | 35 +- src/vnet/adj/adj.c | 11 +- src/vnet/adj/adj.h | 1 - src/vnet/adj/adj_internal.h | 2 + src/vnet/adj/adj_mcast.c | 346 ++++++++++ src/vnet/adj/adj_mcast.h | 78 +++ src/vnet/adj/adj_nbr.c | 2 +- src/vnet/adj/adj_rewrite.c | 53 -- src/vnet/adj/adj_rewrite.h | 49 -- src/vnet/dhcpv6/proxy_node.c | 46 +- src/vnet/dpo/dpo.c | 2 + src/vnet/dpo/dpo.h | 8 +- src/vnet/dpo/load_balance.c | 13 +- src/vnet/dpo/load_balance.h | 8 + src/vnet/dpo/replicate_dpo.c | 759 ++++++++++++++++++++++ src/vnet/dpo/replicate_dpo.h | 143 +++++ src/vnet/ethernet/arp.c | 84 ++- src/vnet/ethernet/ethernet.h | 2 + src/vnet/ethernet/interface.c | 20 + src/vnet/fib/fib_attached_export.c | 4 +- src/vnet/fib/fib_entry.h | 2 +- src/vnet/fib/fib_entry_delegate.c | 3 + src/vnet/fib/fib_entry_src.c | 4 + src/vnet/fib/fib_node.h | 2 + src/vnet/fib/fib_path.c | 91 ++- src/vnet/fib/fib_path_list.c | 9 +- src/vnet/fib/fib_path_list.h | 6 + src/vnet/fib/fib_table.c | 69 +- src/vnet/fib/fib_table.h | 16 + src/vnet/fib/fib_test.c | 207 +++--- src/vnet/fib/fib_types.c | 4 + src/vnet/fib/fib_types.h | 14 + src/vnet/fib/fib_urpf_list.c | 20 +- src/vnet/fib/ip4_fib.c | 50 +- src/vnet/fib/ip4_fib.h | 9 + src/vnet/fib/ip6_fib.c | 117 ++-- src/vnet/fib/ip6_fib.h | 11 +- src/vnet/fib/mpls_fib.c | 17 +- src/vnet/fib/mpls_fib.h | 9 + src/vnet/ip/ip.api | 53 ++ src/vnet/ip/ip4.h | 24 + src/vnet/ip/ip4_forward.c | 498 +++++---------- src/vnet/ip/ip4_input.c | 4 +- src/vnet/ip/ip6.h | 27 + src/vnet/ip/ip6_forward.c | 83 ++- src/vnet/ip/ip6_input.c | 43 +- src/vnet/ip/ip6_neighbor.c | 134 ++-- src/vnet/ip/ip_api.c | 210 +++++++ src/vnet/ip/lookup.c | 171 +++++ src/vnet/ip/lookup.h | 82 +-- src/vnet/mcast/mcast.c | 565 ----------------- src/vnet/mcast/mcast.h | 50 -- src/vnet/mcast/mcast_test.c | 149 ----- src/vnet/mfib/ip4_mfib.c | 465 ++++++++++++++ src/vnet/mfib/ip4_mfib.h | 95 +++ src/vnet/mfib/ip6_mfib.c | 663 +++++++++++++++++++ src/vnet/mfib/ip6_mfib.h | 109 ++++ src/vnet/mfib/mfib_entry.c | 1096 ++++++++++++++++++++++++++++++++ src/vnet/mfib/mfib_entry.h | 172 +++++ src/vnet/mfib/mfib_forward.c | 512 +++++++++++++++ src/vnet/mfib/mfib_itf.c | 119 ++++ src/vnet/mfib/mfib_itf.h | 63 ++ src/vnet/mfib/mfib_signal.c | 201 ++++++ src/vnet/mfib/mfib_signal.h | 59 ++ src/vnet/mfib/mfib_table.c | 489 ++++++++++++++ src/vnet/mfib/mfib_table.h | 331 ++++++++++ src/vnet/mfib/mfib_test.c | 1225 ++++++++++++++++++++++++++++++++++++ src/vnet/mfib/mfib_types.c | 213 +++++++ src/vnet/mfib/mfib_types.h | 185 ++++++ src/vnet/misc.c | 3 + src/vnet/rewrite.h | 31 + src/vnet/sr/sr.c | 4 +- src/vnet/util/radix.c | 1104 ++++++++++++++++++++++++++++++++ src/vnet/util/radix.h | 147 +++++ src/vnet/vxlan/vxlan.c | 112 +++- src/vpp/api/api.c | 14 +- src/vppinfra.am | 2 +- src/vppinfra/dlist.h | 2 +- src/vppinfra/format.c | 8 +- src/vppinfra/format.h | 4 +- src/vppinfra/unformat.c | 16 +- test/test_dhcp.py | 16 - test/test_ip6.py | 131 ++-- test/test_ip_mcast.py | 612 ++++++++++++++++++ test/test_mfib.py | 23 + test/vpp_interface.py | 3 +- test/vpp_ip_route.py | 101 ++- test/vpp_papi_provider.py | 34 +- 90 files changed, 11211 insertions(+), 1767 deletions(-) create mode 100644 src/scripts/vnet/mcast/ip4 create mode 100644 src/vnet/adj/adj_mcast.c create mode 100644 src/vnet/adj/adj_mcast.h delete mode 100644 src/vnet/adj/adj_rewrite.c delete mode 100644 src/vnet/adj/adj_rewrite.h create mode 100644 src/vnet/dpo/replicate_dpo.c create mode 100644 src/vnet/dpo/replicate_dpo.h delete mode 100644 src/vnet/mcast/mcast.c delete mode 100644 src/vnet/mcast/mcast.h delete mode 100644 src/vnet/mcast/mcast_test.c create mode 100644 src/vnet/mfib/ip4_mfib.c create mode 100644 src/vnet/mfib/ip4_mfib.h create mode 100644 src/vnet/mfib/ip6_mfib.c create mode 100644 src/vnet/mfib/ip6_mfib.h create mode 100644 src/vnet/mfib/mfib_entry.c create mode 100644 src/vnet/mfib/mfib_entry.h create mode 100644 src/vnet/mfib/mfib_forward.c create mode 100644 src/vnet/mfib/mfib_itf.c create mode 100644 src/vnet/mfib/mfib_itf.h create mode 100644 src/vnet/mfib/mfib_signal.c create mode 100644 src/vnet/mfib/mfib_signal.h create mode 100644 src/vnet/mfib/mfib_table.c create mode 100644 src/vnet/mfib/mfib_table.h create mode 100644 src/vnet/mfib/mfib_test.c create mode 100644 src/vnet/mfib/mfib_types.c create mode 100644 src/vnet/mfib/mfib_types.h create mode 100644 src/vnet/util/radix.c create mode 100644 src/vnet/util/radix.h create mode 100644 test/test_ip_mcast.py create mode 100644 test/test_mfib.py (limited to 'src/vppinfra/format.h') diff --git a/src/scripts/vnet/mcast/ip4 b/src/scripts/vnet/mcast/ip4 new file mode 100644 index 00000000..69f1ee00 --- /dev/null +++ b/src/scripts/vnet/mcast/ip4 @@ -0,0 +1,22 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 232.1.1.1 + ICMP echo_request + incrementing 100 + } +} + +trace add pg-input 100 +loop create +loop create +set int state loop0 up +set int state loop1 up + +ip mroute add 232.1.1.1 via pg0 Accept +ip mroute add 232.1.1.1 via loop0 Forward +ip mroute add 232.1.1.1 via loop1 Forward diff --git a/src/vat/api_format.c b/src/vat/api_format.c index b83313de..4cfe4a58 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "vat/json_format.h" @@ -505,6 +506,53 @@ unformat_flow_classify_table_type (unformat_input_t * input, va_list * va) return 1; } +static const char *mfib_flag_names[] = MFIB_ENTRY_NAMES_SHORT; +static const char *mfib_flag_long_names[] = MFIB_ENTRY_NAMES_LONG; +static const char *mfib_itf_flag_long_names[] = MFIB_ITF_NAMES_LONG; +static const char *mfib_itf_flag_names[] = MFIB_ITF_NAMES_SHORT; + +uword +unformat_mfib_itf_flags (unformat_input_t * input, va_list * args) +{ + mfib_itf_flags_t old, *iflags = va_arg (*args, mfib_itf_flags_t *); + mfib_itf_attribute_t attr; + + old = *iflags; + FOR_EACH_MFIB_ITF_ATTRIBUTE (attr) + { + if (unformat (input, mfib_itf_flag_long_names[attr])) + *iflags |= (1 << attr); + } + FOR_EACH_MFIB_ITF_ATTRIBUTE (attr) + { + if (unformat (input, mfib_itf_flag_names[attr])) + *iflags |= (1 << attr); + } + + return (old == *iflags ? 0 : 1); +} + +uword +unformat_mfib_entry_flags (unformat_input_t * input, va_list * args) +{ + mfib_entry_flags_t old, *eflags = va_arg (*args, mfib_entry_flags_t *); + mfib_entry_attribute_t attr; + + old = *eflags; + FOR_EACH_MFIB_ATTRIBUTE (attr) + { + if (unformat (input, mfib_flag_long_names[attr])) + *eflags |= (1 << attr); + } + FOR_EACH_MFIB_ATTRIBUTE (attr) + { + if (unformat (input, mfib_flag_names[attr])) + *eflags |= (1 << attr); + } + + return (old == *eflags ? 0 : 1); +} + #if (VPP_API_TEST_BUILTIN==0) u8 * format_ip4_address (u8 * s, va_list * args) @@ -3592,6 +3640,7 @@ _(bridge_domain_add_del_reply) \ _(sw_interface_set_l2_xconnect_reply) \ _(l2fib_add_del_reply) \ _(ip_add_del_route_reply) \ +_(ip_mroute_add_del_reply) \ _(mpls_route_add_del_reply) \ _(mpls_ip_bind_unbind_reply) \ _(proxy_arp_add_del_reply) \ @@ -3792,6 +3841,7 @@ _(TAP_MODIFY_REPLY, tap_modify_reply) \ _(TAP_DELETE_REPLY, tap_delete_reply) \ _(SW_INTERFACE_TAP_DETAILS, sw_interface_tap_details) \ _(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \ +_(IP_MROUTE_ADD_DEL_REPLY, ip_mroute_add_del_reply) \ _(MPLS_ROUTE_ADD_DEL_REPLY, mpls_route_add_del_reply) \ _(MPLS_IP_BIND_UNBIND_REPLY, mpls_ip_bind_unbind_reply) \ _(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \ @@ -6383,6 +6433,126 @@ api_ip_add_del_route (vat_main_t * vam) return (vam->retval); } +static int +api_ip_mroute_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_mroute_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0, vrf_id = 0; + u8 is_ipv6 = 0; + u8 is_local = 0; + u8 create_vrf_if_needed = 0; + u8 is_add = 1; + u8 address_set = 0; + u32 grp_address_length = 0; + ip4_address_t v4_grp_address, v4_src_address; + ip6_address_t v6_grp_address, v6_src_address; + mfib_itf_flags_t iflags = 0; + mfib_entry_flags_t eflags = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%U %U", + unformat_ip4_address, &v4_src_address, + unformat_ip4_address, &v4_grp_address)) + { + grp_address_length = 64; + address_set = 1; + is_ipv6 = 0; + } + else if (unformat (i, "%U %U", + unformat_ip6_address, &v6_src_address, + unformat_ip6_address, &v6_grp_address)) + { + grp_address_length = 256; + address_set = 1; + is_ipv6 = 1; + } + else if (unformat (i, "%U", unformat_ip4_address, &v4_grp_address)) + { + memset (&v4_src_address, 0, sizeof (v4_src_address)); + grp_address_length = 32; + address_set = 1; + is_ipv6 = 0; + } + else if (unformat (i, "%U", unformat_ip6_address, &v6_grp_address)) + { + memset (&v6_src_address, 0, sizeof (v6_src_address)); + grp_address_length = 128; + address_set = 1; + is_ipv6 = 1; + } + else if (unformat (i, "/%d", &grp_address_length)) + ; + else if (unformat (i, "local")) + { + is_local = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "create-vrf")) + create_vrf_if_needed = 1; + else if (unformat (i, "%U", unformat_mfib_itf_flags, &iflags)) + ; + else if (unformat (i, "%U", unformat_mfib_entry_flags, &eflags)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (address_set == 0) + { + errmsg ("missing addresses\n"); + return -99; + } + + /* Construct the API message */ + M (IP_MROUTE_ADD_DEL, ip_mroute_add_del); + + mp->next_hop_sw_if_index = ntohl (sw_if_index); + mp->table_id = ntohl (vrf_id); + mp->create_vrf_if_needed = create_vrf_if_needed; + + mp->is_add = is_add; + mp->is_ipv6 = is_ipv6; + mp->is_local = is_local; + mp->itf_flags = ntohl (iflags); + mp->entry_flags = ntohl (eflags); + mp->grp_address_length = grp_address_length; + mp->grp_address_length = ntohs (mp->grp_address_length); + + if (is_ipv6) + { + clib_memcpy (mp->grp_address, &v6_grp_address, sizeof (v6_grp_address)); + clib_memcpy (mp->src_address, &v6_src_address, sizeof (v6_src_address)); + } + else + { + clib_memcpy (mp->grp_address, &v4_grp_address, sizeof (v4_grp_address)); + clib_memcpy (mp->src_address, &v4_src_address, sizeof (v4_src_address)); + + } + + /* send it... */ + S; + /* Wait for a reply... */ + W; + + /* Return the good/bad news */ + return (vam->retval); +} + static int api_mpls_route_add_del (vat_main_t * vam) { @@ -17512,6 +17682,9 @@ _(ip_add_del_route, \ "[ | sw_if_index ] [resolve-attempts ]\n" \ "[weight ] [drop] [local] [classify ] [del]\n" \ "[multipath] [count ]") \ +_(ip_mroute_add_del, \ + " / [table-id ]\n" \ + "[ | sw_if_index ] [local] [del]") \ _(mpls_route_add_del, \ "