- Encap/Decap flags to control the copying of DSCP, ECN, DF from overlay to
underlay and vice-versa.
- L2 tunnels
-missing:
- - GRE keys
+ - GRE keys for IPv4 and IPv6
description: "An implementation of Generic Routing Encapsulation (GRE)"
state: production
properties: [API, CLI, MULTITHREAD]
import "vnet/tunnel/tunnel_types.api";
import "vnet/ip/ip_types.api";
+/* Enable the in-progress messages */
+option status = "in_progress";
+
+/*
+ * Define the service relationships
+ */
+service {
+ rpc gre_tunnel_dump returns gre_tunnel_dump_reply events gre_tunnel_details;
+ rpc gre_tunnel_dump_v2 returns gre_tunnel_dump_v2_reply events gre_tunnel_details_v2;
+};
+
/** \brief A GRE tunnel type
*/
enum gre_tunnel_type : u8
vl_api_address_t dst;
};
+/** \brief A composite type uniquely defining a GRE tunnel with key support.
+ @param type - tunnel type (see enum definition), 0: L3, 1: TEB, 2: ERSPAN
+ @param mode - P2P or P2MP
+ @param flags - to control encap/decap behaviour
+ @param session_id - session for ERSPAN tunnel, range 0-1023
+ @param instance - optional unique custom device instance, else ~0.
+ @param outer_table_id - Encap FIB table ID
+ @param sw_if_index - ignored on create/delete, present in details.
+ @param src - Source IP address
+ @param dst - Destination IP address, can be multicast
+ @param key - GRE key value (RFC 2890), 0 for no key
+*/
+typedef gre_tunnel_v2
+{
+ vl_api_gre_tunnel_type_t type;
+ vl_api_tunnel_mode_t mode;
+ vl_api_tunnel_encap_decap_flags_t flags;
+ u16 session_id;
+ u32 instance;
+ u32 outer_table_id;
+ vl_api_interface_index_t sw_if_index;
+ vl_api_address_t src;
+ vl_api_address_t dst;
+ u32 key;
+};
+
/** \brief Add or delete a single GRE tunnel.
@param client_index - opaque cookie to identify the sender.
@param context - sender context, to match reply w/ request.
vl_api_interface_index_t sw_if_index;
};
+/** \brief Add or delete a single GRE tunnel with key support.
+ @param client_index - opaque cookie to identify the sender.
+ @param context - sender context, to match reply w/ request.
+ @param is_add - add if true, delete if false.
+ @param tunnel - tunnel definition to add or delete (with key field).
+*/
+define gre_tunnel_add_del_v2
+{
+ u32 client_index;
+ u32 context;
+ bool is_add;
+ vl_api_gre_tunnel_v2_t tunnel;
+};
+
+/** \brief Add or delete a single GRE tunnel with key support.
+ @param context - sender context, to match reply w/ request.
+ @param retval - return code for the request.
+ @param sw_if_index - the interface corresponding to the affected tunnel.
+*/
+define gre_tunnel_add_del_v2_reply
+{
+ u32 context;
+ i32 retval;
+ vl_api_interface_index_t sw_if_index;
+};
+
/** \brief Dump details of all or just a single GRE tunnel.
@param client_index - opaque cookie to identify the sender.
@param context - sender context, to match reply w/ request.
vl_api_interface_index_t sw_if_index;
};
+/** \brief Reply for gre_tunnel_dump - empty since actual data is sent via gre_tunnel_details.
+ @param context - sender context, to match reply w/ request.
+ @param retval - return code for the request.
+*/
+define gre_tunnel_dump_reply
+{
+ u32 context;
+ i32 retval;
+};
+
+/** \brief Dump details of all or just a single GRE tunnel with key support.
+ @param client_index - opaque cookie to identify the sender.
+ @param context - sender context, to match reply w/ request.
+ @param sw_if_index - filter for tunnel of this interface index, ~0 for all.
+*/
+autoreply define gre_tunnel_dump_v2
+{
+ u32 client_index;
+ u32 context;
+ vl_api_interface_index_t sw_if_index;
+};
+
+
/** \brief Details response for one of the requested GRE tunnels.
@param context - sender context, to match reply w/ request.
@param tunnel - definition of the dumped tunnel.
vl_api_gre_tunnel_t tunnel;
};
+/** \brief Details response for one of the requested GRE tunnels with key support.
+ @param context - sender context, to match reply w/ request.
+ @param tunnel - definition of the dumped tunnel (with key field).
+*/
+define gre_tunnel_details_v2
+{
+ u32 context;
+ vl_api_gre_tunnel_v2_t tunnel;
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
if (!is_ipv6)
{
- vec_validate (rewrite, sizeof (*h4) - 1);
+ /* Allocate space for maximum header size including key */
+ if (gre_key_is_valid (t->gre_key))
+ vec_validate (rewrite, sizeof (*h4) + sizeof (gre_key_t) - 1);
+ else
+ vec_validate (rewrite, sizeof (*h4) - 1);
h4 = (ip4_and_gre_header_t *) rewrite;
gre = &h4->gre;
h4->ip4.ip_version_and_header_length = 0x45;
}
else
{
- vec_validate (rewrite, sizeof (*h6) - 1);
+ /* Allocate space for maximum header size including key */
+ if (gre_key_is_valid (t->gre_key))
+ vec_validate (rewrite, sizeof (*h6) + sizeof (gre_key_t) - 1);
+ else
+ vec_validate (rewrite, sizeof (*h6) - 1);
h6 = (ip6_and_gre_header_t *) rewrite;
gre = &h6->gre;
h6->ip6.ip_version_traffic_class_and_flow_label =
gre->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_SEQUENCE);
}
else
- gre->protocol =
- clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type));
-
+ {
+ gre->protocol =
+ clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type));
+ gre->flags_and_version = 0; // Clear flags first
+ /* Add key only for non-ERSPAN tunnels */
+ if (gre_key_is_valid (t->gre_key))
+ {
+ gre_header_with_key_t *grek = (gre_header_with_key_t *) gre;
+ grek->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_KEY);
+ grek->key = clib_host_to_net_u32 (t->gre_key);
+ }
+ }
return (rewrite);
}
typedef enum
{
-#define gre_error(n,s) GRE_ERROR_##n,
+#define gre_error(n, s) GRE_ERROR_##n,
#include <gre/error.def>
#undef gre_error
GRE_N_ERROR,
* and output of mirrored packet from a L2 network only. There is
* no support for receiving ERSPAN packets from a GRE ERSPAN tunnel
*/
-#define foreach_gre_tunnel_type \
- _(L3, "L3") \
- _(TEB, "TEB") \
- _(ERSPAN, "ERSPAN") \
+#define foreach_gre_tunnel_type \
+ _ (L3, "L3") \
+ _ (TEB, "TEB") \
+ _ (ERSPAN, "ERSPAN")
/**
* @brief The GRE tunnel type
#undef _
} __clib_packed gre_tunnel_type_t;
-extern u8 *format_gre_tunnel_type (u8 * s, va_list * args);
+/**
+ * @brief GRE key type (RFC 2890)
+ */
+typedef u32 gre_key_t;
+
+/**
+ * @brief Check if a GRE key is valid (non-zero)
+ */
+#define gre_key_is_valid(_key) ((_key) != 0)
+extern u8 *format_gre_tunnel_type (u8 *s, va_list *args);
+
+/**
+ * @brief Format a GRE key for display
+ */
+format_function_t format_gre_key;
/**
* A GRE payload protocol registration
struct
{
u32 fib_index;
+ gre_key_t gre_key;
u16 session_id;
gre_tunnel_type_t type;
tunnel_mode_t mode;
};
- u64 as_u64;
+ u64 as_u64[2];
};
-} gre_tunnel_key_common_t;
+} __clib_packed gre_tunnel_key_common_t;
-STATIC_ASSERT_SIZEOF (gre_tunnel_key_common_t, sizeof (u64));
+STATIC_ASSERT_SIZEOF (gre_tunnel_key_common_t, 2 * sizeof (u64));
/**
* @brief Key for a IPv4 GRE Tunnel
gre_tunnel_key_common_t gtk_common;
} __attribute__ ((packed)) gre_tunnel_key4_t;
-STATIC_ASSERT_SIZEOF (gre_tunnel_key4_t, 2 * sizeof (u64));
+STATIC_ASSERT_SIZEOF (gre_tunnel_key4_t, 3 * sizeof (u64));
/**
* @brief Key for a IPv6 GRE Tunnel
gre_tunnel_key_common_t gtk_common;
} __attribute__ ((packed)) gre_tunnel_key6_t;
-STATIC_ASSERT_SIZEOF (gre_tunnel_key6_t, 5 * sizeof (u64));
+STATIC_ASSERT_SIZEOF (gre_tunnel_key6_t, 6 * sizeof (u64));
/**
* Union of the two possible key types
u32 sw_if_index;
gre_tunnel_type_t type;
tunnel_mode_t mode;
+ gre_key_t gre_key;
+
tunnel_encap_decap_flags_t flags;
/**
/**
* GRE header sequence number (SN) used for ERSPAN type 2 header, must be
* bumped automically to be thread safe. As multiple GRE tunnels are created
- * for the same fib-idx/DIP/SIP with different ERSPAN session number, they all
- * share the same SN which is kept per FIB/DIP/SIP, as specified by RFC2890.
+ * for the same fib-idx/DIP/SIP with different ERSPAN session number, they
+ * all share the same SN which is kept per FIB/DIP/SIP, as specified by
+ * RFC2890.
*/
gre_sn_t *gre_sn;
-
- u32 dev_instance; /* Real device instance in tunnel vector */
- u32 user_instance; /* Instance name being shown to user */
+ u32 dev_instance; /* Real device instance in tunnel vector */
+ u32 user_instance; /* Instance name being shown to user */
} gre_tunnel_t;
typedef struct
}) ip6_and_gre_header_t;
always_inline gre_protocol_info_t *
-gre_get_protocol_info (gre_main_t * em, gre_protocol_t protocol)
+gre_get_protocol_info (gre_main_t *em, gre_protocol_t protocol)
{
uword *p = hash_get (em->protocol_info_by_protocol, protocol);
return p ? vec_elt_at_index (em->protocol_infos, p[0]) : 0;
extern gre_main_t gre_main;
-extern clib_error_t *gre_interface_admin_up_down (vnet_main_t * vnm,
+extern clib_error_t *gre_interface_admin_up_down (vnet_main_t *vnm,
u32 hw_if_index, u32 flags);
extern void gre_tunnel_stack (adj_index_t ai);
-extern void gre_update_adj (vnet_main_t * vnm,
- u32 sw_if_index, adj_index_t ai);
+extern void gre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai);
typedef struct mgre_walk_ctx_t_
{
unformat_function_t unformat_gre_header;
unformat_function_t unformat_pg_gre_header;
-void
-gre_register_input_protocol (vlib_main_t * vm, gre_protocol_t protocol,
- u32 node_index, gre_tunnel_type_t tunnel_type);
+void gre_register_input_protocol (vlib_main_t *vm, gre_protocol_t protocol,
+ u32 node_index,
+ gre_tunnel_type_t tunnel_type);
/* manually added to the interface output node in gre.c */
-#define GRE_OUTPUT_NEXT_LOOKUP 1
+#define GRE_OUTPUT_NEXT_LOOKUP 1
typedef struct
{
ip46_address_t src, dst;
u32 outer_table_id;
u16 session_id;
+ gre_key_t gre_key;
tunnel_encap_decap_flags_t flags;
} vnet_gre_tunnel_add_del_args_t;
-extern int vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t * a,
- u32 * sw_if_indexp);
+extern int vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t *a,
+ u32 *sw_if_indexp);
static inline void
-gre_mk_key4 (ip4_address_t src,
- ip4_address_t dst,
- u32 fib_index,
- gre_tunnel_type_t ttype,
- tunnel_mode_t tmode, u16 session_id, gre_tunnel_key4_t * key)
+gre_mk_key4 (ip4_address_t src, ip4_address_t dst, u32 fib_index,
+ gre_tunnel_type_t ttype, tunnel_mode_t tmode, u16 session_id,
+ gre_key_t gre_key, gre_tunnel_key4_t *key)
{
+ clib_memset (key, 0, sizeof (*key)); // Zero entire structure first
key->gtk_src = src;
key->gtk_dst = dst;
key->gtk_common.type = ttype;
key->gtk_common.mode = tmode;
key->gtk_common.fib_index = fib_index;
key->gtk_common.session_id = session_id;
+ key->gtk_common.gre_key = gre_key;
}
static inline int
-gre_match_key4 (const gre_tunnel_key4_t * key1,
- const gre_tunnel_key4_t * key2)
+gre_match_key4 (const gre_tunnel_key4_t *key1, const gre_tunnel_key4_t *key2)
{
return ((key1->gtk_as_u64 == key2->gtk_as_u64) &&
- (key1->gtk_common.as_u64 == key2->gtk_common.as_u64));
+ (key1->gtk_common.as_u64[0] == key2->gtk_common.as_u64[0]) &&
+ (key1->gtk_common.as_u64[1] == key2->gtk_common.as_u64[1]));
}
static inline void
-gre_mk_key6 (const ip6_address_t * src,
- const ip6_address_t * dst,
- u32 fib_index,
- gre_tunnel_type_t ttype,
- tunnel_mode_t tmode, u16 session_id, gre_tunnel_key6_t * key)
+gre_mk_key6 (const ip6_address_t *src, const ip6_address_t *dst, u32 fib_index,
+ gre_tunnel_type_t ttype, tunnel_mode_t tmode, u16 session_id,
+ gre_key_t gre_key, gre_tunnel_key6_t *key)
{
+ clib_memset (key, 0, sizeof (*key)); // Zero entire structure first
key->gtk_src = *src;
key->gtk_dst = *dst;
key->gtk_common.type = ttype;
key->gtk_common.mode = tmode;
key->gtk_common.fib_index = fib_index;
key->gtk_common.session_id = session_id;
+ key->gtk_common.gre_key = gre_key;
}
static inline int
-gre_match_key6 (const gre_tunnel_key6_t * key1,
- const gre_tunnel_key6_t * key2)
+gre_match_key6 (const gre_tunnel_key6_t *key1, const gre_tunnel_key6_t *key2)
{
return (ip6_address_is_equal (&key1->gtk_src, &key2->gtk_src) &&
ip6_address_is_equal (&key1->gtk_dst, &key2->gtk_dst) &&
- (key1->gtk_common.as_u64 == key2->gtk_common.as_u64));
+ (key1->gtk_common.as_u64[0] == key2->gtk_common.as_u64[0]) &&
+ (key1->gtk_common.as_u64[1] == key2->gtk_common.as_u64[1]));
}
static inline void
-gre_mk_sn_key (const gre_tunnel_t * gt, gre_sn_key_t * key)
+gre_mk_sn_key (const gre_tunnel_t *gt, gre_sn_key_t *key)
{
key->src = gt->tunnel_src;
key->dst = gt->tunnel_dst.fp_addr;
a->session_id = ntohs (mp->tunnel.session_id);
a->outer_table_id = ntohl (mp->tunnel.outer_table_id);
a->flags = flags;
+ a->gre_key = 0; // No key in the v1 API
rv = vnet_gre_tunnel_add_del (a, &sw_if_index);
({ rmp->sw_if_index = ntohl (sw_if_index); }));
}
+static void
+vl_api_gre_tunnel_add_del_v2_t_handler (vl_api_gre_tunnel_add_del_v2_t *mp)
+{
+ vnet_gre_tunnel_add_del_args_t _a = {}, *a = &_a;
+ vl_api_gre_tunnel_add_del_v2_reply_t *rmp;
+ tunnel_encap_decap_flags_t flags;
+ u32 sw_if_index = ~0;
+ ip46_type_t itype[2];
+ int rv = 0;
+
+ itype[0] = ip_address_decode (&mp->tunnel.src, &a->src);
+ itype[1] = ip_address_decode (&mp->tunnel.dst, &a->dst);
+
+ if (itype[0] != itype[1])
+ {
+ rv = VNET_API_ERROR_INVALID_PROTOCOL;
+ goto out;
+ }
+
+ if (ip46_address_is_equal (&a->src, &a->dst))
+ {
+ rv = VNET_API_ERROR_SAME_SRC_DST;
+ goto out;
+ }
+
+ rv = gre_tunnel_type_decode (mp->tunnel.type, &a->type);
+
+ if (rv)
+ goto out;
+
+ rv = tunnel_mode_decode (mp->tunnel.mode, &a->mode);
+
+ if (rv)
+ goto out;
+
+ rv = tunnel_encap_decap_flags_decode (mp->tunnel.flags, &flags);
+
+ if (rv)
+ goto out;
+
+ a->is_add = mp->is_add;
+ a->is_ipv6 = (itype[0] == IP46_TYPE_IP6);
+ a->instance = ntohl (mp->tunnel.instance);
+ a->session_id = ntohs (mp->tunnel.session_id);
+ a->outer_table_id = ntohl (mp->tunnel.outer_table_id);
+ a->flags = flags;
+ a->gre_key = ntohl (mp->tunnel.key); // Key field present in v2 API
+
+ rv = vnet_gre_tunnel_add_del (a, &sw_if_index);
+
+out:
+ REPLY_MACRO2 (VL_API_GRE_TUNNEL_ADD_DEL_V2_REPLY,
+ ({ rmp->sw_if_index = ntohl (sw_if_index); }));
+}
+
static void
send_gre_tunnel_details (gre_tunnel_t *t, vl_api_gre_tunnel_dump_t *mp)
{
}));
}
+static void
+send_gre_tunnel_details_v2 (gre_tunnel_t *t, vl_api_gre_tunnel_dump_v2_t *mp)
+{
+ vl_api_gre_tunnel_details_v2_t *rmp;
+
+ REPLY_MACRO_DETAILS2 (
+ VL_API_GRE_TUNNEL_DETAILS_V2, ({
+ ip_address_encode (&t->tunnel_src, IP46_TYPE_ANY, &rmp->tunnel.src);
+ ip_address_encode (&t->tunnel_dst.fp_addr, IP46_TYPE_ANY,
+ &rmp->tunnel.dst);
+
+ rmp->tunnel.outer_table_id = htonl (
+ fib_table_get_table_id (t->outer_fib_index, t->tunnel_dst.fp_proto));
+
+ rmp->tunnel.type = gre_tunnel_type_encode (t->type);
+ rmp->tunnel.mode = tunnel_mode_encode (t->mode);
+ rmp->tunnel.flags = tunnel_encap_decap_flags_encode (t->flags);
+ rmp->tunnel.instance = htonl (t->user_instance);
+ rmp->tunnel.sw_if_index = htonl (t->sw_if_index);
+ rmp->tunnel.session_id = htons (t->session_id);
+ rmp->tunnel.key =
+ htonl (t->gre_key); // Include the GRE key in the v2 API
+ }));
+}
+
static void
vl_api_gre_tunnel_dump_t_handler (vl_api_gre_tunnel_dump_t *mp)
{
}
}
+static void
+vl_api_gre_tunnel_dump_v2_t_handler (vl_api_gre_tunnel_dump_v2_t *mp)
+{
+ vl_api_registration_t *reg;
+ gre_main_t *gm = &gre_main;
+ gre_tunnel_t *t;
+ u32 sw_if_index;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ sw_if_index = ntohl (mp->sw_if_index);
+
+ if (~0 == sw_if_index)
+ {
+ pool_foreach (t, gm->tunnels)
+ {
+ send_gre_tunnel_details_v2 (t, mp);
+ }
+ }
+
+ else
+ {
+ if ((sw_if_index >= vec_len (gm->tunnel_index_by_sw_if_index)) ||
+ (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index]))
+ {
+ return;
+ }
+ t = &gm->tunnels[gm->tunnel_index_by_sw_if_index[sw_if_index]];
+ send_gre_tunnel_details_v2 (t, mp);
+ }
+}
+
/*
* gre_api_hookup
* Add vpe's API message handlers to the table.
return (s);
}
+/**
+ * @brief Format a GRE key for display
+ */
+u8 *
+format_gre_key (u8 *s, va_list *args)
+{
+ gre_key_t key = va_arg (*args, gre_key_t);
+
+ if (!gre_key_is_valid (key))
+ return format (s, "INVALID");
+ else
+ return format (s, "%u", key);
+}
+
static u8 *
format_gre_tunnel (u8 *s, va_list *args)
{
s = format (s, "payload %U ", format_gre_tunnel_type, t->type);
s = format (s, "%U ", format_tunnel_mode, t->mode);
+ if (gre_key_is_valid (t->gre_key))
+ s = format (s, "key %U ", format_gre_key, t->gre_key);
+
if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
s = format (s, "session %d ", t->session_id);
if (!a->is_ipv6)
{
gre_mk_key4 (a->src.ip4, a->dst.ip4, outer_fib_index, a->type, a->mode,
- a->session_id, &key->gtk_v4);
+ a->session_id, a->gre_key, &key->gtk_v4);
p = hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
}
else
{
gre_mk_key6 (&a->src.ip6, &a->dst.ip6, outer_fib_index, a->type, a->mode,
- a->session_id, &key->gtk_v6);
+ a->session_id, a->gre_key, &key->gtk_v6);
p = hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6);
}
if (FIB_PROTOCOL_IP4 == nh->fp_proto)
gre_mk_key4 (t->tunnel_src.ip4, nh->fp_addr.ip4,
teib_entry_get_fib_index (ne), t->type, TUNNEL_MODE_P2P, 0,
- &key->gtk_v4);
+ t->gre_key, &key->gtk_v4);
else
gre_mk_key6 (&t->tunnel_src.ip6, &nh->fp_addr.ip6,
teib_entry_get_fib_index (ne), t->type, TUNNEL_MODE_P2P, 0,
- &key->gtk_v6);
+ t->gre_key, &key->gtk_v6);
}
/**
pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
clib_memset (t, 0, sizeof (*t));
+ // added for GRE Key - only mark as present if key is non-zero
+ t->gre_key = a->gre_key;
/* Reconcile the real dev_instance and a possible requested instance */
u32 t_idx = t - gm->tunnels; /* tunnel index (or instance) */
u8 is_add = 1;
u32 sw_if_index;
clib_error_t *error = NULL;
-
+ u32 key = 0; // added GRE key
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
else if (unformat (line_input, "flags %U",
unformat_tunnel_encap_decap_flags, &flags))
;
+ else if (unformat (line_input, "key %u", &key))
+ ;
else
{
error = clib_error_return (0, "unknown input `%U'",
a->is_ipv6 = !ip46_address_is_ip4 (&src);
a->instance = instance;
a->flags = flags;
+ a->gre_key = key;
clib_memcpy (&a->src, &src, sizeof (a->src));
clib_memcpy (&a->dst, &dst, sizeof (a->dst));
.path = "create gre tunnel",
.short_help = "create gre tunnel src <addr> dst <addr> [instance <n>] "
"[outer-fib-id <fib>] [teb | erspan <session-id>] [del] "
- "[multipoint]",
+ "[multipoint]"
+ "[key <value>]",
.function = create_gre_tunnel_command_fn,
};
{
const uword *p;
p = is_ipv6 ? hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6) :
- hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
+ hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
if (PREDICT_FALSE (!p))
{
*next = GRE_INPUT_NEXT_DROP;
ip6[1] = vlib_buffer_get_current (b[1]);
gre[0] = (void *) (ip6[0] + 1);
gre[1] = (void *) (ip6[1] + 1);
- vlib_buffer_advance (b[0], sizeof (*ip6[0]) + sizeof (*gre[0]));
- vlib_buffer_advance (b[1], sizeof (*ip6[0]) + sizeof (*gre[0]));
+ /* Calculate total header size for each packet */
+ u16 gre_hdr_size0 = sizeof (*gre[0]);
+ u16 gre_hdr_size1 = sizeof (*gre[1]);
+ if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ gre_hdr_size0 += sizeof (gre_key_t);
+ if (gre[1]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ gre_hdr_size1 += sizeof (gre_key_t);
+
+ /* Single buffer advance for each packet */
+ vlib_buffer_advance (b[0], sizeof (*ip6[0]) + gre_hdr_size0);
+ vlib_buffer_advance (b[1], sizeof (*ip6[1]) + gre_hdr_size1);
}
else
{
ip4[1] = vlib_buffer_get_current (b[1]);
gre[0] = (void *) (ip4[0] + 1);
gre[1] = (void *) (ip4[1] + 1);
- vlib_buffer_advance (b[0], sizeof (*ip4[0]) + sizeof (*gre[0]));
- vlib_buffer_advance (b[1], sizeof (*ip4[0]) + sizeof (*gre[0]));
+ /* Calculate total header size for each packet */
+ u16 gre_hdr_size0 = sizeof (*gre[0]);
+ u16 gre_hdr_size1 = sizeof (*gre[1]);
+ if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ gre_hdr_size0 += sizeof (gre_key_t);
+ if (gre[1]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ gre_hdr_size1 += sizeof (gre_key_t);
+
+ /* Single buffer advance for each packet */
+ vlib_buffer_advance (b[0], sizeof (*ip4[0]) + gre_hdr_size0);
+ vlib_buffer_advance (b[1], sizeof (*ip4[1]) + gre_hdr_size1);
+ }
+
+ /* GRE key processing here */
+ gre_key_t gre_key[2] = { 0, 0 };
+ if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ {
+ gre_header_with_key_t *grek = (gre_header_with_key_t *) gre[0];
+ gre_key[0] = clib_net_to_host_u32 (grek->key);
+ }
+ if (gre[1]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ {
+ gre_header_with_key_t *grek = (gre_header_with_key_t *) gre[1];
+ gre_key[1] = clib_net_to_host_u32 (grek->key);
}
if (PREDICT_TRUE (cached_protocol == gre[0]->protocol))
type[1] = ni[1].tunnel_type;
b[0]->error = nidx[0] == SPARSE_VEC_INVALID_INDEX ?
- node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] :
- node->errors[GRE_ERROR_NONE];
+ node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] :
+ node->errors[GRE_ERROR_NONE];
b[1]->error = nidx[1] == SPARSE_VEC_INVALID_INDEX ?
- node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] :
- node->errors[GRE_ERROR_NONE];
+ node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] :
+ node->errors[GRE_ERROR_NONE];
version[0] = clib_net_to_host_u16 (gre[0]->flags_and_version);
version[1] = clib_net_to_host_u16 (gre[1]->flags_and_version);
{
gre_mk_key6 (&ip6[0]->dst_address, &ip6[0]->src_address,
vnet_buffer (b[0])->ip.fib_index, type[0],
- TUNNEL_MODE_P2P, 0, &key[0].gtk_v6);
+ TUNNEL_MODE_P2P, 0, gre_key[0], &key[0].gtk_v6);
gre_mk_key6 (&ip6[1]->dst_address, &ip6[1]->src_address,
vnet_buffer (b[1])->ip.fib_index, type[1],
- TUNNEL_MODE_P2P, 0, &key[1].gtk_v6);
+ TUNNEL_MODE_P2P, 0, gre_key[1], &key[1].gtk_v6);
matched[0] = gre_match_key6 (&cached_key.gtk_v6, &key[0].gtk_v6);
matched[1] = gre_match_key6 (&cached_key.gtk_v6, &key[1].gtk_v6);
}
{
gre_mk_key4 (ip4[0]->dst_address, ip4[0]->src_address,
vnet_buffer (b[0])->ip.fib_index, type[0],
- TUNNEL_MODE_P2P, 0, &key[0].gtk_v4);
+ TUNNEL_MODE_P2P, 0, gre_key[0], &key[0].gtk_v4);
gre_mk_key4 (ip4[1]->dst_address, ip4[1]->src_address,
vnet_buffer (b[1])->ip.fib_index, type[1],
- TUNNEL_MODE_P2P, 0, &key[1].gtk_v4);
+ TUNNEL_MODE_P2P, 0, gre_key[1], &key[1].gtk_v4);
matched[0] = gre_match_key4 (&cached_key.gtk_v4, &key[0].gtk_v4);
matched[1] = gre_match_key4 (&cached_key.gtk_v4, &key[1].gtk_v4);
}
/* ip6_local hands us the ip header, not the gre header */
ip6[0] = vlib_buffer_get_current (b[0]);
gre[0] = (void *) (ip6[0] + 1);
- vlib_buffer_advance (b[0], sizeof (*ip6[0]) + sizeof (*gre[0]));
+
+ /* Calculate total header size */
+ u16 gre_hdr_size = sizeof (*gre[0]);
+ if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ gre_hdr_size += sizeof (gre_key_t);
+ /* Single buffer advance */
+ vlib_buffer_advance (b[0], sizeof (*ip6[0]) + gre_hdr_size);
}
else
{
/* ip4_local hands us the ip header, not the gre header */
ip4[0] = vlib_buffer_get_current (b[0]);
gre[0] = (void *) (ip4[0] + 1);
- vlib_buffer_advance (b[0], sizeof (*ip4[0]) + sizeof (*gre[0]));
+ /* Calculate total header size */
+ u16 gre_hdr_size = sizeof (*gre[0]);
+ if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ gre_hdr_size += sizeof (gre_key_t);
+ /* Single buffer advance */
+ vlib_buffer_advance (b[0], sizeof (*ip4[0]) + gre_hdr_size);
+ }
+
+ /* GRE key processing here */
+ gre_key_t gre_key = 0;
+ if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY))
+ {
+ gre_header_with_key_t *grek = (gre_header_with_key_t *) gre[0];
+ gre_key = clib_net_to_host_u32 (grek->key);
}
if (PREDICT_TRUE (cached_protocol == gre[0]->protocol))
type[0] = ni[0].tunnel_type;
b[0]->error = nidx[0] == SPARSE_VEC_INVALID_INDEX ?
- node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] :
- node->errors[GRE_ERROR_NONE];
+ node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] :
+ node->errors[GRE_ERROR_NONE];
version[0] = clib_net_to_host_u16 (gre[0]->flags_and_version);
version[0] &= GRE_VERSION_MASK;
{
gre_mk_key6 (&ip6[0]->dst_address, &ip6[0]->src_address,
vnet_buffer (b[0])->ip.fib_index, type[0],
- TUNNEL_MODE_P2P, 0, &key[0].gtk_v6);
+ TUNNEL_MODE_P2P, 0, gre_key, &key[0].gtk_v6);
matched[0] = gre_match_key6 (&cached_key.gtk_v6, &key[0].gtk_v6);
}
else
{
gre_mk_key4 (ip4[0]->dst_address, ip4[0]->src_address,
vnet_buffer (b[0])->ip.fib_index, type[0],
- TUNNEL_MODE_P2P, 0, &key[0].gtk_v4);
+ TUNNEL_MODE_P2P, 0, gre_key, &key[0].gtk_v4);
matched[0] = gre_match_key4 (&cached_key.gtk_v4, &key[0].gtk_v4);
}
};
VLIB_REGISTER_NODE (gre4_input_node) = {
- .name = "gre4-input",
- /* Takes a vector of packets. */
- .vector_size = sizeof (u32),
+ .name = "gre4-input",
+ /* Takes a vector of packets. */
+ .vector_size = sizeof (u32),
- .n_errors = GRE_N_ERROR,
- .error_strings = gre_error_strings,
+ .n_errors = GRE_N_ERROR,
+ .error_strings = gre_error_strings,
- .n_next_nodes = GRE_INPUT_N_NEXT,
- .next_nodes = {
+ .n_next_nodes = GRE_INPUT_N_NEXT,
+ .next_nodes = {
#define _(s, n) [GRE_INPUT_NEXT_##s] = n,
- foreach_gre_input_next
+ foreach_gre_input_next
#undef _
- },
+ },
- .format_buffer = format_gre_header_with_length,
- .format_trace = format_gre_rx_trace,
- .unformat_buffer = unformat_gre_header,
-};
+ .format_buffer = format_gre_header_with_length,
+ .format_trace = format_gre_rx_trace,
+ .unformat_buffer = unformat_gre_header,
+ };
VLIB_REGISTER_NODE (gre6_input_node) = {
- .name = "gre6-input",
- /* Takes a vector of packets. */
- .vector_size = sizeof (u32),
+ .name = "gre6-input",
+ /* Takes a vector of packets. */
+ .vector_size = sizeof (u32),
- .runtime_data_bytes = sizeof (gre_input_runtime_t),
+ .runtime_data_bytes = sizeof (gre_input_runtime_t),
- .n_errors = GRE_N_ERROR,
- .error_strings = gre_error_strings,
+ .n_errors = GRE_N_ERROR,
+ .error_strings = gre_error_strings,
- .n_next_nodes = GRE_INPUT_N_NEXT,
- .next_nodes = {
+ .n_next_nodes = GRE_INPUT_N_NEXT,
+ .next_nodes = {
#define _(s, n) [GRE_INPUT_NEXT_##s] = n,
- foreach_gre_input_next
+ foreach_gre_input_next
#undef _
- },
+ },
- .format_buffer = format_gre_header_with_length,
- .format_trace = format_gre_rx_trace,
- .unformat_buffer = unformat_gre_header,
-};
+ .format_buffer = format_gre_header_with_length,
+ .format_trace = format_gre_rx_trace,
+ .unformat_buffer = unformat_gre_header,
+ };
#ifndef CLIB_MARCH_VARIANT
void
* limitations under the License.
*/
-#define foreach_gre_protocol \
-_ (0x0800, ip4) \
-_ (0x86DD, ip6) \
-_ (0x6558, teb) \
-_ (0x0806, arp) \
-_ (0x8847, mpls_unicast) \
-_ (0x88BE, erspan) \
-_ (0x894F, nsh)
+#define foreach_gre_protocol \
+ _ (0x0800, ip4) \
+ _ (0x86DD, ip6) \
+ _ (0x6558, teb) \
+ _ (0x0806, arp) \
+ _ (0x8847, mpls_unicast) \
+ _ (0x88BE, erspan) \
+ _ (0x894F, nsh)
typedef enum
{
-#define _(n,f) GRE_PROTOCOL_##f = n,
+#define _(n, f) GRE_PROTOCOL_##f = n,
foreach_gre_protocol
#undef _
} gre_protocol_t;
#define GRE_FLAGS_CHECKSUM (1 << 15)
/* deprecated, according to rfc2784 */
-#define GRE_FLAGS_ROUTING (1 << 14)
-#define GRE_FLAGS_KEY (1 << 13)
-#define GRE_FLAGS_SEQUENCE (1 << 12)
+#define GRE_FLAGS_ROUTING (1 << 14)
+#define GRE_FLAGS_KEY (1 << 13)
+#define GRE_FLAGS_SEQUENCE (1 << 12)
#define GRE_FLAGS_STRICT_SOURCE_ROUTE (1 << 11)
/* version 1 is PPTP which we don't support */
#define GRE_SUPPORTED_VERSION 0
-#define GRE_VERSION_MASK 0x7
+#define GRE_VERSION_MASK 0x7
/* 0x800 for ip4, etc. */
u16 protocol;
} gre_header_t;
+typedef struct
+{
+ u16 flags_and_version;
+ u16 protocol;
+ u32 key;
+} gre_header_with_key_t;
+
/* From draft-foschiano-erspan-03.txt
Different frame variants known as "ERSPAN Types" can be
distinguished based on the GRE "Protocol Type" field value: Type I
and II's value is 0x88BE while Type III's is 0x22EB [ETYPES].
- GRE header for ERSPAN Type II encapsulation (8 octets [34:41])
+ GRE header for ERSPAN Type II encapsulation (8 octets [34:41])
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The ERSPAN Type II feature header is described below:
- ERSPAN Type II header (8 octets [42:49])
+ ERSPAN Type II header (8 octets [42:49])
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The various fields of the above header are described in this table:
Field Position Length Definition
- [octet:bit] (bits)
+ [octet:bit] (bits)
Ver [42:0] 4 ERSPAN Encapsulation version.
- This indicates the version of
- the ERSPAN encapsulation
- specification. Set to 0x1 for
- Type II.
+ This indicates the version of
+ the ERSPAN encapsulation
+ specification. Set to 0x1 for
+ Type II.
VLAN [42:4] 12 Original VLAN of the frame,
- mirrored from the source.
- If the En field is set to 11,
- the value of VLAN is undefined.
+ mirrored from the source.
+ If the En field is set to 11,
+ the value of VLAN is undefined.
COS [44:0] 3 Original class of service of the
- frame, mirrored from the source.
+ frame, mirrored from the source.
En [44:3] 2 The trunk encapsulation type
- associated with the ERSPAN source
- port for ingress ERSPAN traffic.
+ associated with the ERSPAN source
+ port for ingress ERSPAN traffic.
- The possible values are:
- 00-originally without VLAN tag
- 01-originally ISL encapsulated
- 10-originally 802.1Q encapsulated
- 11-VLAN tag preserved in frame.
+ The possible values are:
+ 00-originally without VLAN tag
+ 01-originally ISL encapsulated
+ 10-originally 802.1Q encapsulated
+ 11-VLAN tag preserved in frame.
T [44:5] 1 This bit indicates that the frame
- copy encapsulated in the ERSPAN
- packet has been truncated. This
- occurs if the ERSPAN encapsulated
- frame exceeds the configured MTU.
+ copy encapsulated in the ERSPAN
+ packet has been truncated. This
+ occurs if the ERSPAN encapsulated
+ frame exceeds the configured MTU.
Session ID [44:6] 10 Identification associated with
(ERSPAN ID) each ERSPAN session. Must be
- unique between the source and the
- receiver(s). (See section below.)
+ unique between the source and the
+ receiver(s). (See section below.)
Reserved [46:0] 12 All bits are set to zero
Index [47:4] 20 A 20 bit index/port number
- associated with the ERSPAN
- traffic's port and
- direction (ingress/egress). N.B.:
- This field is platform dependent.
+ associated with the ERSPAN
+ traffic's port and
+ direction (ingress/egress). N.B.:
+ This field is platform dependent.
*/
typedef CLIB_PACKED (struct {
erspan_t2_t erspan;
}) erspan_t2_header_t;
-
/* u64 template for ERSPAN type 2 header with both EN bits set */
#define ERSPAN_HDR2 0x1000180000000000ul
pkts.append(p)
return pkts
+ def create_tunnel_stream_4o4_with_key(
+ self, src_if, tunnel_src, tunnel_dst, src_ip, dst_ip, key
+ ):
+ pkts = []
+ for i in range(0, 257):
+ info = self.create_packet_info(src_if, src_if)
+ payload = self.info_to_payload(info)
+ p = (
+ Ether(dst=src_if.local_mac, src=src_if.remote_mac)
+ / IP(src=tunnel_src, dst=tunnel_dst)
+ / GRE(key=key)
+ / IP(src=src_ip, dst=dst_ip)
+ / UDP(sport=1234, dport=1234)
+ / Raw(payload)
+ )
+ info.data = p.copy()
+ pkts.append(p)
+ return pkts
+
def create_tunnel_stream_6o4(self, src_if, tunnel_src, tunnel_dst, src_ip, dst_ip):
pkts = []
for i in range(0, 257):
self.logger.error(ppp("Tx:", tx))
raise
+ def verify_tunneled_4o4_with_key(
+ self, src_if, capture, sent, tunnel_src, tunnel_dst, key, dscp=0, ecn=0
+ ):
+ """
+ Verify GRE encapsulation with key field:
+ - Basic GRE tunnel checks (source, destination, etc.)
+ - Verify GRE flags indicate key field is present (0x2000)
+ - Verify the GRE key value matches what we configured
+ """
+ self.assertEqual(len(capture), len(sent))
+ tos = (dscp << 2) | ecn
+
+ for tx, rx in zip(sent, capture):
+ try:
+
+ tx_ip = tx[IP]
+ rx_ip = rx[IP]
+
+ # Verify tunnel outer header
+ self.assertEqual(rx_ip.src, tunnel_src)
+ self.assertEqual(rx_ip.dst, tunnel_dst)
+ self.assertEqual(rx_ip.tos, tos)
+ self.assertEqual(rx_ip.len, len(rx_ip))
+
+ # Verify GRE header
+ rx_gre = rx[GRE]
+
+ # Check if GRE flags has the KEY bit set (0x2000)
+ # In Scapy GRE, this should be reflected in the 'flags' field or through presence of 'key' field
+ self.assertTrue(
+ hasattr(rx_gre, "key"), "GRE key field not present in packet"
+ )
+
+ # Verify the key value is correct
+ self.assertEqual(
+ rx_gre.key,
+ key,
+ f"GRE key value mismatch: expected {key}, got {rx_gre.key}",
+ )
+ self.logger.info(f"Verified GRE key: {rx_gre.key}")
+
+ # Verify inner packet data
+ rx_inner_ip = rx_gre[IP]
+ self.assertEqual(rx_inner_ip.src, tx_ip.src)
+ self.assertEqual(rx_inner_ip.dst, tx_ip.dst)
+
+ # IP processing post pop has decremented the TTL
+ self.assertEqual(rx_inner_ip.ttl + 1, tx_ip.ttl)
+
+ except:
+ self.logger.error(ppp("Rx:", rx))
+ self.logger.error(ppp("Tx:", tx))
+ raise
+
def verify_tunneled_6o6(
self, src_if, capture, sent, tunnel_src, tunnel_dst, dscp=0, ecn=0
):
self.pg0.unconfig_ip6()
+ def test_gre_with_key(self):
+ """GRE IPv4 tunnel with Key Tests"""
+
+ # Use a key value for the GRE tunnel
+ key_value = 123
+
+ # Create a GRE interface with key support
+ gre_if = VppGreInterface(self, self.pg0.local_ip4, "1.1.1.2", gre_key=key_value)
+ gre_if.add_vpp_config()
+
+ # Configure the interface using VPP methods
+ gre_if.admin_up()
+ gre_if.config_ip4()
+
+ # Create route via tunnel
+ route_via_tun = VppIpRoute(
+ self, "4.4.4.4", 32, [VppRoutePath("0.0.0.0", gre_if.sw_if_index)]
+ )
+ route_via_tun.add_vpp_config()
+
+ # Add a route that resolves the tunnel's destination
+ route_tun_dst = VppIpRoute(
+ self,
+ "1.1.1.2",
+ 32,
+ [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index)],
+ )
+ route_tun_dst.add_vpp_config()
+
+ # Send packets that should be routed via the tunnel
+ tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
+ rx = self.send_and_expect(self.pg0, tx, self.pg0)
+
+ # Verify GRE encapsulation with key using the verification function
+ self.logger.info(f"Verifying GRE encapsulation with key {key_value}")
+ self.verify_tunneled_4o4_with_key(
+ self.pg0, # source interface
+ rx, # received packets
+ tx, # sent packets
+ self.pg0.local_ip4, # tunnel source
+ "1.1.1.2", # tunnel destination
+ key_value, # GRE key value
+ )
+
+ # Cleanup
+ route_tun_dst.remove_vpp_config()
+ route_via_tun.remove_vpp_config()
+ gre_if.remove_vpp_config()
+
def test_gre6(self):
"""GRE IPv6 tunnel Tests"""
mode=None,
flags=0,
session=0,
+ gre_key=0,
):
"""Create VPP GRE interface"""
super(VppGreInterface, self).__init__(test)
self.t_dst = dst_ip
self.t_outer_table = outer_table_id
self.t_session = session
+ self.t_gre_key = gre_key # Added GRE key field
self.t_flags = flags
self.t_type = type
if not self.t_type:
self.t_mode = VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_P2P
def add_vpp_config(self):
- r = self.test.vapi.gre_tunnel_add_del(
- is_add=1,
- tunnel={
- "src": self.t_src,
- "dst": self.t_dst,
- "outer_table_id": self.t_outer_table,
- "instance": 0xFFFFFFFF,
- "type": self.t_type,
- "mode": self.t_mode,
- "flags": self.t_flags,
- "session_id": self.t_session,
- },
- )
+ # If we need a key, use the v2 API
+ if self.t_gre_key != 0:
+ r = self.test.vapi.gre_tunnel_add_del_v2(
+ is_add=1,
+ tunnel={
+ "src": self.t_src,
+ "dst": self.t_dst,
+ "outer_table_id": self.t_outer_table,
+ "instance": 0xFFFFFFFF,
+ "type": self.t_type,
+ "mode": self.t_mode,
+ "flags": self.t_flags,
+ "session_id": self.t_session,
+ "key": self.t_gre_key,
+ },
+ )
+ else:
+ # Use regular v1 API for tunnels without key
+ r = self.test.vapi.gre_tunnel_add_del(
+ is_add=1,
+ tunnel={
+ "src": self.t_src,
+ "dst": self.t_dst,
+ "outer_table_id": self.t_outer_table,
+ "instance": 0xFFFFFFFF,
+ "type": self.t_type,
+ "mode": self.t_mode,
+ "flags": self.t_flags,
+ "session_id": self.t_session,
+ },
+ )
+
self.set_sw_if_index(r.sw_if_index)
self.generate_remote_hosts()
self.test.registry.register(self, self.test.logger)
def remove_vpp_config(self):
self.unconfig()
- self.test.vapi.gre_tunnel_add_del(
- is_add=0,
- tunnel={
- "src": self.t_src,
- "dst": self.t_dst,
- "outer_table_id": self.t_outer_table,
- "instance": 0xFFFFFFFF,
- "type": self.t_type,
- "mode": self.t_mode,
- "flags": self.t_flags,
- "session_id": self.t_session,
- },
- )
+
+ # Use appropriate API based on whether tunnel has a key
+ if self.t_gre_key != 0:
+ # Use v2 API for tunnels with keys
+ self.test.vapi.gre_tunnel_add_del_v2(
+ is_add=0,
+ tunnel={
+ "src": self.t_src,
+ "dst": self.t_dst,
+ "outer_table_id": self.t_outer_table,
+ "instance": 0xFFFFFFFF,
+ "type": self.t_type,
+ "mode": self.t_mode,
+ "flags": self.t_flags,
+ "session_id": self.t_session,
+ "key": self.t_gre_key,
+ },
+ )
+ else:
+ # Use v1 API for tunnels without keys
+ self.test.vapi.gre_tunnel_add_del(
+ is_add=0,
+ tunnel={
+ "src": self.t_src,
+ "dst": self.t_dst,
+ "outer_table_id": self.t_outer_table,
+ "instance": 0xFFFFFFFF,
+ "type": self.t_type,
+ "mode": self.t_mode,
+ "flags": self.t_flags,
+ "session_id": self.t_session,
+ },
+ )
def object_id(self):
return "gre-%d" % self.sw_if_index
def query_vpp_config(self):
- return self.test.vapi.gre_tunnel_dump(sw_if_index=self._sw_if_index)
+ try:
+ # Use appropriate API based on whether tunnel has a key
+ if hasattr(self, "t_gre_key") and self.t_gre_key != 0:
+ dump = self.test.vapi.gre_tunnel_dump_v2(sw_if_index=self.sw_if_index)
+ else:
+ dump = self.test.vapi.gre_tunnel_dump(sw_if_index=self.sw_if_index)
+
+ # Validate dump data matches this tunnel's configuration
+ for entry in dump:
+ # Skip non-tunnel entries (like int values)
+ if not hasattr(entry, "sw_if_index"):
+ continue
+
+ # Compare tunnel parameters
+ key_match = True
+ if hasattr(self, "t_gre_key") and self.t_gre_key != 0:
+ # For tunnels with keys, also validate the key value
+ key_match = hasattr(entry, "key") and entry.key == self.t_gre_key
+
+ if (
+ entry.sw_if_index == self.sw_if_index
+ and str(entry.src) == str(self.t_src)
+ and str(entry.dst) == str(self.t_dst)
+ and entry.type == self.t_type
+ and key_match
+ ):
+ return True
+
+ return False
+ except Exception:
+ return False
@property
def remote_ip(self):