Skip to content

Commit

Permalink
teamd: fallback to alternative BPF filter in case access of vlan_tci …
Browse files Browse the repository at this point in the history
…is not supported

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
  • Loading branch information
jpirko committed Jan 23, 2013
1 parent 0217096 commit 43faa9b
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
3 changes: 2 additions & 1 deletion teamd/teamd.h
Expand Up @@ -312,7 +312,8 @@ int teamd_hash_func_set(struct teamd_context *ctx);

int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
const unsigned short family,
const struct sock_fprog *fprog);
const struct sock_fprog *fprog,
const struct sock_fprog *alt_fprog);
int teamd_getsockname_hwaddr(int sock, struct sockaddr_ll *addr,
size_t expected_len);
int teamd_sendto(int sockfd, const void *buf, size_t len, int flags,
Expand Down
67 changes: 58 additions & 9 deletions teamd/teamd_common.c
Expand Up @@ -26,12 +26,65 @@
#include <sys/stat.h>
#include <linux/if_packet.h>
#include <linux/filter.h>
#include <private/misc.h>

#include "teamd.h"

static struct sock_filter bad_flt[] = {
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, -1),
BPF_STMT(BPF_RET + BPF_K, 0),
};

static const struct sock_fprog bad_fprog = {
.len = ARRAY_SIZE(bad_flt),
.filter = bad_flt,
};

static int attach_filter(int sock, const struct sock_fprog *pref_fprog,
const struct sock_fprog *alt_fprog)
{
int ret;
const struct sock_fprog *fprog;

if (!pref_fprog)
return 0;

/* Now we are in tough situation. Older kernels (<3.8) does not
* support SKF_AD_VLAN_TAG_PRESENT and SKF_AD_VLAN_TAG. But the kernel
* check if these are supported was added after that:
* aa1113d9f85da59dcbdd32aeb5d71da566e46def
* But it was added close enough. So try to attach obviously bad
* filter and assume that is it does not fail, kernel does not support
* accessing skb->vlan_tci getting and use alternative filter instead.
*/

ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
&bad_fprog, sizeof(bad_fprog));
if (ret == -1) {
if (errno != EINVAL)
return -errno;
fprog = pref_fprog;
}
else if (alt_fprog) {
teamd_log_warn("Kernel does not support accessing skb->vlan_tci from BPF,\n"
"falling back to alternative filter. Expect vlan-tagged ARPs\n"
"to be accounted on non-tagged link monitor and vice versa.");
fprog = alt_fprog;
} else {
return 0;
}

ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
fprog, sizeof(*fprog));
if (ret == -1)
return -errno;
return 0;
}

int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
const unsigned short family,
const struct sock_fprog *fprog)
const struct sock_fprog *fprog,
const struct sock_fprog *alt_fprog)
{
struct sockaddr_ll ll_my;
int sock;
Expand All @@ -44,14 +97,10 @@ int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
return -errno;
}

if (fprog) {
ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
fprog, sizeof(*fprog));
if (ret == -1) {
teamd_log_err("Failed to attach filter.");
err = -errno;
goto close_sock;
}
err = attach_filter(sock, fprog, alt_fprog);
if (err) {
teamd_log_err("Failed to attach filter.");
goto close_sock;
}

memset(&ll_my, 0, sizeof(ll_my));
Expand Down
17 changes: 15 additions & 2 deletions teamd/teamd_link_watch.c
Expand Up @@ -546,6 +546,19 @@ lw_ap_ppriv_get(struct lw_psr_port_priv *psr_ppriv)
#define OFFSET_ARP_OP_CODE \
in_struct_offset(struct arphdr, ar_op)

static struct sock_filter arp_rpl_flt[] = {
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, OFFSET_ARP_OP_CODE),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 0, 1),
BPF_STMT(BPF_RET + BPF_K, (u_int) -1),
BPF_STMT(BPF_RET + BPF_K, 0),
};

static const struct sock_fprog arp_rpl_fprog = {
.len = ARRAY_SIZE(arp_rpl_flt),
.filter = arp_rpl_flt,
};

static struct sock_filter arp_novlan_rpl_flt[] = {
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 4),
Expand Down Expand Up @@ -598,7 +611,7 @@ static int lw_ap_sock_open(struct lw_psr_port_priv *psr_ppriv)
}
return teamd_packet_sock_open(&psr_ppriv->sock,
psr_ppriv->common.tdport->ifindex,
htons(ETH_P_ARP), &fprog);
htons(ETH_P_ARP), &fprog, &arp_rpl_fprog);
}

static void lw_ap_sock_close(struct lw_psr_port_priv *psr_ppriv)
Expand Down Expand Up @@ -926,7 +939,7 @@ static int lw_nsnap_sock_open(struct lw_psr_port_priv *psr_ppriv)
*/
err = teamd_packet_sock_open(&psr_ppriv->sock,
psr_ppriv->common.tdport->ifindex,
htons(ETH_P_IPV6), &na_fprog);
htons(ETH_P_IPV6), &na_fprog, NULL);
if (err)
return err;
err = icmp6_sock_open(&nsnap_ppriv->tx_sock);
Expand Down
2 changes: 1 addition & 1 deletion teamd/teamd_runner_lacp.c
Expand Up @@ -884,7 +884,7 @@ static int lacp_port_added(struct teamd_context *ctx,

err = teamd_packet_sock_open(&lacp_port->sock,
tdport->ifindex,
htons(ETH_P_SLOW), NULL);
htons(ETH_P_SLOW), NULL, NULL);
if (err)
return err;

Expand Down

0 comments on commit 43faa9b

Please sign in to comment.