Skip to content

Commit

Permalink
pppoe: Add support to 'ignore-ingress-ppp-brd' feature for pppoe-bundle
Browse files Browse the repository at this point in the history
This feature ensure that when interface are part of the same pppoe-bundle
then PPP frame broadcast are ignored. In some networking design, having
multiple interface into the same L2 segment can lead to L2 broadcast
during MAC learning process at switch side. PPP is specialy sensitive
to broadcast since it can force unappropriate state transition.

This feature configured for a pppoe-bundle ensure that ingress PPP frame
on diffrent ifindex as the one used during session init are silently
ignored.

This feature is an opt-in setting, since on some others networking
design ones could want to setup asymetric L2 path for ingress and
egress.

This feature is made available via VTY 'ignore-ingress-ppp-brd' in
pppoe-bundle configuration.
  • Loading branch information
acassen committed Sep 1, 2024
1 parent 5694d33 commit 57abced
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 7 deletions.
8 changes: 4 additions & 4 deletions src/gtp_pppoe.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ gtp_pppoe_ingress(pkt_t *pkt, void *arg)
}

static int
gtp_pppoe_socket_init(gtp_pppoe_t *pppoe, uint16_t proto)
gtp_pppoe_socket_init(gtp_pppoe_t *pppoe, uint16_t proto, int id)
{
struct sockaddr_ll sll;
int fd, ret;
Expand All @@ -306,15 +306,15 @@ gtp_pppoe_socket_init(gtp_pppoe_t *pppoe, uint16_t proto)
fd = if_setsockopt_promisc(fd, sll.sll_ifindex, true);
if (fd < 0) {
log_message(LOG_INFO, "%s(): #%d : Error creating pppoe channel on interface %s (%m)"
, __FUNCTION__
, __FUNCTION__, id
, pppoe->ifname);
return -1;
}

ret = bind(fd, (struct sockaddr *) &sll, sizeof(sll));
if (ret < 0) {
log_message(LOG_INFO, "%s(): #%d : Error binding pppoe channel on interface %s (%m)"
, __FUNCTION__
, __FUNCTION__, id
, pppoe->ifname);
close(fd);
return -1;
Expand All @@ -341,7 +341,7 @@ gtp_pppoe_worker_task(void *arg)
prctl(PR_SET_NAME, pname, 0, 0, 0, 0);

/* Socket init */
w->fd = gtp_pppoe_socket_init(pppoe, w->proto);
w->fd = gtp_pppoe_socket_init(pppoe, w->proto, w->id);
if (w->fd < 0)
return NULL;

Expand Down
19 changes: 19 additions & 0 deletions src/gtp_pppoe_proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,15 @@ pppoe_dispatch_disc_pkt(gtp_pppoe_t *pppoe, pkt_t *pkt)
off += len;
}
breakbreak:
/* Using PPPoE bundle, PPP frames could be broadcasted to every interfaces
* part of the bundle. if "ignore-ingress-ppp-brd" feature is used then
* only take care of pkt on the same interface as the one used during
* session init */
if (s && s->pppoe->bundle &&
__test_bit(PPPOE_FL_IGNORE_INGRESS_PPP_BRD_BIT, &s->pppoe->bundle->flags) &&
(s->pppoe->ifindex != pppoe->ifindex))
return;

switch (code) {
case PPPOE_CODE_PADI:
case PPPOE_CODE_PADR:
Expand Down Expand Up @@ -704,5 +713,15 @@ pppoe_dispatch_session_pkt(gtp_pppoe_t *pppoe, pkt_t *pkt)
}

pkt_buffer_put_data(pkt->pbuff, off);

/* Using PPPoE bundle, PPP frames could be broadcasted to every interfaces
* part of the bundle. if "ignore-ingress-ppp-brd" feature is used then
* only take care of pkt on the same interface as the one used during
* session init */
if (sp->pppoe->bundle &&
__test_bit(PPPOE_FL_IGNORE_INGRESS_PPP_BRD_BIT, &sp->pppoe->bundle->flags) &&
(sp->pppoe->ifindex != pppoe->ifindex))
return;

sppp_input(sp->s_ppp, pkt);
}
39 changes: 36 additions & 3 deletions src/gtp_pppoe_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,37 @@ DEFUN(pppoe_bundle_instance,
return CMD_SUCCESS;
}

DEFUN(pppoe_bundle_ignore_ingress_ppp_brd,
pppoe_bundle_ignore_ingress_ppp_brd_cmd,
"ignore-ingress-ppp-brd",
"Ignore Ingress PPP broadcast messages\n")
{
gtp_pppoe_bundle_t *bundle = vty->index;
gtp_pppoe_t *pppoe;

pppoe = gtp_pppoe_bundle_instance_prepare(vty, bundle, argc, argv);
if (!pppoe)
return CMD_WARNING;

__set_bit(PPPOE_FL_IGNORE_INGRESS_PPP_BRD_BIT, &bundle->flags);
return CMD_SUCCESS;
}

DEFUN(no_pppoe_bundle_ignore_ingress_ppp_brd,
no_pppoe_bundle_ignore_ingress_ppp_brd_cmd,
"no ignore-ingress-ppp-brd",
"Allow Ingress PPP broadcast messages\n")
{
gtp_pppoe_bundle_t *bundle = vty->index;
gtp_pppoe_t *pppoe;

pppoe = gtp_pppoe_bundle_instance_prepare(vty, bundle, argc, argv);
if (!pppoe)
return CMD_WARNING;

__clear_bit(PPPOE_FL_IGNORE_INGRESS_PPP_BRD_BIT, &bundle->flags);
return CMD_SUCCESS;
}

/*
* Show commands
Expand Down Expand Up @@ -732,11 +763,11 @@ gtp_config_pppoe_bundle_write(vty_t *vty)

list_for_each_entry(bundle, l, next) {
vty_out(vty, "pppoe-bundle %s%s", bundle->name, VTY_NEWLINE);
if (__test_bit(PPPOE_FL_IGNORE_INGRESS_PPP_BRD_BIT, &bundle->flags))
vty_out(vty, " ignore-ingress-ppp-brd%s", VTY_NEWLINE);
for (i = 0; i < PPPOE_BUNDLE_MAXSIZE && bundle->pppoe[i]; i++) {
pppoe = bundle->pppoe[i];
vty_out(vty, " instance %s%s"
, pppoe->name
, VTY_NEWLINE);
vty_out(vty, " instance %s%s", pppoe->name, VTY_NEWLINE);
}
vty_out(vty, "!%s", VTY_NEWLINE);
}
Expand Down Expand Up @@ -782,6 +813,8 @@ gtp_pppoe_vty_init(void)
install_element(CONFIG_NODE, &no_pppoe_bundle_cmd);

install_element(PPPOE_BUNDLE_NODE, &pppoe_bundle_instance_cmd);
install_element(PPPOE_BUNDLE_NODE, &pppoe_bundle_ignore_ingress_ppp_brd_cmd);
install_element(PPPOE_BUNDLE_NODE, &no_pppoe_bundle_ignore_ingress_ppp_brd_cmd);

/* Install show commands. */
install_element(VIEW_NODE, &show_pppoe_cmd);
Expand Down
4 changes: 4 additions & 0 deletions src/include/gtp_pppoe.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ enum pppoe_flags {
PPPOE_FL_LCP_MAX_TERMINATE_BIT,
PPPOE_FL_LCP_MAX_CONFIGURE_BIT,
PPPOE_FL_LCP_MAX_FAILURE_BIT,
PPPOE_FL_IGNORE_INGRESS_PPP_BRD_BIT,
};

struct rps_opts {
Expand Down Expand Up @@ -164,7 +165,10 @@ typedef struct _gtp_pppoe_bundle {

struct _gtp_pppoe **pppoe;
int instance_idx;

list_head_t next;

unsigned long flags;
} gtp_pppoe_bundle_t;

typedef struct _gtp_pppoe {
Expand Down

0 comments on commit 57abced

Please sign in to comment.