aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vnet/vnet/interface.c1
-rw-r--r--vnet/vnet/interface_cli.c67
-rw-r--r--vnet/vnet/interface_funcs.h38
-rw-r--r--vnet/vnet/vnet.h2
-rw-r--r--vpp-api-test/vat/api_format.c80
-rw-r--r--vpp/vpp-api/api.c74
-rw-r--r--vpp/vpp-api/custom_dump.c23
-rw-r--r--vpp/vpp-api/vpe.api28
8 files changed, 302 insertions, 11 deletions
diff --git a/vnet/vnet/interface.c b/vnet/vnet/interface.c
index e552733e..6e3d7f29 100644
--- a/vnet/vnet/interface.c
+++ b/vnet/vnet/interface.c
@@ -1202,6 +1202,7 @@ vnet_interface_init (vlib_main_t * vm)
return error;
}
+ vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
}
VLIB_INIT_FUNCTION (vnet_interface_init);
diff --git a/vnet/vnet/interface_cli.c b/vnet/vnet/interface_cli.c
index 1c15eb18..7dbee867 100644
--- a/vnet/vnet/interface_cli.c
+++ b/vnet/vnet/interface_cli.c
@@ -228,6 +228,7 @@ show_sw_interfaces (vlib_main_t * vm,
u32 sw_if_index = ~(u32) 0;
u8 show_addresses = 0;
u8 show_features = 0;
+ u8 show_tag = 0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
@@ -242,6 +243,8 @@ show_sw_interfaces (vlib_main_t * vm,
show_addresses = 1;
else if (unformat (input, "features") || unformat (input, "feat"))
show_features = 1;
+ else if (unformat (input, "tag"))
+ show_tag = 1;
else
{
error = clib_error_return (0, "unknown input `%U'",
@@ -250,14 +253,26 @@ show_sw_interfaces (vlib_main_t * vm,
}
}
- if (show_features)
+ if (show_features || show_tag)
{
if (sw_if_index == ~(u32) 0)
return clib_error_return (0, "Interface not specified...");
+ }
+ if (show_features)
+ {
vnet_interface_features_show (vm, sw_if_index);
return 0;
}
+ if (show_tag)
+ {
+ u8 *tag;
+ tag = vnet_get_sw_interface_tag (vnm, sw_if_index);
+ vlib_cli_output (vm, "%U: %s",
+ format_vnet_sw_if_index_name, vnm, sw_if_index,
+ tag ? (char *) tag : "(none)");
+ return 0;
+ }
if (!show_addresses)
vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0);
@@ -1091,6 +1106,56 @@ VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = {
};
/* *INDENT-ON* */
+static clib_error_t *
+set_tag (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 sw_if_index = ~0;
+ u8 *tag = 0;
+
+ if (!unformat (input, "%U %s", unformat_vnet_sw_interface,
+ vnm, &sw_if_index, &tag))
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+
+ vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_tag_command, static) = {
+ .path = "set interface tag",
+ .short_help = "set interface tag <intfc> <tag>",
+ .function = set_tag,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+clear_tag (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 sw_if_index = ~0;
+
+ if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+
+ vnet_clear_sw_interface_tag (vnm, sw_if_index);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (clear_tag_command, static) = {
+ .path = "clear interface tag",
+ .short_help = "clear interface tag <intfc>",
+ .function = clear_tag,
+};
+/* *INDENT-ON* */
+
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/vnet/vnet/interface_funcs.h b/vnet/vnet/interface_funcs.h
index 17c677f0..a488599c 100644
--- a/vnet/vnet/interface_funcs.h
+++ b/vnet/vnet/interface_funcs.h
@@ -92,6 +92,44 @@ vnet_get_device_class (vnet_main_t * vnm, u32 dev_class_index)
dev_class_index);
}
+static inline u8 *
+vnet_get_sw_interface_tag (vnet_main_t * vnm, u32 sw_if_index)
+{
+ uword *p;
+ p = hash_get (vnm->interface_tag_by_sw_if_index, sw_if_index);
+ if (p)
+ return ((u8 *) p[0]);
+ return 0;
+}
+
+static inline void
+vnet_set_sw_interface_tag (vnet_main_t * vnm, u8 * tag, u32 sw_if_index)
+{
+ uword *p;
+ p = hash_get (vnm->interface_tag_by_sw_if_index, sw_if_index);
+ if (p)
+ {
+ u8 *oldtag = (u8 *) p[0];
+ hash_unset (vnm->interface_tag_by_sw_if_index, sw_if_index);
+ vec_free (oldtag);
+ }
+
+ hash_set (vnm->interface_tag_by_sw_if_index, sw_if_index, tag);
+}
+
+static inline void
+vnet_clear_sw_interface_tag (vnet_main_t * vnm, u32 sw_if_index)
+{
+ uword *p;
+ p = hash_get (vnm->interface_tag_by_sw_if_index, sw_if_index);
+ if (p)
+ {
+ u8 *oldtag = (u8 *) p[0];
+ hash_unset (vnm->interface_tag_by_sw_if_index, sw_if_index);
+ vec_free (oldtag);
+ }
+}
+
/**
* Call back walk type for walking SW indices on a HW interface
*/
diff --git a/vnet/vnet/vnet.h b/vnet/vnet/vnet.h
index 36cdddd6..5a8ae858 100644
--- a/vnet/vnet/vnet.h
+++ b/vnet/vnet/vnet.h
@@ -68,6 +68,8 @@ typedef struct vnet_main_t
_vnet_interface_function_list_elt_t
* sw_interface_admin_up_down_functions[VNET_ITF_FUNC_N_PRIO];
+ uword *interface_tag_by_sw_if_index;
+
/*
* Last "api" error, preserved so we can issue reasonable diagnostics
* at or near the top of the food chain
diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c
index 448ae75c..958f75f5 100644
--- a/vpp-api-test/vat/api_format.c
+++ b/vpp-api-test/vat/api_format.c
@@ -3547,7 +3547,8 @@ _(ip_source_and_port_range_check_interface_add_del_reply)\
_(delete_subif_reply) \
_(l2_interface_pbb_tag_rewrite_reply) \
_(punt_reply) \
-_(feature_enable_disable_reply)
+_(feature_enable_disable_reply) \
+_(sw_interface_tag_add_del_reply)
#define _(n) \
static void vl_api_##n##_t_handler \
@@ -3791,7 +3792,8 @@ _(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \
_(PUNT_REPLY, punt_reply) \
_(IP_FIB_DETAILS, ip_fib_details) \
_(IP6_FIB_DETAILS, ip6_fib_details) \
-_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply)
+_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) \
+_(SW_INTERFACE_TAG_ADD_DEL_REPLY, sw_interface_tag_add_del_reply)
/* M: construct, but don't yet send a message */
@@ -5629,6 +5631,7 @@ api_tap_connect (vat_main_t * vam)
u8 random_mac = 1;
u8 name_set = 0;
u8 *tap_name;
+ u8 *tag = 0;
memset (mac_address, 0, sizeof (mac_address));
@@ -5643,6 +5646,7 @@ api_tap_connect (vat_main_t * vam)
random_mac = 1;
else if (unformat (i, "tapname %s", &tap_name))
name_set = 1;
+ else if (unformat (i, "tag %s", &tag));
else
break;
}
@@ -5655,16 +5659,28 @@ api_tap_connect (vat_main_t * vam)
if (vec_len (tap_name) > 63)
{
errmsg ("tap name too long\n");
+ return -99;
}
vec_add1 (tap_name, 0);
+ if (vec_len (tag) > 63)
+ {
+ errmsg ("tag too long\n");
+ return -99;
+ }
+ vec_add1 (tag, 0);
+
/* Construct the API message */
M (TAP_CONNECT, tap_connect);
mp->use_random_mac = random_mac;
clib_memcpy (mp->mac_address, mac_address, 6);
clib_memcpy (mp->tap_name, tap_name, vec_len (tap_name));
+ if (tag)
+ clib_memcpy (mp->tag, tag, vec_len (tag));
+
vec_free (tap_name);
+ vec_free (tag);
/* send it... */
S;
@@ -10666,6 +10682,7 @@ api_create_vhost_user_if (vat_main_t * vam)
u32 custom_dev_instance = ~0;
u8 hwaddr[6];
u8 use_custom_mac = 0;
+ u8 *tag = 0;
/* Shut up coverity */
memset (hwaddr, 0, sizeof (hwaddr));
@@ -10682,6 +10699,8 @@ api_create_vhost_user_if (vat_main_t * vam)
use_custom_mac = 1;
else if (unformat (i, "server"))
is_server = 1;
+ else if (unformat (i, "tag %s", &tag))
+ ;
else
break;
}
@@ -10711,6 +10730,9 @@ api_create_vhost_user_if (vat_main_t * vam)
}
mp->use_custom_mac = use_custom_mac;
clib_memcpy (mp->mac_address, hwaddr, 6);
+ if (tag)
+ strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
+ vec_free (tag);
S;
W;
@@ -16410,6 +16432,54 @@ api_feature_enable_disable (vat_main_t * vam)
}
static int
+api_sw_interface_tag_add_del (vat_main_t * vam)
+{
+ unformat_input_t *i = vam->input;
+ vl_api_sw_interface_tag_add_del_t *mp;
+ f64 timeout;
+ u32 sw_if_index = ~0;
+ u8 *tag = 0;
+ u8 enable = 1;
+
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "tag %s", &tag))
+ ;
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ ;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ ;
+ else if (unformat (i, "del"))
+ enable = 0;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ {
+ errmsg ("missing interface name or sw_if_index\n");
+ return -99;
+ }
+
+ if (enable && (tag == 0))
+ {
+ errmsg ("no tag specified\n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del);
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->is_add = enable;
+ if (enable)
+ strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
+ vec_free (tag);
+
+ S;
+ W;
+}
+
+static int
q_or_quit (vat_main_t * vam)
{
longjmp (vam->jump_buf, 1);
@@ -16807,7 +16877,7 @@ _(l2_flags, \
_(bridge_flags, \
"bd_id <bridge-domain-id> [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \
_(tap_connect, \
- "tapname <name> mac <mac-addr> | random-mac") \
+ "tapname <name> mac <mac-addr> | random-mac [tag <string>]") \
_(tap_modify, \
"<vpp-if-name> | sw_if_index <id> tapname <name> mac <mac-addr> | random-mac") \
_(tap_delete, \
@@ -17085,7 +17155,9 @@ _(flow_classify_dump, "type [ip4|ip6]") \
_(ip_fib_dump, "") \
_(ip6_fib_dump, "") \
_(feature_enable_disable, "arc_name <arc_name> " \
- "feature_name <feature_name> <intfc> | sw_if_index <nn> [disable]")
+ "feature_name <feature_name> <intfc> | sw_if_index <nn> [disable]") \
+_(sw_interface_tag_add_del, "<intfc> | sw_if_index <nn> tag <text>" \
+"[disable]")
/* List of command functions, CLI names map directly to functions */
#define foreach_cli_function \
diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c
index 2c0256cc..b5253726 100644
--- a/vpp/vpp-api/api.c
+++ b/vpp/vpp-api/api.c
@@ -255,8 +255,8 @@ _(COP_INTERFACE_ENABLE_DISABLE, cop_interface_enable_disable) \
_(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable) \
_(GET_NODE_GRAPH, get_node_graph) \
_(SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats) \
-_(IOAM_ENABLE, ioam_enable) \
-_(IOAM_DISABLE, ioam_disable) \
+_(IOAM_ENABLE, ioam_enable) \
+_(IOAM_DISABLE, ioam_disable) \
_(LISP_ADD_DEL_LOCATOR_SET, lisp_add_del_locator_set) \
_(LISP_ADD_DEL_LOCATOR, lisp_add_del_locator) \
_(LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid) \
@@ -332,7 +332,8 @@ _(IP_FIB_DUMP, ip_fib_dump) \
_(IP_FIB_DETAILS, ip_fib_details) \
_(IP6_FIB_DUMP, ip6_fib_dump) \
_(IP6_FIB_DETAILS, ip6_fib_details) \
-_(FEATURE_ENABLE_DISABLE, feature_enable_disable)
+_(FEATURE_ENABLE_DISABLE, feature_enable_disable) \
+_(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del)
#define QUOTE_(x) #x
#define QUOTE(x) QUOTE_(x)
@@ -1997,8 +1998,10 @@ vl_api_tap_connect_t_handler (vl_api_tap_connect_t * mp, vlib_main_t * vm)
{
int rv;
vl_api_tap_connect_reply_t *rmp;
+ vnet_main_t *vnm = vnet_get_main ();
unix_shared_memory_queue_t *q;
u32 sw_if_index = (u32) ~ 0;
+ u8 *tag;
rv = vnet_tap_connect_renumber (vm, mp->tap_name,
mp->use_random_mac ? 0 : mp->mac_address,
@@ -2009,6 +2012,14 @@ vl_api_tap_connect_t_handler (vl_api_tap_connect_t * mp, vlib_main_t * vm)
if (!q)
return;
+ /* Add tag if supplied */
+ if (rv == 0 && mp->tag[0])
+ {
+ mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
+ tag = format (0, "%s%c", mp->tag, 0);
+ vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
+ }
+
rmp = vl_msg_api_alloc (sizeof (*rmp));
rmp->_vl_msg_id = ntohs (VL_API_TAP_CONNECT_REPLY);
rmp->context = mp->context;
@@ -2054,6 +2065,11 @@ vl_api_tap_delete_t_handler (vl_api_tap_delete_t * mp, vlib_main_t * vm)
u32 sw_if_index = ntohl (mp->sw_if_index);
rv = vnet_tap_delete (vm, sw_if_index);
+ if (!rv)
+ {
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_clear_sw_interface_tag (vnm, sw_if_index);
+ }
q = vl_api_client_index_to_input_queue (mp->client_index);
if (!q)
@@ -2684,7 +2700,9 @@ send_sw_interface_details (vpe_api_main_t * am,
u8 * interface_name, u32 context)
{
vl_api_sw_interface_details_t *mp;
+ vnet_main_t *vnm = vnet_get_main ();
vnet_hw_interface_t *hi;
+ u8 *tag;
hi = vnet_get_sup_hw_interface (am->vnet_main, swif->sw_if_index);
@@ -2752,6 +2770,10 @@ send_sw_interface_details (vpe_api_main_t * am,
}
}
+ tag = vnet_get_sw_interface_tag (vnm, swif->sw_if_index);
+ if (tag)
+ strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
+
vl_msg_api_send_shmem (q, (u8 *) & mp);
}
@@ -4020,7 +4042,6 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
int rv = 0;
vl_api_create_vhost_user_if_reply_t *rmp;
u32 sw_if_index = (u32) ~ 0;
-
vnet_main_t *vnm = vnet_get_main ();
vlib_main_t *vm = vlib_get_main ();
@@ -4029,6 +4050,19 @@ vl_api_create_vhost_user_if_t_handler (vl_api_create_vhost_user_if_t * mp)
mp->renumber, ntohl (mp->custom_dev_instance),
(mp->use_custom_mac) ? mp->mac_address : NULL);
+ /* Remember an interface tag for the new interface */
+ if (rv == 0)
+ {
+ /* If a tag was supplied... */
+ if (mp->tag[0])
+ {
+ /* Make sure it's a proper C-string */
+ mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
+ u8 *tag = format (0, "%s%c", mp->tag, 0);
+ vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
+ }
+ }
+
/* *INDENT-OFF* */
REPLY_MACRO2(VL_API_CREATE_VHOST_USER_IF_REPLY,
({
@@ -4074,6 +4108,7 @@ vl_api_delete_vhost_user_if_t_handler (vl_api_delete_vhost_user_if_t * mp)
if (!q)
return;
+ vnet_clear_sw_interface_tag (vnm, sw_if_index);
send_sw_interface_flags_deleted (vam, q, sw_if_index);
}
}
@@ -9113,6 +9148,37 @@ vl_api_feature_enable_disable_t_handler (vl_api_feature_enable_disable_t * mp)
REPLY_MACRO (VL_API_FEATURE_ENABLE_DISABLE_REPLY);
}
+static void vl_api_sw_interface_tag_add_del_t_handler
+ (vl_api_sw_interface_tag_add_del_t * mp)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vl_api_sw_interface_tag_add_del_reply_t *rmp;
+ int rv = 0;
+ u8 *tag;
+ u32 sw_if_index = ntohl (mp->sw_if_index);
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ if (mp->is_add)
+ {
+ if (mp->tag[0] == 0)
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
+ tag = format (0, "%s%c", mp->tag, 0);
+ vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
+ }
+ else
+ vnet_clear_sw_interface_tag (vnm, sw_if_index);
+
+ BAD_SW_IF_INDEX_LABEL;
+out:
+ REPLY_MACRO (VL_API_SW_INTERFACE_TAG_ADD_DEL_REPLY);
+}
+
#define BOUNCE_HANDLER(nn) \
static void vl_api_##nn##_t_handler ( \
vl_api_##nn##_t *mp) \
diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c
index 28d3341d..a36a8a43 100644
--- a/vpp/vpp-api/custom_dump.c
+++ b/vpp/vpp-api/custom_dump.c
@@ -431,7 +431,8 @@ static void *vl_api_tap_connect_t_print
s = format (s, "tapname %s ", mp->tap_name);
if (mp->use_random_mac)
s = format (s, "random-mac ");
-
+ if (mp->tag[0])
+ s = format (s, "tag %s ", mp->tag);
if (memcmp (mp->mac_address, null_mac, 6))
s = format (s, "mac %U ", format_ethernet_address, mp->mac_address);
@@ -1568,6 +1569,8 @@ static void *vl_api_create_vhost_user_if_t_print
s = format (s, "server ");
if (mp->renumber)
s = format (s, "renumber %d ", ntohl (mp->custom_dev_instance));
+ if (mp->tag[0])
+ s = format (s, "tag %s", mp->tag);
FINISH;
}
@@ -2926,6 +2929,21 @@ static void *vl_api_feature_enable_disable_t_print
FINISH;
}
+static void *vl_api_sw_interface_tag_add_del_t_print
+ (vl_api_sw_interface_tag_add_del_t * mp, void *handle)
+{
+ u8 *s;
+
+ s = format (0, "SCRIPT: sw_interface_tag_add_del ");
+ s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index));
+ if (mp->is_add)
+ s = format (s, "tag %s ", mp->tag);
+ else
+ s = format (s, "del ");
+
+ FINISH;
+}
+
#define foreach_custom_print_no_arg_function \
_(lisp_eid_table_vni_dump) \
_(lisp_map_resolver_dump) \
@@ -3098,7 +3116,8 @@ _(IOAM_ENABLE, ioam_enable) \
_(IOAM_DISABLE, ioam_disable) \
_(IP_FIB_DUMP, ip_fib_dump) \
_(IP6_FIB_DUMP, ip6_fib_dump) \
-_(FEATURE_ENABLE_DISABLE, feature_enable_disable)
+_(FEATURE_ENABLE_DISABLE, feature_enable_disable) \
+_(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del)
void
vl_msg_api_custom_dump_configure (api_main_t * am)
{
diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api
index 5ab21029..bcc3f4ec 100644
--- a/vpp/vpp-api/vpe.api
+++ b/vpp/vpp-api/vpe.api
@@ -117,6 +117,7 @@ define sw_interface_details
u32 vtr_push_dot1q; // ethertype of first pushed tag is dot1q/dot1ad
u32 vtr_tag1; // first pushed tag
u32 vtr_tag2; // second pushed tag
+ u8 tag[64];
};
/* works */
@@ -226,6 +227,7 @@ define tap_connect
u8 mac_address[6];
u8 renumber;
u32 custom_dev_instance;
+ u8 tag[64];
};
/** \brief Reply for tap connect request
@@ -2269,6 +2271,7 @@ define create_vhost_user_if
u32 custom_dev_instance;
u8 use_custom_mac;
u8 mac_address[6];
+ u8 tag[64];
};
/** \brief vhost-user interface create response
@@ -5518,3 +5521,28 @@ define feature_enable_disable_reply
u32 context;
i32 retval;
};
+
+/** \brief Set / clear software interface tag
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sw_if_index - the interface
+ @param add_del - 1 = add, 0 = delete
+ @param tag - an ascii tag
+*/
+define sw_interface_tag_add_del {
+ u32 client_index;
+ u32 context;
+ u8 is_add;
+ u32 sw_if_index;
+ u8 tag[64];
+};
+
+/** \brief Reply to set / clear software interface tag
+ @param context - sender context which was passed in the request
+ @param retval - return code for the request
+*/
+define sw_interface_tag_add_del_reply
+{
+ u32 context;
+ i32 retval;
+};