Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
488 changes: 244 additions & 244 deletions docs/graph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions docs/grout.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Grout is a software router based on DPDK __rte_graph__.
[**-s** _PATH_]
[**-t**]
[**-T** _REGEXP_]
[**-u** _MTU_]
[**-v**]
[**-V**]
[**-x**]
Expand Down Expand Up @@ -130,6 +131,12 @@ Global trace configuration for ALL the components:

Can be specified multiple times up to 32 times.

#### **-u**, **--max-mtu** _MTU_

Maximum Transmission Unit.

Default: _1800_.

#### **-v**, **--verbose**

Increase verbosity. Can be specified multiple times.
Expand Down
5 changes: 4 additions & 1 deletion main/dpdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ int dpdk_init(void) {
gr_vec_add(eal_args, "--no-shconf");
gr_vec_add(eal_args, "--no-huge");
gr_vec_add(eal_args, "-m");
gr_vec_add(eal_args, "2048");
if (gr_config.max_mtu > 2048)
gr_vec_add(eal_args, "4096");
else
gr_vec_add(eal_args, "2048");
} else {
gr_vec_add(eal_args, "--in-memory");
}
Expand Down
1 change: 1 addition & 0 deletions main/gr_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct gr_config {
gid_t api_sock_gid;
mode_t api_sock_mode;
unsigned log_level;
unsigned max_mtu;
bool test_mode;
bool poll_mode;
bool log_syslog;
Expand Down
36 changes: 33 additions & 3 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
// Please keep options/flags in alphabetical order.

static void usage(const char *prog) {
printf("Usage: %s [-h] [-L <type>:<lvl>] [-p] [-s <path>] [-t] [-T <regexp>]\n", prog);
printf(" %*s [-B <size>] [-D <path>] [-M <mode>] [-x] [-v] [-V]\n",
printf("Usage: %s [-h] [-L <type>:<lvl>] [-p] [-s <path>] [-t] [-u <mtu>]\n", prog);
printf(" %*s [-T <regexp>] [-B <size>] [-D <path>] [-M <mode>] [-x] [-v] [-V]\n",
(int)strlen(prog),
"");
puts("");
Expand All @@ -50,6 +50,7 @@ static void usage(const char *prog) {
puts(" Default: GROUT_SOCK_PATH from env or");
printf(" %s).\n", GR_DEFAULT_SOCK_PATH);
puts(" -t, --test-mode Run in test mode (no hugepages).");
puts(" -u, --max-mtu <mtu> Maximum Transmission Unit (default 1800).");
puts(" -T, --trace <regexp> Enable trace matching the regular expression.");
puts(" -B, --trace-bufsz <size> Maximum size of allocated memory for trace output.");
puts(" -D, --trace-dir <path> Change path for trace output.");
Expand Down Expand Up @@ -127,13 +128,37 @@ static int parse_sock_mode(const char *perm_str) {
return 0;
}

static int parse_max_mtu(const char *mtu) {
unsigned long val;
char *endptr;

errno = 0;
val = strtoul(mtu, &endptr, 10);

if (errno != 0 || *endptr != '\0' || val < 512 || val > 16384) {
if (errno == 0) {
if (*endptr != '\0')
errno = EINVAL;
else
errno = ERANGE;
}
fprintf(stderr, "error: invalid max-mtu '%s': %s\n", mtu, strerror(errno));
return -1;
}

gr_config.max_mtu = (unsigned)val;

return 0;
}

static int parse_args(int argc, char **argv) {
int c;

#define FLAGS ":B:D:L:M:T:Vhm:o:pSs:tvx"
#define FLAGS ":B:D:L:M:T:Vhm:o:pSs:tu:vx"
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"log-level", required_argument, NULL, 'L'},
{"max-mtu", required_argument, NULL, 'u'},
{"poll-mode", no_argument, NULL, 'p'},
{"syslog", no_argument, NULL, 'S'},
{"socket", required_argument, NULL, 's'},
Expand All @@ -158,6 +183,7 @@ static int parse_args(int argc, char **argv) {
gr_config.api_sock_uid = getuid();
gr_config.api_sock_gid = getgid();
gr_config.api_sock_mode = 0660;
gr_config.max_mtu = 1800;
gr_config.log_level = RTE_LOG_NOTICE;
gr_config.eal_extra_args = NULL;

Expand Down Expand Up @@ -205,6 +231,10 @@ static int parse_args(int argc, char **argv) {
case 'x':
gr_config.log_packets = true;
break;
case 'u':
if (parse_max_mtu(optarg) < 0)
return errno_set(EINVAL);
break;
case 'v':
gr_config.log_level++;
break;
Expand Down
20 changes: 15 additions & 5 deletions modules/infra/control/mempool.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2024 Christophe Fontaine

#include <gr_config.h>
#include <gr_log.h>
#include <gr_mbuf.h>
#include <gr_mempool.h>
Expand All @@ -14,6 +15,8 @@ struct mempool_tracker {

#define MAX_MEMPOOL_PER_NUMA 32
#define MEMPOOL_DEFAULT_SIZE (1 << 16) - 1
#define ETHER_HDR_SIZE 14
#define VLAN_HDR_SIZE 4

static int mt_sort(const void *p1, const void *p2) {
const struct mempool_tracker *mt1 = p1;
Expand All @@ -37,10 +40,15 @@ struct rte_mempool *gr_pktmbuf_pool_get(int8_t socket_id, uint32_t count) {
char mp_name[RTE_MEMPOOL_NAMESIZE];
struct rte_mempool *mp = NULL;
uint32_t alloc_size;
uint32_t mbuf_size;

if (socket_id < SOCKET_ID_ANY || socket_id >= RTE_MAX_NUMA_NODES)
return errno_set_null(EINVAL);

mbuf_size = rte_align32pow2(
RTE_PKTMBUF_HEADROOM + ETHER_HDR_SIZE + VLAN_HDR_SIZE + gr_config.max_mtu
);

for (int i = 0; i < MAX_MEMPOOL_PER_NUMA; i++) {
unsigned mt_index = socket_id == SOCKET_ID_ANY ? 0 : socket_id + 1;
struct mempool_tracker *mt = &trackers[mt_index][i];
Expand All @@ -54,16 +62,17 @@ struct rte_mempool *gr_pktmbuf_pool_get(int8_t socket_id, uint32_t count) {
}
sprintf(mp_name, "mbuf_%d:%d", socket_id, i);
LOG(DEBUG,
"allocate mempool %s reserved %u (size %u)",
"allocate mempool %s reserved %u (size %u, mbuf_size %u)",
mp_name,
count,
alloc_size);
alloc_size,
mbuf_size);
mt->mp = rte_pktmbuf_pool_create(
mp_name,
alloc_size,
RTE_MEMPOOL_CACHE_MAX_SIZE,
GR_MBUF_PRIV_MAX_SIZE,
RTE_MBUF_DEFAULT_BUF_SIZE,
mbuf_size,
socket_id
);
if (mt->mp == NULL)
Expand All @@ -73,11 +82,12 @@ struct rte_mempool *gr_pktmbuf_pool_get(int8_t socket_id, uint32_t count) {
break;
} else if ((count + mt->reserved) <= mt->mp->size) {
LOG(DEBUG,
"reuse mempool %s reserved %u -> %u (size %u)",
"reuse mempool %s reserved %u -> %u (size %u, mbuf_size %u)",
mt->mp->name,
mt->reserved,
mt->reserved + count,
mt->mp->size);
mt->mp->size,
mbuf_size);
mt->reserved += count;
mp = mt->mp;
break;
Expand Down
19 changes: 12 additions & 7 deletions modules/infra/control/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <gr_port.h>
#include <gr_queue.h>
#include <gr_vec.h>
#include <gr_vlan.h>
#include <gr_worker.h>

#include <numa.h>
Expand Down Expand Up @@ -72,12 +73,7 @@ static struct rte_eth_conf default_port_config = {
},
},
.rxmode = {
.offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM
| RTE_ETH_RX_OFFLOAD_VLAN
| RTE_ETH_RX_OFFLOAD_SCATTER,
},
.txmode = {
.offloads = RTE_ETH_TX_OFFLOAD_MULTI_SEGS,
.offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM | RTE_ETH_RX_OFFLOAD_VLAN,
},
};

Expand Down Expand Up @@ -128,7 +124,6 @@ int port_configure(struct iface_info_port *p, uint16_t n_txq_min) {
else
conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
conf.rxmode.offloads &= info.rx_offload_capa;
conf.txmode.offloads &= info.tx_offload_capa;
if (info.dev_flags != NULL && *info.dev_flags & RTE_ETH_DEV_INTR_LSC) {
conf.intr_conf.lsc = 1;
}
Expand Down Expand Up @@ -162,6 +157,9 @@ static int iface_port_reconfig(
bool needs_configure = false;
int ret;

if ((set_attrs & GR_IFACE_SET_MTU) && conf->mtu > gr_config.max_mtu)
return errno_set(ERANGE);

if ((ret = port_unplug(p->port_id)) < 0)
return ret;

Expand Down Expand Up @@ -254,6 +252,13 @@ static int iface_port_reconfig(
return errno_log(-ret, "rte_eth_dev_get_mtu");
}

struct iface *v = NULL;
while ((v = iface_next(GR_IFACE_TYPE_VLAN, v)) != NULL) {
struct iface_info_vlan *vlan = (struct iface_info_vlan *)v->info;
if (vlan->parent_id == iface->id)
v->mtu = iface->mtu;
}

if (set_attrs & GR_IFACE_SET_MODE)
iface->mode = conf->mode;

Expand Down
3 changes: 1 addition & 2 deletions modules/infra/control/vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,9 @@ static int iface_vlan_reconfig(

if (set_attrs & GR_IFACE_SET_FLAGS)
iface->flags = conf->flags;
if (set_attrs & GR_IFACE_SET_MTU)
iface->mtu = conf->mtu ? conf->mtu : iface_from_id(cur->parent_id)->mtu;
if (set_attrs & GR_IFACE_SET_VRF)
iface->vrf_id = conf->vrf_id;
iface->mtu = iface_from_id(cur->parent_id)->mtu;

gr_event_push(GR_EVENT_IFACE_POST_RECONFIG, iface);

Expand Down
9 changes: 9 additions & 0 deletions modules/ip/datapath/ip_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum {
HOLD,
NO_ROUTE,
ERROR,
TOO_BIG,
EDGE_COUNT,
};

Expand Down Expand Up @@ -83,6 +84,12 @@ ip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, u
edge = ERROR;
goto next;
}

if (rte_pktmbuf_pkt_len(mbuf) > iface->mtu) {
edge = TOO_BIG;
goto next;
}

// Determine what is the next node based on the output interface type
// By default, it will be eth_output unless another output node was registered.
edge = iface_type_edges[iface->type];
Expand Down Expand Up @@ -133,6 +140,7 @@ static struct rte_node_register output_node = {
[HOLD] = "ip_hold",
[NO_ROUTE] = "ip_error_dest_unreach",
[ERROR] = "ip_output_error",
[TOO_BIG] = "ip_output_too_big",
},
};

Expand All @@ -144,3 +152,4 @@ static struct gr_node_info info = {
GR_NODE_REGISTER(info);

GR_DROP_REGISTER(ip_output_error);
GR_DROP_REGISTER(ip_output_too_big);
9 changes: 9 additions & 0 deletions modules/ip6/datapath/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum {
HOLD,
DEST_UNREACH,
ERROR,
TOO_BIG,
EDGE_COUNT,
};

Expand Down Expand Up @@ -83,6 +84,12 @@ ip6_output_process(struct rte_graph *graph, struct rte_node *node, void **objs,
edge = ERROR;
goto next;
}

if (rte_pktmbuf_pkt_len(mbuf) > iface->mtu) {
edge = TOO_BIG;
goto next;
}

// Determine what is the next node based on the output interface type
// By default, it will be eth_output unless another output node was registered.
edge = iface_type_edges[iface->type];
Expand Down Expand Up @@ -128,6 +135,7 @@ static struct rte_node_register output_node = {
[HOLD] = "ip6_hold",
[ERROR] = "ip6_output_error",
[DEST_UNREACH] = "ip6_error_dest_unreach",
[TOO_BIG] = "ip6_output_too_big",
},
};

Expand All @@ -139,3 +147,4 @@ static struct gr_node_info info = {
GR_NODE_REGISTER(info);

GR_DROP_REGISTER(ip6_output_error);
GR_DROP_REGISTER(ip6_output_too_big);
2 changes: 1 addition & 1 deletion modules/ipip/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static int iface_ipip_fini(struct iface *iface) {
static int iface_ipip_init(struct iface *iface, const void *api_info) {
const struct gr_iface conf = {
.flags = iface->flags,
.mtu = iface->mtu,
.mtu = iface->mtu ?: 1480,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which case, iface->mtu is zero ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless users have specified a value for mtu in the initial interface creation message, it will be 0. It was OK until now since we'll drop packets that are bigger than output interface MTU.

I chose to initialize it to 1480 which seems like a good default.

.mode = iface->mode,
.vrf_id = iface->vrf_id
};
Expand Down
10 changes: 5 additions & 5 deletions smoke/ip_forward_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
p0=${run_id}0
p1=${run_id}1

grcli add interface port $p0 devargs net_tap0,iface=$p0 mac f0:0d:ac:dc:00:00 mtu 9000
grcli add interface port $p1 devargs net_tap1,iface=$p1 mac f0:0d:ac:dc:00:01 mtu 9000
grcli add interface port $p0 devargs net_tap0,iface=$p0 mac f0:0d:ac:dc:00:00
grcli add interface port $p1 devargs net_tap1,iface=$p1 mac f0:0d:ac:dc:00:01
grcli add ip address 172.16.0.1/24 iface $p0
grcli add ip address 172.16.1.1/24 iface $p1
grcli add ip route 16.0.0.0/16 via 172.16.0.2
Expand All @@ -19,7 +19,7 @@ for n in 0 1; do
p=$run_id$n
netns_add $p
ip link set $p netns $p
ip -n $p link set $p address ba:d0:ca:ca:00:0$n mtu 9000
ip -n $p link set $p address ba:d0:ca:ca:00:0$n
ip -n $p link set $p up
ip -n $p link set lo up
ip -n $p addr add 172.16.$n.2/24 dev $p
Expand All @@ -28,8 +28,8 @@ for n in 0 1; do
ip -n $p addr show
done

ip netns exec $p0 ping -i0.01 -c3 -n 16.1.0.1 -s 5000
ip netns exec $p1 ping -i0.01 -c3 -n 16.0.0.1 -s 5000
ip netns exec $p0 ping -i0.01 -c3 -n 16.1.0.1
ip netns exec $p1 ping -i0.01 -c3 -n 16.0.0.1
ip netns exec $p0 ping -i0.01 -c3 -n 172.16.1.2
ip netns exec $p1 ping -i0.01 -c3 -n 172.16.0.2
ip netns exec $p0 ping -i0.01 -c3 -n 172.16.0.1
Expand Down