Skip to content

Commit

Permalink
netfilter: flowtable: add pppoe support
Browse files Browse the repository at this point in the history
Add the PPPoE protocol and session id to the flow tuple using the encap
fields to uniquely identify flows from the receive path. For the
transmit path, dev_hard_header() on the vlan device push the headers.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Pablo Neira Ayuso authored and David S. Miller committed Mar 24, 2021
1 parent e990cef commit 72efd58
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 7 deletions.
53 changes: 47 additions & 6 deletions net/netfilter/nf_flow_table_ip.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_pppox.h>
#include <linux/ppp_defs.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
Expand Down Expand Up @@ -139,18 +142,26 @@ static bool ip_has_options(unsigned int thoff)
static void nf_flow_tuple_encap(struct sk_buff *skb,
struct flow_offload_tuple *tuple)
{
struct vlan_ethhdr *veth;
struct pppoe_hdr *phdr;
int i = 0;

if (skb_vlan_tag_present(skb)) {
tuple->encap[i].id = skb_vlan_tag_get(skb);
tuple->encap[i].proto = skb->vlan_proto;
i++;
}
if (skb->protocol == htons(ETH_P_8021Q)) {
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);

switch (skb->protocol) {
case htons(ETH_P_8021Q):
veth = (struct vlan_ethhdr *)skb_mac_header(skb);
tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
tuple->encap[i].proto = skb->protocol;
break;
case htons(ETH_P_PPP_SES):
phdr = (struct pppoe_hdr *)skb_mac_header(skb);
tuple->encap[i].id = ntohs(phdr->sid);
tuple->encap[i].proto = skb->protocol;
break;
}
}

Expand Down Expand Up @@ -228,17 +239,41 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
return NF_STOLEN;
}

static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
{
__be16 proto;

proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
sizeof(struct pppoe_hdr)));
switch (proto) {
case htons(PPP_IP):
return htons(ETH_P_IP);
case htons(PPP_IPV6):
return htons(ETH_P_IPV6);
}

return 0;
}

static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,
u32 *offset)
{
if (skb->protocol == htons(ETH_P_8021Q)) {
struct vlan_ethhdr *veth;
struct vlan_ethhdr *veth;

switch (skb->protocol) {
case htons(ETH_P_8021Q):
veth = (struct vlan_ethhdr *)skb_mac_header(skb);
if (veth->h_vlan_encapsulated_proto == proto) {
*offset += VLAN_HLEN;
return true;
}
break;
case htons(ETH_P_PPP_SES):
if (nf_flow_pppoe_proto(skb) == proto) {
*offset += PPPOE_SES_HLEN;
return true;
}
break;
}

return false;
Expand All @@ -255,12 +290,18 @@ static void nf_flow_encap_pop(struct sk_buff *skb,
__vlan_hwaccel_clear_tag(skb);
continue;
}
if (skb->protocol == htons(ETH_P_8021Q)) {
switch (skb->protocol) {
case htons(ETH_P_8021Q):
vlan_hdr = (struct vlan_hdr *)skb->data;
__skb_pull(skb, VLAN_HLEN);
vlan_set_encap_proto(skb, vlan_hdr);
skb_reset_network_header(skb);
break;
case htons(ETH_P_PPP_SES):
skb->protocol = nf_flow_pppoe_proto(skb);
skb_pull(skb, PPPOE_SES_HLEN);
skb_reset_network_header(skb);
break;
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion net/netfilter/nft_flow_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,15 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
switch (path->type) {
case DEV_PATH_ETHERNET:
case DEV_PATH_VLAN:
case DEV_PATH_PPPOE:
info->indev = path->dev;
if (is_zero_ether_addr(info->h_source))
memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);

if (path->type == DEV_PATH_ETHERNET)
break;

/* DEV_PATH_VLAN */
/* DEV_PATH_VLAN and DEV_PATH_PPPOE */
if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
info->indev = NULL;
break;
Expand All @@ -106,6 +107,8 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->encap[info->num_encaps].id = path->encap.id;
info->encap[info->num_encaps].proto = path->encap.proto;
info->num_encaps++;
if (path->type == DEV_PATH_PPPOE)
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))
Expand Down

0 comments on commit 72efd58

Please sign in to comment.