Skip to content

Commit

Permalink
Add a tool to inspect dpservice tables
Browse files Browse the repository at this point in the history
  • Loading branch information
PlagueCZ committed Dec 17, 2024
1 parent c8b02cb commit 01cec9f
Show file tree
Hide file tree
Showing 43 changed files with 1,379 additions and 15 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ WORKDIR /
COPY --from=builder \
/workspace/build/src/dpservice-bin \
/workspace/build/tools/dump/dpservice-dump \
/workspace/build/tools/inspect/dpservice-inspect \
/workspace/build/cli/dpservice-cli/dpservice-cli \
/workspace/build/cli/dpservice-exporter/dpservice-exporter \
/workspace/hack/prepare.sh \
Expand Down
7 changes: 6 additions & 1 deletion docs/deployment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ For development, direct use of dp-service is covered by the [development section
## Command-line tools
All tool binaries are designed to be prefixed with `dpservice-` to enable the operator to simply type `dps<TAB>` for list of possible tools.

The provided Docker image contains `dpservice-bin` as the main process (already started by being the entrypoint), `dpservice-cli` to gRPC communication with the main process, and `dpservice-dump` to provide a way to see the actual traffic handled by dp-service. Also included is `dpservice-exporter`, a Prometheus exporter that can export various statistics about dpservice (interface stats, NAT port usage, hash table fullness, ...)
The provided Docker image contains:
- `dpservice-bin`, the main process (already started by being the entrypoint)
- `dpservice-cli`, gRPC client connecting to the main process, [documentation](../../cli/dpservice-cli/docs/)
- `dpservice-dump`, tool to provide a way to see the actual traffic handled by dp-service, [documentation](dpservice-dump.md)
- `dpservice-inspect`, tool to view internal state of dp-service, [documentation](dpservice-inspect.md)
- `dpservice-exporter`, a Prometheus exporter that can export various statistics about dpservice (interface stats, NAT port usage, hash table fullness, ...)
3 changes: 2 additions & 1 deletion docs/deployment/dpservice-dump.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Always make sure that the tool detaches cleanly (i.e. prints out `Graphtrace suc

## Examples
`dpservice-dump` prints all ingress/egress packets processed by dp-service.

`dpservice-dump --drops` also prints dropped packets.
`dpservice-dump --nodes` also prints packets as they are [going through the graph](../concepts/graphtrace.md)

`dpservice-dump --nodes` also prints packets as they are [going through the graph](../concepts/graphtrace.md)
19 changes: 19 additions & 0 deletions docs/deployment/dpservice-inspect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Dataplane Service Internal Inspection Tool
`dpservice-inspect` is a tool to see internal state of dp-service. Currently, only hash-tables are accessible.

## Command-line Options
All options are described in `dpservice-inspect --help`, see [the markdown version of it](help_dpservice-inspect.md)

## Disclaimer
As this tool attaches to a live packet-processing dp-service, use it with caution. It should not cause performance degradation in packet-processing since the tool only reads shared-memory in a separate process.

## Examples
`dpservice-inspect` prints all supported hash-tables that can be viewed.

`dpservice-inspect -t <table>` prints the number of entries in a given table

`dpservice-inspect -t <table> --dump` prints the contents of the table

You can choose the output format using `-o`.

> By default, this tool uses `-1` as the NUMA socket. In practice dp-service will be utilizing NUMA and you need to specify it via `-s`.
13 changes: 13 additions & 0 deletions docs/deployment/help_dpservice-inspect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Command-line Options

| Option | Argument | Description | Choices |
|--------|----------|-------------|---------|
| -h, --help | None | display this help and exit | |
| -v, --version | None | display version and exit | |
| -o, --output-format | FORMAT | format of the output | 'human' (default), 'table', 'csv' or 'json' |
| -t, --table | NAME | hash table to choose | 'list' (default), 'conntrack', 'dnat', 'iface', 'lb', 'lb_id', 'portmap', 'portoverload', 'snat', 'vnf', 'vnf_rev' or 'vni' |
| -s, --socket | NUMBER | NUMA socket to use | |
| --dump | None | dump table contents | |

> This file has been generated by dp_conf_generate.py. As such it should fully reflect the output of `--help`.
1 change: 1 addition & 0 deletions include/dp_flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
extern "C" {
#endif

#define DP_FLOW_TABLE_NAME "conntrack_table"
// arbitrary big number
#define DP_FLOW_TABLE_MAX 850000

Expand Down
2 changes: 2 additions & 0 deletions include/dp_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
extern "C" {
#endif

#define DP_IFACE_TABLE_NAME "interface_table"

int dp_ifaces_init(int socket_id);
void dp_ifaces_free(void);

Expand Down
2 changes: 2 additions & 0 deletions include/dp_lb.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ extern "C" {
#include "dp_flow.h"
#include "grpc/dp_grpc_responder.h"

#define DP_LB_TABLE_NAME "loadbalancer_table"
#define DP_LB_ID_TABLE_NAME "loadbalancer_id_table"
#define DP_LB_TABLE_MAX 256
#define DP_LB_MAX_IPS_PER_VIP 64
/* Needs to be a prime number at least 2xDP_LB_MAX_IPS_PER_VIP for a uniform distribution */
Expand Down
5 changes: 5 additions & 0 deletions include/dp_nat.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
extern "C" {
#endif

#define DP_NAT_DNAT_TABLE_NAME "dnat_table"
#define DP_NAT_SNAT_TABLE_NAME "snat_table"
#define DP_NAT_PORTMAP_TABLE_NAME "nat_portmap_table"
#define DP_NAT_PORTOVERLOAD_TABLE_NAME "nat_portoverload_table"

#define DP_NETWORK_NAT_ALL_VNI 0

struct nat_key {
Expand Down
6 changes: 6 additions & 0 deletions include/dp_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ int dp_get_dev_info(uint16_t port_id, struct rte_eth_dev_info *dev_info, char if
int dp_get_num_of_vfs(void);


static __rte_always_inline
int dp_get_jhash_table_full_name(const char *name, int socket_id, char *dest, size_t dest_size)
{
return snprintf(dest, dest_size, "%s_%d", name, socket_id);
}

struct rte_hash *dp_create_jhash_table(int capacity, size_t key_len, const char *name, int socket_id);

void dp_free_jhash_table(struct rte_hash *table);
Expand Down
3 changes: 3 additions & 0 deletions include/dp_vnf.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
extern "C" {
#endif

#define DP_VNF_TABLE_NAME "vnf_table"
#define DP_VNF_REVERSE_TABLE_NAME "reverse_vnf_table"

#define DP_VNF_MATCH_ALL_PORT_IDS 0xFFFF

// forward declaration as 'struct dp_grpc_responder' needs some definitions from here
Expand Down
2 changes: 2 additions & 0 deletions include/dp_vni.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ extern "C" {

extern struct rte_hash *vni_handle_tbl;

#define DP_VNI_TABLE_NAME "vni_table"

#define DP_VNI_MAX_TABLE_SIZE 512

// Protect array access
Expand Down
2 changes: 1 addition & 1 deletion src/dp_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static bool offload_mode_enabled = 0;
int dp_flow_init(int socket_id)
{
flow_table = dp_create_jhash_table(DP_FLOW_TABLE_MAX, sizeof(struct flow_key),
"conntrack_table", socket_id);
DP_FLOW_TABLE_NAME, socket_id);
if (!flow_table)
return DP_ERROR;

Expand Down
2 changes: 1 addition & 1 deletion src/dp_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ static struct rte_hash *iface_id_table = NULL;
int dp_ifaces_init(int socket_id)
{
iface_id_table = dp_create_jhash_table(DP_MAX_PORTS, DP_IFACE_ID_MAX_LEN,
"interface_table", socket_id);
DP_IFACE_TABLE_NAME, socket_id);
if (!iface_id_table)
return DP_ERROR;

Expand Down
4 changes: 2 additions & 2 deletions src/dp_lb.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ static struct rte_hash *id_map_lb_tbl = NULL;
int dp_lb_init(int socket_id)
{
lb_table = dp_create_jhash_table(DP_LB_TABLE_MAX, sizeof(struct lb_key),
"loadbalancer_table", socket_id);
DP_LB_TABLE_NAME, socket_id);
if (!lb_table)
return DP_ERROR;

id_map_lb_tbl = dp_create_jhash_table(DP_LB_TABLE_MAX, DP_LB_ID_MAX_LEN,
"loadbalancer_id_table", socket_id);
DP_LB_ID_TABLE_NAME, socket_id);
if (!id_map_lb_tbl)
return DP_ERROR;

Expand Down
8 changes: 4 additions & 4 deletions src/dp_nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,23 @@ static uint64_t dp_nat_full_log_delay;
int dp_nat_init(int socket_id)
{
ipv4_snat_tbl = dp_create_jhash_table(DP_NAT_TABLE_MAX, sizeof(struct nat_key),
"snat_table", socket_id);
DP_NAT_SNAT_TABLE_NAME, socket_id);
if (!ipv4_snat_tbl)
return DP_ERROR;

ipv4_dnat_tbl = dp_create_jhash_table(DP_NAT_TABLE_MAX, sizeof(struct nat_key),
"dnat_table", socket_id);
DP_NAT_DNAT_TABLE_NAME, socket_id);
if (!ipv4_dnat_tbl)
return DP_ERROR;

ipv4_netnat_portmap_tbl = dp_create_jhash_table(DP_FLOW_TABLE_MAX, sizeof(struct netnat_portmap_key),
"nat_portmap_table", socket_id);
DP_NAT_PORTMAP_TABLE_NAME, socket_id);

if (!ipv4_netnat_portmap_tbl)
return DP_ERROR;

ipv4_netnat_portoverload_tbl = dp_create_jhash_table(DP_FLOW_TABLE_MAX, sizeof(struct netnat_portoverload_tbl_key),
"nat_portoverload_table", socket_id);
DP_NAT_PORTOVERLOAD_TABLE_NAME, socket_id);

if (!ipv4_netnat_portoverload_tbl)
return DP_ERROR;
Expand Down
4 changes: 2 additions & 2 deletions src/dp_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ struct rte_hash *dp_create_jhash_table(int capacity, size_t key_len, const char
else
hash_func = rte_jhash;

if ((unsigned int)snprintf(full_name, sizeof(full_name), "%s_%d", name, socket_id) >= RTE_HASH_NAMESIZE) {
DPS_LOG_ERR("jhash table name is too long", DP_LOG_NAME(full_name));
if (DP_FAILED(dp_get_jhash_table_full_name(name, socket_id, full_name, sizeof(full_name)))) {
DPS_LOG_ERR("jhash table name is too long", DP_LOG_NAME(name));
return NULL;
}

Expand Down
4 changes: 2 additions & 2 deletions src/dp_vnf.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ static struct rte_hash *vnf_value_tbl = NULL;
int dp_vnf_init(int socket_id)
{
vnf_handle_tbl = dp_create_jhash_table(DP_VNF_MAX_TABLE_SIZE, sizeof(union dp_ipv6),
"vnf_table", socket_id);
DP_VNF_TABLE_NAME, socket_id);
if (!vnf_handle_tbl)
return DP_ERROR;

vnf_value_tbl = dp_create_jhash_table(DP_VNF_MAX_TABLE_SIZE, sizeof(struct dp_vnf),
"reverse_vnf_table", socket_id);
DP_VNF_REVERSE_TABLE_NAME, socket_id);
if (!vnf_value_tbl) {
dp_free_jhash_table(vnf_handle_tbl);
return DP_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion src/dp_vni.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct rte_hash *vni_handle_tbl = NULL;
int dp_vni_init(int socket_id)
{
vni_handle_tbl = dp_create_jhash_table(DP_VNI_MAX_TABLE_SIZE, sizeof(struct dp_vni_key),
"vni_table", socket_id);
DP_VNI_TABLE_NAME, socket_id);
if (!vni_handle_tbl)
return DP_ERROR;

Expand Down
30 changes: 30 additions & 0 deletions tools/inspect/common_ip.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

#include "common_ip.h"

#include <stdio.h>
#include <arpa/inet.h>

char str_proto[16];

const char *get_str_ipproto(uint8_t proto)
{
switch (proto) {
case IPPROTO_IP:
return "ip";
case IPPROTO_ICMP:
return "icmp";
case IPPROTO_IPIP:
return "ipip";
case IPPROTO_TCP:
return "tcp";
case IPPROTO_UDP:
return "udp";
case IPPROTO_IPV6:
return "ipv6";
default:
snprintf(str_proto, sizeof(str_proto), "%u", proto);
return str_proto;
}
}
11 changes: 11 additions & 0 deletions tools/inspect/common_ip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

#ifndef __COMMON_IP_H__
#define __COMMON_IP_H__

#include <stdint.h>

const char *get_str_ipproto(uint8_t proto);

#endif
25 changes: 25 additions & 0 deletions tools/inspect/common_vnf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

#include "common_vnf.h"

const char *get_str_vnftype(enum dp_vnf_type type)
{
switch (type) {
case DP_VNF_TYPE_UNDEFINED:
return "none";
case DP_VNF_TYPE_LB_ALIAS_PFX:
return "lb_pfx";
case DP_VNF_TYPE_ALIAS_PFX:
return "pfx";
case DP_VNF_TYPE_LB:
return "lb";
case DP_VNF_TYPE_VIP:
return "vip";
case DP_VNF_TYPE_NAT:
return "nat";
case DP_VNF_TYPE_INTERFACE_IP:
return "iface";
}
return "?";
}
11 changes: 11 additions & 0 deletions tools/inspect/common_vnf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

#ifndef __COMMON_VNF_H__
#define __COMMON_VNF_H__

#include "dp_vnf.h"

const char *get_str_vnftype(enum dp_vnf_type type);

#endif
43 changes: 43 additions & 0 deletions tools/inspect/dp_conf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"header": "opts.h",
"source": "opts.c",
"markdown": "../../docs/deployment/help_dpservice-inspect.md",
"options": [
{
"shopt": "o",
"lgopt": "output-format",
"arg": "FORMAT",
"help": "format of the output",
"var": "output_format",
"type": "enum",
"choices": [ "human", "table", "csv", "json" ],
"default": "human"
},
{
"shopt": "t",
"lgopt": "table",
"arg": "NAME",
"help": "hash table to choose",
"var": "table",
"type": "enum",
"choices": [ "list", "conntrack", "dnat", "iface", "lb", "lb_id", "portmap", "portoverload", "snat", "vnf", "vnf_rev", "vni" ],
"default": "list"
},
{
"shopt": "s",
"lgopt": "socket",
"arg": "NUMBER",
"help": "NUMA socket to use",
"var": "numa_socket",
"type": "int",
"default": -1
},
{
"lgopt": "dump",
"help": "dump table contents",
"var": "dump",
"type": "bool",
"default": "false"
}
]
}
Loading

0 comments on commit 01cec9f

Please sign in to comment.