Skip to content

Commit

Permalink
pppoe: Initial support to PPPoE Bundle
Browse files Browse the repository at this point in the history
This feature is available via VTY command "pppoe-bundle" and define a
bundle of pppoe instance. All pppoe instance of a bundle will
share the same sessions tracking.

This feature is usefull for transparent takeover.
  • Loading branch information
acassen committed Apr 4, 2024
1 parent c29f7cf commit 0e23729
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 10 deletions.
1 change: 1 addition & 0 deletions lib/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ typedef enum _node_type {
PDN_NODE, /* PDN daemon commands. */
IP_VRF_NODE, /* IP VRF commands. */
PPPOE_NODE, /* PPPoE commands. */
PPPOE_BUNDLE_NODE, /* PPPoE Bundle commands. */
APN_NODE, /* APN commands. */
GTP_SWITCH_NODE, /* GTP Switch commands. */
GTP_ROUTER_NODE, /* GTP Router commands. */
Expand Down
8 changes: 5 additions & 3 deletions src/gtp_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ int
gtp_bpf_opts_load(gtp_bpf_opts_t *opts, vty_t *vty, int argc, const char **argv,
int (*bpf_load) (gtp_bpf_opts_t *))
{
int ret, ifindex;
int err, ifindex;

if (argc < 2) {
vty_out(vty, "%% missing arguments%s", VTY_NEWLINE);
Expand All @@ -209,8 +209,8 @@ gtp_bpf_opts_load(gtp_bpf_opts_t *opts, vty_t *vty, int argc, const char **argv,
opts->ifindex = ifindex;
opts->vty = vty;

ret = (*bpf_load) (opts);
if (ret < 0) {
err = (*bpf_load) (opts);
if (err) {
vty_out(vty, "%% Error loading eBPF program:%s on ifindex:%d%s"
, opts->filename
, opts->ifindex
Expand Down Expand Up @@ -275,6 +275,7 @@ alloc_daemon_data(void)
INIT_LIST_HEAD(&new->mirror_rules);
INIT_LIST_HEAD(&new->ip_vrf);
INIT_LIST_HEAD(&new->pppoe);
INIT_LIST_HEAD(&new->pppoe_bundle);
INIT_LIST_HEAD(&new->gtp_apn);
INIT_LIST_HEAD(&new->gtp_switch_ctx);
INIT_LIST_HEAD(&new->gtp_router_ctx);
Expand All @@ -294,6 +295,7 @@ free_daemon_data(void)
gtp_switch_server_destroy();
gtp_router_server_destroy();
gtp_request_destroy();
gtp_pppoe_bundle_destroy();
gtp_pppoe_destroy();
gtp_sessions_destroy();
gtp_conn_destroy();
Expand Down
94 changes: 92 additions & 2 deletions src/gtp_pppoe.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ gtp_pppoe_get_by_name(const char *name)
return NULL;
}

gtp_pppoe_bundle_t *
gtp_pppoe_bundle_get_by_name(const char *name)
{
gtp_pppoe_bundle_t *bundle;

pthread_mutex_lock(&gtp_pppoe_mutex);
list_for_each_entry(bundle, &daemon_data->pppoe_bundle, next) {
if (!strncmp(bundle->name, name, GTP_NAME_MAX_LEN)) {
pthread_mutex_unlock(&gtp_pppoe_mutex);
return bundle;
}
}
pthread_mutex_unlock(&gtp_pppoe_mutex);
return NULL;
}

static gtp_pppoe_t *
gtp_pppoe_get_by_ifindex(const unsigned int ifindex)
{
Expand Down Expand Up @@ -96,6 +112,16 @@ gtp_pppoe_add(gtp_pppoe_t *pppoe)
return 0;
}

static int
gtp_pppoe_bundle_add(gtp_pppoe_bundle_t *bundle)
{
pthread_mutex_lock(&gtp_pppoe_mutex);
list_add_tail(&bundle->next, &daemon_data->pppoe_bundle);
pthread_mutex_unlock(&gtp_pppoe_mutex);
return 0;
}


/*
* Receive Packet Steering eBPF related
*/
Expand Down Expand Up @@ -463,9 +489,12 @@ gtp_pppoe_init(const char *name)
}

PMALLOC(pppoe);
if (!pppoe)
if (!pppoe) {
errno = ENOMEM;
return NULL;
}
strlcpy(pppoe->name, name, GTP_NAME_MAX_LEN);
INIT_LIST_HEAD(&pppoe->next);
pppoe->seed = time(NULL);
srand(pppoe->seed);
pkt_queue_init(&pppoe->pkt_q);
Expand Down Expand Up @@ -515,4 +544,65 @@ gtp_pppoe_destroy(void)
pthread_mutex_unlock(&gtp_pppoe_mutex);

return 0;
}
}


/*
* PPPoE Bundle init
*/
gtp_pppoe_bundle_t *
gtp_pppoe_bundle_init(const char *name)
{
gtp_pppoe_bundle_t *bundle = NULL;

bundle = gtp_pppoe_bundle_get_by_name(name);
if (bundle) {
errno = EEXIST;
return NULL;
}

PMALLOC(bundle);
if (!bundle) {
errno = ENOMEM;
return NULL;
}
strlcpy(bundle->name, name, GTP_NAME_MAX_LEN);
INIT_LIST_HEAD(&bundle->next);
gtp_htab_init(&bundle->session_tab, CONN_HASHTAB_SIZE);
gtp_htab_init(&bundle->unique_tab, CONN_HASHTAB_SIZE);
bundle->pppoe = MALLOC(sizeof(gtp_pppoe_t) * PPPOE_BUNDLE_MAXSIZE);

gtp_pppoe_bundle_add(bundle);

return bundle;
}

int
__gtp_pppoe_bundle_release(gtp_pppoe_bundle_t *bundle)
{
list_head_del(&bundle->next);
FREE(bundle->pppoe);
return 0;
}

int
gtp_pppoe_bundle_release(gtp_pppoe_bundle_t *bundle)
{
pthread_mutex_lock(&gtp_pppoe_mutex);
__gtp_pppoe_bundle_release(bundle);
pthread_mutex_unlock(&gtp_pppoe_mutex);
return 0;
}

int
gtp_pppoe_bundle_destroy(void)
{
gtp_pppoe_bundle_t *bundle, *_bundle;

pthread_mutex_lock(&gtp_pppoe_mutex);
list_for_each_entry_safe(bundle, _bundle, &daemon_data->pppoe_bundle, next)
__gtp_pppoe_bundle_release(bundle);
pthread_mutex_unlock(&gtp_pppoe_mutex);

return 0;
}
132 changes: 127 additions & 5 deletions src/gtp_pppoe_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,24 @@ extern data_t *daemon_data;
extern thread_master_t *master;


static int gtp_config_write(vty_t *vty);
static int gtp_config_pppoe_write(vty_t *vty);
static int gtp_config_pppoe_bundle_write(vty_t *vty);
cmd_node_t pppoe_node = {
.node = PPPOE_NODE,
.parent_node = CONFIG_NODE,
.prompt ="%s(pppoe)# ",
.config_write = gtp_config_write,
.config_write = gtp_config_pppoe_write,
};

cmd_node_t pppoe_bundle_node = {
.node = PPPOE_BUNDLE_NODE,
.parent_node = CONFIG_NODE,
.prompt ="%s(pppoe-bundle)# ",
.config_write = gtp_config_pppoe_bundle_write,
};

/*
* Command
* PPPoE Commands
*/
DEFUN(pppoe,
pppoe_cmd,
Expand Down Expand Up @@ -423,6 +431,96 @@ DEFUN(pppoe_lcp_max_failure,
return CMD_SUCCESS;
}

/*
* PPPoE Bundle Commands
*/
DEFUN(pppoe_bundle,
pppoe_bundle_cmd,
"pppoe-bundle STRING",
"Configure PPPoE Bundle\n"
"PPPoE Bundle Name")
{
gtp_pppoe_bundle_t *new;

if (argc < 1) {
vty_out(vty, "%% missing arguments%s", VTY_NEWLINE);
return CMD_WARNING;
}

new = gtp_pppoe_bundle_init(argv[0]);
if (!new) {
if (errno == EEXIST)
vty_out(vty, "%% PPPoE bundle %s already exist !!!%s"
, argv[0], VTY_NEWLINE);
else
vty_out(vty, "%% PPPoE Error allocating bundle %s !!!%s"
, argv[0], VTY_NEWLINE);
return CMD_WARNING;
}


vty->node = PPPOE_BUNDLE_NODE;
vty->index = new;
return CMD_SUCCESS;
}

DEFUN(no_pppoe_bundle,
no_pppoe_bundle_cmd,
"no pppoe-bundle STRING",
"Destroy PPPoe Bundle\n"
"PPPoE Bundle Name")
{
gtp_pppoe_bundle_t *bundle;

if (argc < 1) {
vty_out(vty, "%% missing arguments%s", VTY_NEWLINE);
return CMD_WARNING;
}

/* Already existing ? */
bundle = gtp_pppoe_bundle_get_by_name(argv[0]);
if (!bundle) {
vty_out(vty, "%% unknown PPPoE bundle %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}

gtp_pppoe_bundle_release(bundle);
return CMD_SUCCESS;
}

DEFUN(pppoe_bundle_instance,
pppoe_bundle_instance_cmd,
"instance STRING",
"PPPoE Instance\n"
"Name\n")
{
gtp_pppoe_bundle_t *bundle = vty->index;
gtp_pppoe_t *pppoe;

if (argc < 1) {
vty_out(vty, "%% missing arguments%s", VTY_NEWLINE);
return CMD_WARNING;
}

pppoe = gtp_pppoe_get_by_name(argv[0]);
if (!pppoe) {
vty_out(vty, "%% Unknown PPPoe Instance %s%s"
, argv[0]
, VTY_NEWLINE);
return CMD_WARNING;
}

if (bundle->instance_idx >= PPPOE_BUNDLE_MAXSIZE) {
vty_out(vty, "%% PPPoe Bundle no more Instance available%s"
, VTY_NEWLINE);
return CMD_WARNING;
}

bundle->pppoe[bundle->instance_idx++] = pppoe;
return CMD_SUCCESS;
}


/*
* Show commands
*/
Expand Down Expand Up @@ -493,9 +591,9 @@ DEFUN(show_pppoe,

/* Configuration writer */
static int
gtp_config_write(vty_t *vty)
gtp_config_pppoe_write(vty_t *vty)
{
list_head_t *l = &daemon_data->pppoe;
list_head_t *l = &daemon_data->pppoe;
gtp_pppoe_t *pppoe;

list_for_each_entry(pppoe, l, next) {
Expand Down Expand Up @@ -561,6 +659,23 @@ gtp_config_write(vty_t *vty)
return CMD_SUCCESS;
}

static int
gtp_config_pppoe_bundle_write(vty_t *vty)
{
list_head_t *l = &daemon_data->pppoe_bundle;
gtp_pppoe_bundle_t *bundle;
int i;

list_for_each_entry(bundle, l, next) {
vty_out(vty, "pppoe-bundle %s%s", bundle->name, VTY_NEWLINE);
for (i = 0; i < PPPOE_BUNDLE_MAXSIZE && bundle->pppoe[i]; i++)
vty_out(vty, " instance %s%s", bundle->pppoe[i]->name, VTY_NEWLINE);
vty_out(vty, "!%s", VTY_NEWLINE);
}

return CMD_SUCCESS;
}


/*
* VTY init
Expand Down Expand Up @@ -592,6 +707,13 @@ gtp_pppoe_vty_init(void)
install_element(PPPOE_NODE, &pppoe_lcp_max_configure_cmd);
install_element(PPPOE_NODE, &pppoe_lcp_max_failure_cmd);

/* Install PPPoE Bundle commands. */
install_node(&pppoe_bundle_node);
install_element(CONFIG_NODE, &pppoe_bundle_cmd);
install_element(CONFIG_NODE, &no_pppoe_bundle_cmd);

install_element(PPPOE_BUNDLE_NODE, &pppoe_bundle_instance_cmd);

/* Install show commands. */
install_element(VIEW_NODE, &show_pppoe_cmd);
install_element(ENABLE_NODE, &show_pppoe_cmd);
Expand Down
1 change: 1 addition & 0 deletions src/include/gtp_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ typedef struct _data {

list_head_t mirror_rules;
list_head_t pppoe;
list_head_t pppoe_bundle;
list_head_t ip_vrf;
list_head_t gtp_apn;
list_head_t gtp_switch_ctx;
Expand Down
Loading

0 comments on commit 0e23729

Please sign in to comment.