aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2015-03-27 16:22:38 +0100
committerJiri Pirko <jiri@resnulli.us>2015-03-27 16:37:20 +0100
commit56e4a2990edebd8b9fe491d3cad5256734d1746f (patch)
treece778134d3d4290c463113b316173c2e257e43fa
parent2b101406db9159b31b962ef0aaafb432b5e16e94 (diff)
downloadlibteam-56e4a2990edebd8b9fe491d3cad5256734d1746f.tar.gz
teamd: lw: arp_ping: fix arp rx handling
arp ping linkwatch uses packet socket bound to ETH_P_ARP. This socket gets skb delivered in after rx_handler is called, unlike ETH_P_ALL. When put in bridge, bridge consumes all incoming skbs, therefore the packet socket never sees any arps. To fix this, bind the socket to ETH_P_ALL to move the probe before rx_handler. Socket filter is updated with checking protocol for arp type to avoid receiving of another packets. Signed-off-by: Jiri Pirko <jiri@resnulli.us>
-rw-r--r--teamd/teamd_lw_arp_ping.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/teamd/teamd_lw_arp_ping.c b/teamd/teamd_lw_arp_ping.c
index 95fbafc..e2ccd56 100644
--- a/teamd/teamd_lw_arp_ping.c
+++ b/teamd/teamd_lw_arp_ping.c
@@ -55,6 +55,8 @@ lw_ap_ppriv_get(struct lw_psr_port_priv *psr_ppriv)
in_struct_offset(struct arphdr, ar_op)
static struct sock_filter arp_rpl_flt[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_AD_OFF + SKF_AD_PROTOCOL),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_P_ARP, 0, 4),
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),
@@ -68,6 +70,8 @@ static const struct sock_fprog arp_rpl_fprog = {
};
static struct sock_filter arp_novlan_rpl_flt[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_AD_OFF + SKF_AD_PROTOCOL),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_P_ARP, 0, 6),
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),
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, OFFSET_ARP_OP_CODE),
@@ -83,6 +87,8 @@ static const struct sock_fprog arp_novlan_rpl_fprog = {
};
static struct sock_filter arp_vlan_rpl_flt[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_AD_OFF + SKF_AD_PROTOCOL),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_P_ARP, 0, 8),
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, 6, 0),
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG),
@@ -95,7 +101,7 @@ static struct sock_filter arp_vlan_rpl_flt[] = {
};
/* this hack replaces vlanid value in filter code */
-#define SET_FILTER_VLANID(fprog, vlanid) (fprog)->filter[3].k = vlanid
+#define SET_FILTER_VLANID(fprog, vlanid) (fprog)->filter[5].k = vlanid
static const struct sock_fprog arp_vlan_rpl_fprog = {
.len = ARRAY_SIZE(arp_vlan_rpl_flt),
@@ -142,7 +148,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, &arp_rpl_fprog);
+ htons(ETH_P_ALL), &fprog, &arp_rpl_fprog);
}
static void lw_ap_sock_close(struct lw_psr_port_priv *psr_ppriv)
@@ -292,6 +298,7 @@ static int lw_ap_send(struct lw_psr_port_priv *psr_ppriv)
0, (struct sockaddr *) &ll_bcast,
sizeof(ll_bcast));
} else {
+ ll_bcast.sll_protocol = htons(ETH_P_ARP);
return teamd_sendto(psr_ppriv->sock, &ap, sizeof(ap),
0, (struct sockaddr *) &ll_bcast,
sizeof(ll_bcast));