summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorManohar Krishnappa Chidambaraswamy <manohar.krishnappa.chidambaraswamy@ericsson.com>2018-04-05 12:20:27 +0000
committerBen Pfaff <blp@ovn.org>2018-04-10 16:19:14 -0700
commitba07cf222a0cd05939941eb49bbabb42c1f1bcbb (patch)
treef50042dbad1caad297830656fb934fed242d9d99 /lib
parent484f7dbdaa2bbeb71781354df29c18fdb12a3925 (diff)
downloadopenvswitch-ba07cf222a0cd05939941eb49bbabb42c1f1bcbb.tar.gz
Handle gratuitous ARP requests and replies in tnl_arp_snoop()
Problem: ======== In user-space tunneling implementation, tnl_arp_snoop() snoops only ARP *reply* packets to resolve tunnel nexthop IP addresses to MAC addresses. Normally the ARP requests are periodically sent by the local host IP stack, so that the ARP cache in OVS is refreshed and entries do not time out. However, if the remote tunnel nexthop is a VRRP IP, and the gateway periodically sends gratuitous ARP *requests* to announce itself, tnl_arp_snoop() treats them as INVALID. Consequently, the ARP cache in OVS expires after 10 minutes, which results in dropping of the next packet(s) until a new ARP request is responded to. Fix: ==== Enhance the tunnel neighbor resolution logic in OVS to not only snoop on ARP replies but also on gratuitous ARP requests. Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com> From: Manohar K C <manohar.krishnappa.chidambaraswamy@ericsson.com> CC: Jan Scheurich <jan.scheurich@ericsson.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/flow.h16
-rw-r--r--lib/tnl-neigh-cache.c6
2 files changed, 20 insertions, 2 deletions
diff --git a/lib/flow.h b/lib/flow.h
index 5e41567b2..af829319e 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -1118,6 +1118,22 @@ static inline bool is_nd(const struct flow *flow,
return false;
}
+static inline bool is_arp(const struct flow *flow)
+{
+ return (flow->dl_type == htons(ETH_TYPE_ARP));
+}
+
+static inline bool is_garp(const struct flow *flow,
+ struct flow_wildcards *wc)
+{
+ if (is_arp(flow)) {
+ return (FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_src) ==
+ FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_dst));
+ }
+
+ return false;
+}
+
static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc)
{
if (get_dl_type(flow) == htons(ETH_TYPE_IP)) {
diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
index 5ddd53976..b28f9f1bb 100644
--- a/lib/tnl-neigh-cache.c
+++ b/lib/tnl-neigh-cache.c
@@ -151,8 +151,10 @@ static int
tnl_arp_snoop(const struct flow *flow, struct flow_wildcards *wc,
const char name[IFNAMSIZ])
{
- if (flow->dl_type != htons(ETH_TYPE_ARP)
- || FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_proto) != ARP_OP_REPLY
+ /* Snoop normal ARP replies and gratuitous ARP requests/replies only */
+ if (!is_arp(flow)
+ || (!is_garp(flow, wc) &&
+ FLOW_WC_GET_AND_MASK_WC(flow, wc, nw_proto) != ARP_OP_REPLY)
|| eth_addr_is_zero(FLOW_WC_GET_AND_MASK_WC(flow, wc, arp_sha))) {
return EINVAL;
}