Skip to content

Commit

Permalink
iface: add vlan subinterface support
Browse files Browse the repository at this point in the history
Signed-off-by: Robin Jarry <[email protected]>
  • Loading branch information
rjarry committed May 28, 2024
1 parent 2559ac1 commit 260b670
Show file tree
Hide file tree
Showing 17 changed files with 682 additions and 102 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
path: ~/.ccache
key: ccache
- run: make
- run: make coverage
- run: make test
lint:
runs-on: ubuntu-latest
container: fedora:latest
Expand Down
15 changes: 15 additions & 0 deletions modules/infra/api/br_infra.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// Value for br_iface.type
#define BR_IFACE_TYPE_UNDEF 0x0000
#define BR_IFACE_TYPE_PORT 0x0001
#define BR_IFACE_TYPE_VLAN 0x0002

// Interface configure flags
#define BR_IFACE_F_UP BR_BIT16(0)
Expand Down Expand Up @@ -61,6 +62,20 @@ struct br_iface_info_port {

static_assert(sizeof(struct br_iface_info_port) <= MEMBER_SIZE(struct br_iface, info));

// VLAN reconfig attributes
#define BR_VLAN_SET_PARENT BR_BIT64(32)
#define BR_VLAN_SET_VLAN BR_BIT64(33)
#define BR_VLAN_SET_MAC BR_BIT64(34)

// Info for BR_IFACE_TYPE_VLAN interfaces
struct br_iface_info_vlan {
uint16_t parent_id;
uint16_t vlan_id;
struct eth_addr mac;
};

static_assert(sizeof(struct br_iface_info_vlan) <= MEMBER_SIZE(struct br_iface, info));

struct br_port_rxq_map {
uint16_t iface_id;
uint16_t rxq_id;
Expand Down
8 changes: 5 additions & 3 deletions modules/infra/cli/br_cli_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ struct cli_iface_type {
STAILQ_ENTRY(cli_iface_type) next;
uint16_t type_id;
const char *name;
void (*show)(const struct br_iface *);
void (*list_info)(const struct br_iface *, char *, size_t);
void (*show)(const struct br_api_client *c, const struct br_iface *);
void (*list_info)(const struct br_api_client *c, const struct br_iface *, char *, size_t);
};

void register_iface_type(struct cli_iface_type *);
Expand Down Expand Up @@ -46,10 +46,12 @@ int complete_iface_names(

#define INT2PTR(i) (void *)(uintptr_t)(i)

#define IFACE_ATTRS_CMD "(up|down),(mtu MTU),(vrf VRF)"
#define IFACE_ATTRS_CMD "(up|down),(promisc PROMISC),(allmulti ALLMULTI),(mtu MTU),(vrf VRF)"

#define IFACE_ATTRS_ARGS \
with_help("Set the interface UP.", ec_node_str("up", "up")), \
with_help("Enable/disable promiscuous mode.", ec_node_re("PROMISC", "on|off")), \
with_help("Enable/disable all-multicast mode.", ec_node_re("ALLMULTI", "on|off")), \
with_help("Set the interface DOWN.", ec_node_str("down", "down")), \
with_help( \
"Maximum transmision unit size.", \
Expand Down
23 changes: 20 additions & 3 deletions modules/infra/cli/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ uint64_t parse_iface_args(
struct br_iface *iface,
bool update
) {
const char *name;
const char *name, *promisc, *allmulti;
uint64_t set_attrs = 0;

name = arg_str(p, "NAME");
Expand All @@ -177,6 +177,23 @@ uint64_t parse_iface_args(
iface->flags &= ~BR_IFACE_F_UP;
set_attrs |= BR_IFACE_SET_FLAGS;
}
promisc = arg_str(p, "PROMISC");
if (promisc != NULL && strcmp(promisc, "on") == 0) {
iface->flags |= BR_IFACE_F_PROMISC;
set_attrs |= BR_IFACE_SET_FLAGS;
} else if (promisc != NULL && strcmp(promisc, "off") == 0) {
iface->flags &= ~BR_IFACE_F_PROMISC;
set_attrs |= BR_IFACE_SET_FLAGS;
}

allmulti = arg_str(p, "ALLMULTI");
if (allmulti != NULL && strcmp(allmulti, "on") == 0) {
iface->flags |= BR_IFACE_F_ALLMULTI;
set_attrs |= BR_IFACE_SET_FLAGS;
} else if (allmulti != NULL && strcmp(allmulti, "off") == 0) {
iface->flags &= ~BR_IFACE_F_ALLMULTI;
set_attrs |= BR_IFACE_SET_FLAGS;
}

if (arg_u16(p, "MTU", &iface->mtu) == 0)
set_attrs |= BR_IFACE_SET_MTU;
Expand Down Expand Up @@ -273,7 +290,7 @@ static cmd_status_t iface_list(const struct br_api_client *c, const struct ec_pn
} else {
scols_line_set_data(line, 3, type->name);
// info
type->list_info(iface, buf, sizeof(buf));
type->list_info(c, iface, buf, sizeof(buf));
scols_line_set_data(line, 4, buf);
}
}
Expand Down Expand Up @@ -319,7 +336,7 @@ static cmd_status_t iface_show(const struct br_api_client *c, const struct ec_pn
printf("type: %u\n", iface.type);
} else {
printf("type: %s\n", type->name);
type->show(&iface);
type->show(c, &iface);
}

return CMD_SUCCESS;
Expand Down
1 change: 1 addition & 0 deletions modules/infra/cli/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ cli_src += files(
'graph.c',
'iface.c',
'port.c',
'vlan.c',
'stats.c',
)

Expand Down
36 changes: 7 additions & 29 deletions modules/infra/cli/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <errno.h>
#include <sys/queue.h>

static void port_show(const struct br_iface *iface) {
static void port_show(const struct br_api_client *, const struct br_iface *iface) {
const struct br_iface_info_port *port = (const struct br_iface_info_port *)iface->info;
printf("devargs: %s\n", port->devargs);
printf("mac: " ETH_ADDR_FMT "\n", ETH_BYTES_SPLIT(port->mac.bytes));
Expand All @@ -25,7 +25,8 @@ static void port_show(const struct br_iface *iface) {
printf("txq_size: %u\n", port->txq_size);
}

static void port_list_info(const struct br_iface *iface, char *buf, size_t len) {
static void
port_list_info(const struct br_api_client *, const struct br_iface *iface, char *buf, size_t len) {
const struct br_iface_info_port *port = (const struct br_iface_info_port *)iface->info;
snprintf(
buf,
Expand All @@ -49,27 +50,9 @@ static uint64_t parse_port_args(
struct br_iface *iface,
bool update
) {
const char *promisc, *allmulti, *devargs;
struct br_iface_info_port *port;
uint64_t set_attrs = parse_iface_args(c, p, iface, update);

promisc = arg_str(p, "PROMISC");
if (promisc != NULL && strcmp(promisc, "on") == 0) {
iface->flags |= BR_IFACE_F_PROMISC;
set_attrs |= BR_IFACE_SET_FLAGS;
} else if (promisc != NULL && strcmp(promisc, "off") == 0) {
iface->flags &= ~BR_IFACE_F_PROMISC;
set_attrs |= BR_IFACE_SET_FLAGS;
}

allmulti = arg_str(p, "ALLMULTI");
if (allmulti != NULL && strcmp(allmulti, "on") == 0) {
iface->flags |= BR_IFACE_F_ALLMULTI;
set_attrs |= BR_IFACE_SET_FLAGS;
} else if (allmulti != NULL && strcmp(allmulti, "off") == 0) {
iface->flags &= ~BR_IFACE_F_ALLMULTI;
set_attrs |= BR_IFACE_SET_FLAGS;
}
struct br_iface_info_port *port;
const char *devargs;

port = (struct br_iface_info_port *)iface->info;
devargs = arg_str(p, "DEVARGS");
Expand Down Expand Up @@ -204,15 +187,10 @@ static cmd_status_t rxq_list(const struct br_api_client *c, const struct ec_pnod
return CMD_SUCCESS;
}

#define PORT_ATTRS_CMD \
IFACE_ATTRS_CMD ",(promisc PROMISC),(allmulti ALLMULTI),(mac MAC)," \
"(rxqs N_RXQ),(qsize Q_SIZE)"
#define PORT_ATTRS_CMD IFACE_ATTRS_CMD ",(mac MAC),(rxqs N_RXQ),(qsize Q_SIZE)"

#define PORT_ATTRS_ARGS \
IFACE_ATTRS_ARGS, \
with_help("Enable/disable promiscuous mode.", ec_node_re("PROMISC", "on|off")), \
with_help("Enable/disable all-multicast mode.", ec_node_re("ALLMULTI", "on|off")), \
with_help("Set the ethernet address.", ec_node_re("MAC", ETH_ADDR_RE)), \
IFACE_ATTRS_ARGS, with_help("Set the ethernet address.", ec_node_re("MAC", ETH_ADDR_RE)), \
with_help("Number of Rx queues.", ec_node_uint("N_RXQ", 0, UINT16_MAX - 1, 10)), \
with_help("Rx/Tx queues size.", ec_node_uint("Q_SIZE", 0, UINT16_MAX - 1, 10))

Expand Down
179 changes: 179 additions & 0 deletions modules/infra/cli/vlan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2023 Robin Jarry

#include "br_cli_iface.h"

#include <br_api.h>
#include <br_cli.h>
#include <br_infra.h>
#include <br_net_types.h>
#include <br_table.h>

#include <ecoli.h>
#include <libsmartcols.h>

#include <errno.h>
#include <sys/queue.h>

static void vlan_show(const struct br_api_client *c, const struct br_iface *iface) {
const struct br_iface_info_vlan *vlan = (const struct br_iface_info_vlan *)iface->info;
struct br_iface parent;

if (iface_from_id(c, vlan->parent_id, &parent) < 0)
printf("parent: %u\n", vlan->parent_id);
else
printf("parent: %s\n", parent.name);
printf("vlan_id: %u\n", vlan->vlan_id);
}

static void
vlan_list_info(const struct br_api_client *c, const struct br_iface *iface, char *buf, size_t len) {
const struct br_iface_info_vlan *vlan = (const struct br_iface_info_vlan *)iface->info;
struct br_iface parent;

if (iface_from_id(c, vlan->parent_id, &parent) < 0)
snprintf(buf, len, "parent=%u vlan_id=%u", vlan->parent_id, vlan->vlan_id);
else
snprintf(buf, len, "parent=%s vlan_id=%u", parent.name, vlan->vlan_id);
}

static struct cli_iface_type vlan_type = {
.type_id = BR_IFACE_TYPE_VLAN,
.name = "vlan",
.show = vlan_show,
.list_info = vlan_list_info,
};

static uint64_t parse_vlan_args(
const struct br_api_client *c,
const struct ec_pnode *p,
struct br_iface *iface,
bool update
) {
uint64_t set_attrs = parse_iface_args(c, p, iface, update);
struct br_iface_info_vlan *vlan;
const char *parent_name;
struct br_iface parent;

vlan = (struct br_iface_info_vlan *)iface->info;
parent_name = arg_str(p, "PARENT");
if (parent_name != NULL) {
if (iface_from_name(c, parent_name, &parent) < 0)
return 0;
if (parent.type != BR_IFACE_TYPE_PORT) {
errno = EMEDIUMTYPE;
return 0;
}
vlan->parent_id = parent.id;
set_attrs |= BR_VLAN_SET_PARENT;
}

if (arg_u16(p, "VLAN", &vlan->vlan_id) == 0)
set_attrs |= BR_VLAN_SET_VLAN;

if (br_eth_addr_parse(arg_str(p, "MAC"), &vlan->mac) == 0) {
set_attrs |= BR_VLAN_SET_MAC;
} else if (!update) {
const struct br_iface_info_port *port;
if (parent_name == NULL && iface_from_id(c, vlan->parent_id, &parent) < 0)
return 0;
if (parent.type != BR_IFACE_TYPE_PORT) {
errno = EMEDIUMTYPE;
return 0;
}
port = (const struct br_iface_info_port *)parent.info;
memcpy(&vlan->mac, &port->mac, sizeof(vlan->mac));
set_attrs |= BR_VLAN_SET_MAC;
}

if (set_attrs == 0)
errno = EINVAL;
return set_attrs;
}

static cmd_status_t vlan_add(const struct br_api_client *c, const struct ec_pnode *p) {
const struct br_infra_iface_add_resp *resp;
struct br_infra_iface_add_req req = {
.iface = {.type = BR_IFACE_TYPE_VLAN, .flags = BR_IFACE_F_UP}
};
void *resp_ptr = NULL;

if (parse_vlan_args(c, p, &req.iface, false) == 0)
return CMD_ERROR;

if (br_api_client_send_recv(c, BR_INFRA_IFACE_ADD, sizeof(req), &req, &resp_ptr) < 0)
return CMD_ERROR;

resp = resp_ptr;
printf("Created interface %u\n", resp->iface_id);
free(resp_ptr);
return CMD_SUCCESS;
}

static cmd_status_t vlan_set(const struct br_api_client *c, const struct ec_pnode *p) {
struct br_infra_iface_set_req req = {0};

if ((req.set_attrs = parse_vlan_args(c, p, &req.iface, true)) == 0)
return CMD_ERROR;

if (br_api_client_send_recv(c, BR_INFRA_IFACE_SET, sizeof(req), &req, NULL) < 0)
return CMD_ERROR;

return CMD_SUCCESS;
}

#define VLAN_ATTRS_CMD IFACE_ATTRS_CMD ",(mac MAC)"

#define VLAN_ATTRS_ARGS \
IFACE_ATTRS_ARGS, with_help("Set the ethernet address.", ec_node_re("MAC", ETH_ADDR_RE))

static int ctx_init(struct ec_node *root) {
int ret;

ret = CLI_COMMAND(
CLI_CONTEXT(root, CTX_ADD, CTX_ARG("interface", "Create interfaces.")),
"vlan NAME parent PARENT vlan_id VLAN [" VLAN_ATTRS_CMD "]",
vlan_add,
"Create a new DPDK vlan.",
with_help("Interface name.", ec_node("any", "NAME")),
with_help(
"Parent port interface.",
ec_node_dyn("PARENT", complete_iface_names, INT2PTR(BR_IFACE_TYPE_PORT))
),
with_help("VLAN ID.", ec_node_uint("VLAN", 1, 4095, 10)),
VLAN_ATTRS_ARGS
);
if (ret < 0)
return ret;
ret = CLI_COMMAND(
CLI_CONTEXT(root, CTX_SET, CTX_ARG("interface", "Modify interfaces.")),
"vlan NAME (name NEW_NAME),(parent PARENT),(vlan_id VLAN)," VLAN_ATTRS_CMD,
vlan_set,
"Modify vlan parameters.",
with_help(
"Interface name.",
ec_node_dyn("NAME", complete_iface_names, INT2PTR(BR_IFACE_TYPE_VLAN))
),
with_help("New interface name.", ec_node("any", "NEW_NAME")),
with_help(
"Parent port interface.",
ec_node_dyn("PARENT", complete_iface_names, INT2PTR(BR_IFACE_TYPE_PORT))
),
with_help("VLAN ID.", ec_node_uint("VLAN", 1, 4095, 10)),
VLAN_ATTRS_ARGS
);
if (ret < 0)
return ret;

return 0;
}

static struct br_cli_context ctx = {
.name = "infra vlan",
.init = ctx_init,
};

static void __attribute__((constructor, used)) init(void) {
register_context(&ctx);
register_iface_type(&vlan_type);
}
23 changes: 23 additions & 0 deletions modules/infra/control/br_vlan.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2024 Robin Jarry

#ifndef _BR_INFRA_VLAN_PRIV
#define _BR_INFRA_VLAN_PRIV

#include <br_iface.h>

#include <rte_ether.h>
#include <rte_mempool.h>

#include <stdint.h>
#include <sys/queue.h>

struct iface_info_vlan {
uint16_t parent_id;
uint16_t vlan_id;
struct rte_ether_addr mac;
};

struct iface *vlan_get_iface(uint16_t port_id, uint16_t vlan_id);

#endif
Loading

0 comments on commit 260b670

Please sign in to comment.