This patchset increases the DAT DHT timeout to reduce the amount of broadcasted ARP Replies.
To increase the timeout only for DAT DHT entries added via DHT-PUT but not for any other entry in the DAT cache the DAT cache and DAT DHT concepts are split into two separate hash tables (PATCH 2/3).
PATCH 3/3 then increases the timeout for DAT DHT entries from 5 to 30 minutes.
The motivation for this patchset is based on the observations made here: https://www.open-mesh.org/projects/batman-adv/wiki/DAT_DHCP_Snooping
In tests this year at Freifunk Lübeck with ~180 mesh nodes and Gluon this reduced the ARP broadcast overhead, measured over 7 days, as follows:
- Total: 6677.66 bits/s -> 677.26 bits/s => -89.86% 11.92 pkts/s -> 1.21 pkts/s => -89.85%
- from gateways: 5618.02 bits/s -> 212.28 => -96.22% 10.03 pkts/s -> 0.38 pkts/s => -96.21%
Also see graphics and a few more test details here: - https://www.open-mesh.org/projects/batman-adv/wiki/DAT_DHCP_Snooping#Result-...
These patches (v5) have been applied in this mesh network without issues for 3 months now.
Regards, Linus
---
Changelog v7: - adding PATCH 1/3 to add the batadv_netlink_get_softif() wrapper to reduce the amount of duplicate code, both in the current code base but also for the next PATCH 2/3
Changelog v6: - removed renaming+deprecation of BATADV_P_DAT_CACHE_REPLY in PATCH 1/2 - small commit message rewording in PATCH 1/2
Changelog v5: - rebased to current main branch -> removed now obsolete debugfs code
Changelog v4: - rebased to: acfc9a214d01695 ("batman-adv: genetlink: make policy common to family")
Changelog v3:
formerly: "batman-adv: Increase purge timeout on DAT DHT candidates" https://patchwork.open-mesh.org/patch/17728/ - fixed the potential jiffies overflow and jiffies initialization issues by replacing the last_dht_update timeout variable with a split of DAT cache and DAT DHT into two separate hash tables -> instead of maintaining two timeouts in one DAT entry two DAT entries are created and maintained in their respective DAT cache and DAT DHT hash tables
Changelog v2:
formerly: "batman-adv: Increase DHCP snooped DAT entry purge timeout in DHT" (https://patchwork.open-mesh.org/patch/17364/) - removed the extended timeouts flag in the DHT-PUT messages introduced in v1 again - removed DHCP dependency
Reduce duplicate code by using netlink helpers which return the soft/hard interface directly. Instead of returning an interface index which we are typically not interested in.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- net/batman-adv/bridge_loop_avoidance.c | 30 +---- net/batman-adv/distributed-arp-table.c | 15 +-- net/batman-adv/gateway_client.c | 15 +-- net/batman-adv/multicast.c | 14 +-- net/batman-adv/netlink.c | 146 +++++++++++++++++-------- net/batman-adv/netlink.h | 5 +- net/batman-adv/originator.c | 80 ++++---------- net/batman-adv/translation-table.c | 28 +---- 8 files changed, 150 insertions(+), 183 deletions(-)
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 449faf5a5487..bdedcbde9e0e 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -2233,25 +2233,16 @@ int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb) { struct batadv_hard_iface *primary_if = NULL; int portid = NETLINK_CB(cb->skb).portid; - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_hashtable *hash; struct batadv_priv *bat_priv; int bucket = cb->args[0]; int idx = cb->args[1]; - int ifindex; int ret = 0;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface); hash = bat_priv->bla.claim_hash; @@ -2403,25 +2394,16 @@ int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb) { struct batadv_hard_iface *primary_if = NULL; int portid = NETLINK_CB(cb->skb).portid; - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_hashtable *hash; struct batadv_priv *bat_priv; int bucket = cb->args[0]; int idx = cb->args[1]; - int ifindex; int ret = 0;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface); hash = bat_priv->bla.backbone_hash; diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 801eff8a40e5..3a257fe07433 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -937,25 +937,16 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) { struct batadv_hard_iface *primary_if = NULL; int portid = NETLINK_CB(cb->skb).portid; - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_hashtable *hash; struct batadv_priv *bat_priv; int bucket = cb->args[0]; int idx = cb->args[1]; - int ifindex; int ret = 0;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface); hash = bat_priv->dat.hash; diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 0ddd8b4b3f4c..8fa82742295d 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -502,22 +502,13 @@ void batadv_gw_node_free(struct batadv_priv *bat_priv) int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb) { struct batadv_hard_iface *primary_if = NULL; - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_priv *bat_priv; - int ifindex; int ret;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 38fab5e46ae2..1fc4f244d58a 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -2112,21 +2112,13 @@ batadv_mcast_netlink_get_primary(struct netlink_callback *cb, struct batadv_hard_iface **primary_if) { struct batadv_hard_iface *hard_iface = NULL; - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_priv *bat_priv; - int ifindex; int ret = 0;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 3f0003fc502c..ce8e02d082d0 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -158,8 +158,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { * * Return: interface index, or 0. */ -int -batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) +static int batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype) { struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype);
@@ -881,14 +880,14 @@ static int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv, }
/** - * batadv_netlink_get_hardif() - Get hardif attributes + * batadv_netlink_cmd_get_hardif() - Get hardif attributes * @skb: Netlink message with request data * @info: receiver information * * Return: 0 on success or negative error number in case of failure */ -static int batadv_netlink_get_hardif(struct sk_buff *skb, - struct genl_info *info) +static int batadv_netlink_cmd_get_hardif(struct sk_buff *skb, + struct genl_info *info) { struct batadv_hard_iface *hard_iface = info->user_ptr[1]; struct batadv_priv *bat_priv = info->user_ptr[0]; @@ -964,28 +963,16 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, static int batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb) { - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_hard_iface *hard_iface; struct batadv_priv *bat_priv; - int ifindex; int portid = NETLINK_CB(cb->skb).portid; int skip = cb->args[0]; int i = 0;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface) - return -ENODEV; - - if (!batadv_softif_is_valid(soft_iface)) { - dev_put(soft_iface); - return -ENODEV; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
@@ -1150,23 +1137,17 @@ static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) }
/** - * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes + * batadv_netlink_get_softif_from_info() - Retrieve soft interface from ifindex * @net: the applicable net namespace - * @info: receiver information + * @ifindex: index of the soft interface * * Return: Pointer to soft interface (with increased refcnt) on success, error * pointer on error */ static struct net_device * -batadv_get_softif_from_info(struct net *net, struct genl_info *info) +batadv_netlink_get_softif_from_ifindex(struct net *net, int ifindex) { struct net_device *soft_iface; - int ifindex; - - if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) - return ERR_PTR(-EINVAL); - - ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
soft_iface = dev_get_by_index(net, ifindex); if (!soft_iface) @@ -1184,28 +1165,61 @@ batadv_get_softif_from_info(struct net *net, struct genl_info *info) }
/** - * batadv_get_hardif_from_info() - Retrieve hardif from genl attributes - * @bat_priv: the bat priv with all the soft interface information + * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes * @net: the applicable net namespace * @info: receiver information * + * Return: Pointer to soft interface (with increased refcnt) on success, error + * pointer on error + */ +static struct net_device * +batadv_netlink_get_softif_from_info(struct net *net, struct genl_info *info) +{ + int ifindex; + + if (!info->attrs[BATADV_ATTR_MESH_IFINDEX]) + return ERR_PTR(-EINVAL); + + ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]); + + return batadv_netlink_get_softif_from_ifindex(net, ifindex); +} + +/** + * batadv_netlink_get_softif() - Retrieve soft interface from netlink callback + * @cb: callback structure containing arguments + * + * Return: Pointer to soft interface (with increased refcnt) on success, error + * pointer on error + */ +struct net_device *batadv_netlink_get_softif(struct netlink_callback *cb) +{ + int ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_MESH_IFINDEX); + if (!ifindex) + return ERR_PTR(-ENONET); + + return batadv_netlink_get_softif_from_ifindex(sock_net(cb->skb->sk), + ifindex); +} + +/** + * batadv_netlink_get_hardif_from_info() - Retrieve hard interface from ifindex + * @bat_priv: the bat priv with all the soft interface information + * @net: the applicable net namespace + * @ifindex: index of the hard interface + * * Return: Pointer to hard interface (with increased refcnt) on success, error * pointer on error */ static struct batadv_hard_iface * -batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net, - struct genl_info *info) +batadv_netlink_get_hardif_from_ifindex(struct batadv_priv *bat_priv, + struct net *net, int ifindex) { struct batadv_hard_iface *hard_iface; struct net_device *hard_dev; - unsigned int hardif_index;
- if (!info->attrs[BATADV_ATTR_HARD_IFINDEX]) - return ERR_PTR(-EINVAL); - - hardif_index = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]); - - hard_dev = dev_get_by_index(net, hardif_index); + hard_dev = dev_get_by_index(net, ifindex); if (!hard_dev) return ERR_PTR(-ENODEV);
@@ -1229,6 +1243,51 @@ batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net, return ERR_PTR(-EINVAL); }
+/** + * batadv_get_hardif_from_info() - Retrieve hardif from genl attributes + * @bat_priv: the bat priv with all the soft interface information + * @net: the applicable net namespace + * @info: receiver information + * + * Return: Pointer to hard interface (with increased refcnt) on success, error + * pointer on error + */ +static struct batadv_hard_iface * +batadv_netlink_get_hardif_from_info(struct batadv_priv *bat_priv, + struct net *net, struct genl_info *info) +{ + int ifindex; + + if (!info->attrs[BATADV_ATTR_HARD_IFINDEX]) + return ERR_PTR(-EINVAL); + + ifindex = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]); + + return batadv_netlink_get_hardif_from_ifindex(bat_priv, net, ifindex); +} + +/** + * batadv_netlink_get_hardif() - Retrieve hard interface from netlink callback + * @bat_priv: the bat priv with all the soft interface information + * @cb: callback structure containing arguments + * + * Return: Pointer to hard interface (with increased refcnt) on success, error + * pointer on error + */ +struct batadv_hard_iface * +batadv_netlink_get_hardif(struct batadv_priv *bat_priv, + struct netlink_callback *cb) +{ + int ifindex = batadv_netlink_get_ifindex(cb->nlh, + BATADV_ATTR_HARD_IFINDEX); + if (!ifindex) + return ERR_PTR(-ENONET); + + return batadv_netlink_get_hardif_from_ifindex(bat_priv, + sock_net(cb->skb->sk), + ifindex); +} + /** * batadv_get_vlan_from_info() - Retrieve vlan from genl attributes * @bat_priv: the bat priv with all the soft interface information @@ -1288,7 +1347,7 @@ static int batadv_pre_doit(const struct genl_split_ops *ops, return -EINVAL;
if (ops->internal_flags & BATADV_FLAG_NEED_MESH) { - soft_iface = batadv_get_softif_from_info(net, info); + soft_iface = batadv_netlink_get_softif_from_info(net, info); if (IS_ERR(soft_iface)) return PTR_ERR(soft_iface);
@@ -1297,7 +1356,8 @@ static int batadv_pre_doit(const struct genl_split_ops *ops, }
if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF) { - hard_iface = batadv_get_hardif_from_info(bat_priv, net, info); + hard_iface = batadv_netlink_get_hardif_from_info(bat_priv, net, + info); if (IS_ERR(hard_iface)) { ret = PTR_ERR(hard_iface); goto err_put_softif; @@ -1390,7 +1450,7 @@ static const struct genl_small_ops batadv_netlink_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, /* can be retrieved by unprivileged users */ .dumpit = batadv_netlink_dump_hardif, - .doit = batadv_netlink_get_hardif, + .doit = batadv_netlink_cmd_get_hardif, .internal_flags = BATADV_FLAG_NEED_MESH | BATADV_FLAG_NEED_HARDIF, }, diff --git a/net/batman-adv/netlink.h b/net/batman-adv/netlink.h index 876d2806a67d..2097c2ae98f1 100644 --- a/net/batman-adv/netlink.h +++ b/net/batman-adv/netlink.h @@ -15,7 +15,10 @@
void batadv_netlink_register(void); void batadv_netlink_unregister(void); -int batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype); +struct net_device *batadv_netlink_get_softif(struct netlink_callback *cb); +struct batadv_hard_iface * +batadv_netlink_get_hardif(struct batadv_priv *bat_priv, + struct netlink_callback *cb);
int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst, u8 result, u32 test_time, u64 total_bytes, diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 8f6dd2c6ee41..9ee9655d9bea 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -755,24 +755,15 @@ batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node, */ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; - struct net_device *hard_iface = NULL; - struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT; + struct batadv_hard_iface *hard_iface; struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; int ret; - int ifindex, hard_ifindex;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
@@ -782,22 +773,14 @@ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) goto out; }
- hard_ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_HARD_IFINDEX); - if (hard_ifindex) { - hard_iface = dev_get_by_index(net, hard_ifindex); - if (hard_iface) - hardif = batadv_hardif_get_by_netdev(hard_iface); - - if (!hardif) { - ret = -ENODEV; + hard_iface = batadv_netlink_get_hardif(bat_priv, cb); + if (IS_ERR(hard_iface)) { + if (PTR_ERR(hard_iface) != -ENONET) { + ret = PTR_ERR(hard_iface); goto out; }
- if (hardif->soft_iface != soft_iface) { - ret = -ENOENT; - goto out; - } + hard_iface = BATADV_IF_DEFAULT; }
if (!bat_priv->algo_ops->neigh.dump) { @@ -805,13 +788,12 @@ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) goto out; }
- bat_priv->algo_ops->neigh.dump(msg, cb, bat_priv, hardif); + bat_priv->algo_ops->neigh.dump(msg, cb, bat_priv, hard_iface);
ret = msg->len;
out: - batadv_hardif_put(hardif); - dev_put(hard_iface); + batadv_hardif_put(hard_iface); batadv_hardif_put(primary_if); dev_put(soft_iface);
@@ -1342,24 +1324,15 @@ static void batadv_purge_orig(struct work_struct *work) */ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; - struct net_device *hard_iface = NULL; - struct batadv_hard_iface *hardif = BATADV_IF_DEFAULT; + struct batadv_hard_iface *hard_iface = BATADV_IF_DEFAULT; struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; int ret; - int ifindex, hard_ifindex;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
@@ -1369,22 +1342,14 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) goto out; }
- hard_ifindex = batadv_netlink_get_ifindex(cb->nlh, - BATADV_ATTR_HARD_IFINDEX); - if (hard_ifindex) { - hard_iface = dev_get_by_index(net, hard_ifindex); - if (hard_iface) - hardif = batadv_hardif_get_by_netdev(hard_iface); - - if (!hardif) { - ret = -ENODEV; + hard_iface = batadv_netlink_get_hardif(bat_priv, cb); + if (IS_ERR(hard_iface)) { + if (PTR_ERR(hard_iface) != -ENONET) { + ret = PTR_ERR(hard_iface); goto out; }
- if (hardif->soft_iface != soft_iface) { - ret = -ENOENT; - goto out; - } + hard_iface = BATADV_IF_DEFAULT; }
if (!bat_priv->algo_ops->orig.dump) { @@ -1392,13 +1357,12 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) goto out; }
- bat_priv->algo_ops->orig.dump(msg, cb, bat_priv, hardif); + bat_priv->algo_ops->orig.dump(msg, cb, bat_priv, hard_iface);
ret = msg->len;
out: - batadv_hardif_put(hardif); - dev_put(hard_iface); + batadv_hardif_put(hard_iface); batadv_hardif_put(primary_if); dev_put(soft_iface);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index bc122c4de73d..a94734a9c3b1 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1161,26 +1161,18 @@ batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, */ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; struct batadv_hashtable *hash; int ret; - int ifindex; int bucket = cb->args[0]; int idx = cb->args[1]; int portid = NETLINK_CB(cb->skb).portid;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
@@ -1936,28 +1928,20 @@ batadv_tt_global_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq, */ int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb) { - struct net *net = sock_net(cb->skb->sk); struct net_device *soft_iface; struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; struct batadv_hashtable *hash; struct hlist_head *head; int ret; - int ifindex; int bucket = cb->args[0]; int idx = cb->args[1]; int sub = cb->args[2]; int portid = NETLINK_CB(cb->skb).portid;
- ifindex = batadv_netlink_get_ifindex(cb->nlh, BATADV_ATTR_MESH_IFINDEX); - if (!ifindex) - return -EINVAL; - - soft_iface = dev_get_by_index(net, ifindex); - if (!soft_iface || !batadv_softif_is_valid(soft_iface)) { - ret = -ENODEV; - goto out; - } + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface);
bat_priv = netdev_priv(soft_iface);
Similar to the translation table split the (mostly) locally maintained DAT cache and the DAT DHT concepts into two separate tables.
This eases the monitoring and debugging regarding the origin of DAT entries. And allows to apply differing properties to entries in the DAT cache and DAT DHT in the future, like distinct timeouts.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- include/uapi/linux/batman_adv.h | 5 + net/batman-adv/distributed-arp-table.c | 316 +++++++++++++++++++------ net/batman-adv/distributed-arp-table.h | 13 +- net/batman-adv/netlink.c | 5 + net/batman-adv/routing.c | 8 +- net/batman-adv/types.h | 7 +- 6 files changed, 269 insertions(+), 85 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 35dc016c9bb4..9498ccb09d67 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -613,6 +613,11 @@ enum batadv_nl_commands { */ BATADV_CMD_SET_VLAN,
+ /** + * @BATADV_CMD_GET_DAT_DHT: Query list of DAT DHT entries + */ + BATADV_CMD_GET_DAT_DHT, + /* add new commands above here */
/** diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 3a257fe07433..b1353afb5ceb 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -145,17 +145,17 @@ static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry) }
/** - * __batadv_dat_purge() - delete entries from the DAT local storage - * @bat_priv: the bat priv with all the soft interface information + * __batadv_dat_purge() - delete entries from a DAT hash table + * @hash: the hash table to delete from * @to_purge: function in charge to decide whether an entry has to be purged or * not. This function takes the dat_entry as argument and has to * returns a boolean value: true is the entry has to be deleted, * false otherwise * - * Loops over each entry in the DAT local storage and deletes it if and only if + * Loops over each entry in a DAT hash table and deletes it if and only if * the to_purge function passed as argument returns true. */ -static void __batadv_dat_purge(struct batadv_priv *bat_priv, +static void __batadv_dat_purge(struct batadv_hashtable *hash, bool (*to_purge)(struct batadv_dat_entry *)) { spinlock_t *list_lock; /* protects write access to the hash lists */ @@ -164,12 +164,12 @@ static void __batadv_dat_purge(struct batadv_priv *bat_priv, struct hlist_head *head; u32 i;
- if (!bat_priv->dat.hash) + if (!hash) return;
- for (i = 0; i < bat_priv->dat.hash->size; i++) { - head = &bat_priv->dat.hash->table[i]; - list_lock = &bat_priv->dat.hash->list_locks[i]; + for (i = 0; i < hash->size; i++) { + head = &hash->table[i]; + list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock); hlist_for_each_entry_safe(dat_entry, node_tmp, head, @@ -202,7 +202,8 @@ static void batadv_dat_purge(struct work_struct *work) priv_dat = container_of(delayed_work, struct batadv_priv_dat, work); bat_priv = container_of(priv_dat, struct batadv_priv, dat);
- __batadv_dat_purge(bat_priv, batadv_dat_to_purge); + __batadv_dat_purge(bat_priv->dat.cache_hash, batadv_dat_to_purge); + __batadv_dat_purge(bat_priv->dat.dht_hash, batadv_dat_to_purge); batadv_dat_start_timer(bat_priv); }
@@ -314,21 +315,19 @@ static u32 batadv_hash_dat(const void *data, u32 size) }
/** - * batadv_dat_entry_hash_find() - look for a given dat_entry in the local hash - * table - * @bat_priv: the bat priv with all the soft interface information + * batadv_dat_entry_hash_find() - look for a given dat_entry in a hash table + * @hash: the hash table to search in * @ip: search key * @vid: VLAN identifier * * Return: the dat_entry if found, NULL otherwise. */ static struct batadv_dat_entry * -batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, +batadv_dat_entry_hash_find(struct batadv_hashtable *hash, __be32 ip, unsigned short vid) { struct hlist_head *head; struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL; - struct batadv_hashtable *hash = bat_priv->dat.hash; u32 index;
if (!hash) @@ -356,28 +355,63 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, return dat_entry_tmp; }
+/** + * batadv_dat_cache_entry_find() - look for a given dat_entry in the DAT cache + * @bat_priv: the bat priv with all the soft interface information + * @ip: search key + * @vid: VLAN identifier + * + * Return: the dat_entry if found, NULL otherwise. + */ +static inline struct batadv_dat_entry * +batadv_dat_cache_entry_find(struct batadv_priv *bat_priv, __be32 ip, + unsigned short vid) +{ + return batadv_dat_entry_hash_find(bat_priv->dat.cache_hash, ip, vid); +} + +/** + * batadv_dat_dht_entry_find() - look for a given dat_entry in the DAT DHT + * @bat_priv: the bat priv with all the soft interface information + * @ip: search key + * @vid: VLAN identifier + * + * Return: the dat_entry if found, NULL otherwise. + */ +static inline struct batadv_dat_entry * +batadv_dat_dht_entry_find(struct batadv_priv *bat_priv, __be32 ip, + unsigned short vid) +{ + return batadv_dat_entry_hash_find(bat_priv->dat.dht_hash, ip, vid); +} + /** * batadv_dat_entry_add() - add a new dat entry or update it if already exists * @bat_priv: the bat priv with all the soft interface information + * @hash: the hash table to add to * @ip: ipv4 to add/edit * @mac_addr: mac address to assign to the given ipv4 * @vid: VLAN identifier + * @tablename: the name of the hash table to add to */ -static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, - u8 *mac_addr, unsigned short vid) +static void +batadv_dat_entry_add(struct batadv_priv *bat_priv, + struct batadv_hashtable *hash, __be32 ip, + u8 *mac_addr, unsigned short vid, + const char *tablename) { struct batadv_dat_entry *dat_entry; int hash_added;
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid); + dat_entry = batadv_dat_entry_hash_find(hash, ip, vid); /* if this entry is already known, just update it */ if (dat_entry) { if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) ether_addr_copy(dat_entry->mac_addr, mac_addr); dat_entry->last_update = jiffies; batadv_dbg(BATADV_DBG_DAT, bat_priv, - "Entry updated: %pI4 %pM (vid: %d)\n", - &dat_entry->ip, dat_entry->mac_addr, + "Entry updated in %s: %pI4 %pM (vid: %d)\n", + tablename, &dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid)); goto out; } @@ -393,7 +427,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, kref_init(&dat_entry->refcount);
kref_get(&dat_entry->refcount); - hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, + hash_added = batadv_hash_add(hash, batadv_compare_dat, batadv_hash_dat, dat_entry, &dat_entry->hash_entry);
@@ -403,13 +437,45 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, goto out; }
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n", - &dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid)); + batadv_dbg(BATADV_DBG_DAT, bat_priv, + "New entry added in %s: %pI4 %pM (vid: %d)\n", + tablename, &dat_entry->ip, dat_entry->mac_addr, + batadv_print_vid(vid));
out: batadv_dat_entry_put(dat_entry); }
+/** + * batadv_dat_cache_entry_add() - add or update dat_entry in the DAT cache + * @bat_priv: the bat priv with all the soft interface information + * @ip: ipv4 to add/edit + * @mac_addr: mac address to assign to the given ipv4 + * @vid: VLAN identifier + */ +static inline void +batadv_dat_cache_entry_add(struct batadv_priv *bat_priv, __be32 ip, + u8 *mac_addr, unsigned short vid) +{ + batadv_dat_entry_add(bat_priv, bat_priv->dat.cache_hash, ip, mac_addr, + vid, "cache"); +} + +/** + * batadv_dat_dht_entry_add() - add or update dat_entry in the DAT DHT + * @bat_priv: the bat priv with all the soft interface information + * @ip: ipv4 to add/edit + * @mac_addr: mac address to assign to the given ipv4 + * @vid: VLAN identifier + */ +static inline void +batadv_dat_dht_entry_add(struct batadv_priv *bat_priv, __be32 ip, + u8 *mac_addr, unsigned short vid) +{ + batadv_dat_entry_add(bat_priv, bat_priv->dat.dht_hash, ip, mac_addr, + vid, "dht"); +} + #ifdef CONFIG_BATMAN_ADV_DEBUG
/** @@ -786,19 +852,57 @@ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, }
/** - * batadv_dat_hash_free() - free the local DAT hash table + * batadv_dat_hash_free() - free a DAT hash table * @bat_priv: the bat priv with all the soft interface information */ -static void batadv_dat_hash_free(struct batadv_priv *bat_priv) +static void batadv_dat_hash_free(struct batadv_hashtable **hash) { - if (!bat_priv->dat.hash) + if (!(*hash)) return;
- __batadv_dat_purge(bat_priv, NULL); + __batadv_dat_purge(*hash, NULL);
- batadv_hash_destroy(bat_priv->dat.hash); + batadv_hash_destroy(*hash);
- bat_priv->dat.hash = NULL; + *hash = NULL; +} + +/** + * batadv_dat_cache_hash_init() - initialise the DAT cache hash table + * @bat_priv: the bat priv with all the soft interface information + * + * Return: 0 in case of success, a negative error code otherwise + */ +static int batadv_dat_cache_hash_init(struct batadv_priv *bat_priv) +{ + if (bat_priv->dat.cache_hash) + return 0; + + bat_priv->dat.cache_hash = batadv_hash_new(1024); + + if (!bat_priv->dat.cache_hash) + return -ENOMEM; + + return 0; +} + +/** + * batadv_dat_dht_hash_init() - initialise the DAT DHT hash table + * @bat_priv: the bat priv with all the soft interface information + * + * Return: 0 in case of success, a negative error code otherwise + */ +static int batadv_dat_dht_hash_init(struct batadv_priv *bat_priv) +{ + if (bat_priv->dat.dht_hash) + return 0; + + bat_priv->dat.dht_hash = batadv_hash_new(1024); + + if (!bat_priv->dat.dht_hash) + return -ENOMEM; + + return 0; }
/** @@ -809,13 +913,15 @@ static void batadv_dat_hash_free(struct batadv_priv *bat_priv) */ int batadv_dat_init(struct batadv_priv *bat_priv) { - if (bat_priv->dat.hash) - return 0; + int ret;
- bat_priv->dat.hash = batadv_hash_new(1024); + ret = batadv_dat_cache_hash_init(bat_priv); + if (ret < 0) + return ret;
- if (!bat_priv->dat.hash) - return -ENOMEM; + ret = batadv_dat_dht_hash_init(bat_priv); + if (ret < 0) + return ret;
INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge); batadv_dat_start_timer(bat_priv); @@ -838,30 +944,31 @@ void batadv_dat_free(struct batadv_priv *bat_priv)
cancel_delayed_work_sync(&bat_priv->dat.work);
- batadv_dat_hash_free(bat_priv); + batadv_dat_hash_free(&bat_priv->dat.cache_hash); + batadv_dat_hash_free(&bat_priv->dat.dht_hash); }
/** - * batadv_dat_cache_dump_entry() - dump one entry of the DAT cache table to a - * netlink socket + * batadv_dat_dump_entry() - dump one entry of a DAT hash table to a netlink + * socket * @msg: buffer for the message * @portid: netlink port * @cb: Control block containing additional options * @dat_entry: entry to dump + * @cmd: generic netlink command * * Return: 0 or error code. */ static int -batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid, - struct netlink_callback *cb, - struct batadv_dat_entry *dat_entry) +batadv_dat_dump_entry(struct sk_buff *msg, u32 portid, + struct netlink_callback *cb, + struct batadv_dat_entry *dat_entry, u8 cmd) { int msecs; void *hdr;
hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq, - &batadv_netlink_family, NLM_F_MULTI, - BATADV_CMD_GET_DAT_CACHE); + &batadv_netlink_family, NLM_F_MULTI, cmd); if (!hdr) return -ENOBUFS;
@@ -884,22 +991,23 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid, }
/** - * batadv_dat_cache_dump_bucket() - dump one bucket of the DAT cache table to - * a netlink socket + * batadv_dat_dump_bucket() - dump one bucket of a DAT hash table to a netlink + * socket * @msg: buffer for the message * @portid: netlink port * @cb: Control block containing additional options * @hash: hash to dump * @bucket: bucket index to dump * @idx_skip: How many entries to skip + * @cmd: generic netlink command * * Return: 0 or error code. */ static int -batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid, - struct netlink_callback *cb, - struct batadv_hashtable *hash, unsigned int bucket, - int *idx_skip) +batadv_dat_dump_bucket(struct sk_buff *msg, u32 portid, + struct netlink_callback *cb, + struct batadv_hashtable *hash, unsigned int bucket, + int *idx_skip, u8 cmd) { struct batadv_dat_entry *dat_entry; int idx = 0; @@ -911,7 +1019,7 @@ batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid, if (idx < *idx_skip) goto skip;
- if (batadv_dat_cache_dump_entry(msg, portid, cb, dat_entry)) { + if (batadv_dat_dump_entry(msg, portid, cb, dat_entry, cmd)) { spin_unlock_bh(&hash->list_locks[bucket]); *idx_skip = idx;
@@ -927,30 +1035,26 @@ batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid, }
/** - * batadv_dat_cache_dump() - dump DAT cache table to a netlink socket + * batadv_dat_dump() - dump a DAT hash table to a netlink socket + * @bat_priv: the bat priv with all the soft interface information * @msg: buffer for the message * @cb: callback structure containing arguments + * @hash: the hash table to dump from + * @cmd: generic netlink command * * Return: message length. */ -int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) +static int +batadv_dat_dump(struct batadv_priv *bat_priv, struct sk_buff *msg, + struct netlink_callback *cb, struct batadv_hashtable *hash, + u8 cmd) { - struct batadv_hard_iface *primary_if = NULL; int portid = NETLINK_CB(cb->skb).portid; - struct net_device *soft_iface; - struct batadv_hashtable *hash; - struct batadv_priv *bat_priv; + struct batadv_hard_iface *primary_if; int bucket = cb->args[0]; int idx = cb->args[1]; int ret = 0;
- soft_iface = batadv_netlink_get_softif(cb); - if (IS_ERR(soft_iface)) - return PTR_ERR(soft_iface); - - bat_priv = netdev_priv(soft_iface); - hash = bat_priv->dat.hash; - primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) { ret = -ENOENT; @@ -958,8 +1062,8 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) }
while (bucket < hash->size) { - if (batadv_dat_cache_dump_bucket(msg, portid, cb, hash, bucket, - &idx)) + if (batadv_dat_dump_bucket(msg, portid, cb, hash, bucket, &idx, + cmd)) break;
bucket++; @@ -974,8 +1078,58 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) out: batadv_hardif_put(primary_if);
+ return ret; +} + +/** + * batadv_dat_cache_dump() - dump the DAT cache table to a netlink socket + * @msg: buffer for the message + * @cb: callback structure containing arguments + * + * Return: Message length on success or a negative error number otherwise. + */ +int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net_device *soft_iface; + struct batadv_priv *bat_priv; + int ret; + + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface); + + bat_priv = netdev_priv(soft_iface); + + ret = batadv_dat_dump(bat_priv, msg, cb, bat_priv->dat.cache_hash, + BATADV_CMD_GET_DAT_CACHE); + dev_put(soft_iface); + return ret; +}
+/** + * batadv_dat_dht_dump() - dump the DAT DHT table to a netlink socket + * @msg: buffer for the message + * @cb: callback structure containing arguments + * + * Return: Message length on success or a negative error number otherwise. + */ +int batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct net_device *soft_iface; + struct batadv_priv *bat_priv; + int ret; + + soft_iface = batadv_netlink_get_softif(cb); + if (IS_ERR(soft_iface)) + return PTR_ERR(soft_iface); + + bat_priv = netdev_priv(soft_iface); + + ret = batadv_dat_dump(bat_priv, msg, cb, bat_priv->dat.dht_hash, + BATADV_CMD_GET_DAT_DHT); + + dev_put(soft_iface); return ret; }
@@ -1155,9 +1309,9 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, hw_src = batadv_arp_hw_src(skb, hdr_size); ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); + dat_entry = batadv_dat_cache_entry_find(bat_priv, ip_dst, vid); if (dat_entry) { /* If the ARP request is destined for a local client the local * client will answer itself. DAT would only generate a @@ -1247,9 +1401,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REQUEST");
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); + dat_entry = batadv_dat_dht_entry_find(bat_priv, ip_dst, vid); if (!dat_entry) goto out;
@@ -1310,8 +1464,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, hw_dst = batadv_arp_hw_dst(skb, hdr_size); ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); + batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
/* Send the ARP reply to the candidates for both the IP addresses that * the node obtained from the ARP reply @@ -1333,7 +1487,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, * packet has to be delivered to the interface */ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, - struct sk_buff *skb, int hdr_size) + struct sk_buff *skb, int hdr_size, + bool is_dht_put) { struct batadv_dat_entry *dat_entry = NULL; u16 type; @@ -1358,13 +1513,18 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, hw_dst = batadv_arp_hw_dst(skb, hdr_size); ip_dst = batadv_arp_ip_dst(skb, hdr_size);
+ if (is_dht_put) { + batadv_dat_dht_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_dht_entry_add(bat_priv, ip_dst, hw_dst, vid); + } + /* If ip_dst is already in cache and has the right mac address, * drop this frame if this ARP reply is destined for us because it's * most probably an ARP reply generated by another node of the DHT. * We have most probably received already a reply earlier. Delivering * this frame would lead to doubled receive of an ARP reply. */ - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid); + dat_entry = batadv_dat_cache_entry_find(bat_priv, ip_src, vid); if (dat_entry && batadv_compare_eth(hw_src, dat_entry->mac_addr)) { batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n", hw_src, &ip_src, hw_dst, &ip_dst, @@ -1375,8 +1535,8 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, /* Update our internal cache with both the IP addresses the node got * within the ARP reply */ - batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); + batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
if (dropped) goto out; @@ -1632,8 +1792,8 @@ static void batadv_dat_put_dhcp(struct batadv_priv *bat_priv, u8 *chaddr,
skb_set_network_header(skb, ETH_HLEN);
- batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid); - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); + batadv_dat_cache_entry_add(bat_priv, yiaddr, chaddr, vid); + batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
batadv_dat_forward_data(bat_priv, skb, yiaddr, vid, BATADV_P_DAT_DHT_PUT); @@ -1758,8 +1918,8 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, hw_src = ethhdr->h_source; vid = batadv_dat_get_vid(skb, &hdr_size);
- batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid); - batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_cache_entry_add(bat_priv, yiaddr, chaddr, vid); + batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
batadv_dbg(BATADV_DBG_DAT, bat_priv, "Snooped from incoming DHCPACK (server address): %pI4, %pM (vid: %i)\n", @@ -1803,7 +1963,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, goto out;
ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size); - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); + dat_entry = batadv_dat_cache_entry_find(bat_priv, ip_dst, vid); /* check if the node already got this entry */ if (!dat_entry) { batadv_dbg(BATADV_DBG_DAT, bat_priv, diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h index bed7f3d20844..28ac93b0113d 100644 --- a/net/batman-adv/distributed-arp-table.h +++ b/net/batman-adv/distributed-arp-table.h @@ -31,7 +31,8 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, struct sk_buff *skb); bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, - struct sk_buff *skb, int hdr_size); + struct sk_buff *skb, int hdr_size, + bool is_dht_put); void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv, struct sk_buff *skb, __be16 proto, @@ -74,6 +75,7 @@ batadv_dat_init_own_addr(struct batadv_priv *bat_priv, int batadv_dat_init(struct batadv_priv *bat_priv); void batadv_dat_free(struct batadv_priv *bat_priv); int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb); +int batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb);
/** * batadv_dat_inc_counter() - increment the correct DAT packet counter @@ -126,7 +128,8 @@ batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
static inline bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, - struct sk_buff *skb, int hdr_size) + struct sk_buff *skb, int hdr_size, + bool is_dht_put) { return false; } @@ -176,6 +179,12 @@ batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb) return -EOPNOTSUPP; }
+static inline int +batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb) +{ + return -EOPNOTSUPP; +} + static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv, u8 subtype) { diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index ce8e02d082d0..0463f166cea8 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -1502,6 +1502,11 @@ static const struct genl_small_ops batadv_netlink_ops[] = { .flags = GENL_UNS_ADMIN_PERM, .dumpit = batadv_dat_cache_dump, }, + { + .cmd = BATADV_CMD_GET_DAT_DHT, + .flags = GENL_ADMIN_PERM, + .dumpit = batadv_dat_dht_dump, + }, { .cmd = BATADV_CMD_GET_MCAST_FLAGS, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index f1061985149f..b3195a225ccc 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -943,10 +943,10 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, struct batadv_unicast_4addr_packet *unicast_4addr_packet; u8 *orig_addr, *orig_addr_gw; struct batadv_orig_node *orig_node = NULL, *orig_node_gw = NULL; + bool is4addr, is_gw, is_dht_put = false; int check, hdr_size = sizeof(*unicast_packet); enum batadv_subtype subtype; int ret = NET_RX_DROP; - bool is4addr, is_gw;
unicast_packet = (struct batadv_unicast_packet *)skb->data; is4addr = unicast_packet->packet_type == BATADV_UNICAST_4ADDR; @@ -1005,6 +1005,8 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, orig_addr = unicast_4addr_packet->src; orig_node = batadv_orig_hash_find(bat_priv, orig_addr); + } else if (subtype == BATADV_P_DAT_DHT_PUT) { + is_dht_put = true; } }
@@ -1012,7 +1014,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, hdr_size)) goto rx_success; if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, - hdr_size)) + hdr_size, is_dht_put)) goto rx_success;
batadv_dat_snoop_incoming_dhcp_ack(bat_priv, skb, hdr_size); @@ -1249,7 +1251,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size)) goto rx_success; - if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size)) + if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size, false)) goto rx_success;
batadv_dat_snoop_incoming_dhcp_ack(bat_priv, skb, hdr_size); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 04f6398b3a40..e018389d0ff9 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1231,8 +1231,11 @@ struct batadv_priv_dat { /** @addr: node DAT address */ batadv_dat_addr_t addr;
- /** @hash: hashtable representing the local ARP cache */ - struct batadv_hashtable *hash; + /** @cache_hash: hashtable representing the local ARP cache */ + struct batadv_hashtable *cache_hash; + + /** @dht_hash: hashtable representing the local DAT DHT */ + struct batadv_hashtable *dht_hash;
/** @work: work queue callback item for cache purging */ struct delayed_work work;
Currently, the DHT_GET messages of the DAT will likely be left unanswered due to the following issues:
When a node has a matching DAT Cache entry for a local ARP Request then this node will answer it directly with the information provided by the cache. This however, will likely lead to missing ARP Replies from the original host. Which in turn leads to the DAT DHT not being updated.
Then the local DAT cache entry will time out, triggering a unicasted DHT_GET. However, as the 5min. timeout has passed, the DAT DHT candidates will likely have purged their entry, too.
So basically this results in an ARP Request broadcast fallback every five minutes.
A second issue is that it is quite common that a host which has long gone offline will be tried to be contacted by another one at some remote period larger than the current 5min. timeout. This too leads to flooded ARP Requests.
With this patch the purge timeout for DAT DHT entries is increased to 30min to reduce the number of DAT ARP broadcast fallbacks.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- net/batman-adv/distributed-arp-table.c | 22 +++++++++++++++++----- net/batman-adv/main.h | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index b1353afb5ceb..5d548b28aa1e 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -133,15 +133,27 @@ static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry) }
/** - * batadv_dat_to_purge() - check whether a dat_entry has to be purged or not + * batadv_dat_cache_to_purge() - check if a cache entry has to be purged or not * @dat_entry: the entry to check * * Return: true if the entry has to be purged now, false otherwise. */ -static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry) +static bool batadv_dat_cache_to_purge(struct batadv_dat_entry *dat_entry) { return batadv_has_timed_out(dat_entry->last_update, - BATADV_DAT_ENTRY_TIMEOUT); + BATADV_DAT_CACHE_ENTRY_TIMEOUT); +} + +/** + * batadv_dat_dht_to_purge() - check if a DHT entry has to be purged or not + * @dat_entry: the entry to check + * + * Return: true if the entry has to be purged now, false otherwise. + */ +static bool batadv_dat_dht_to_purge(struct batadv_dat_entry *dat_entry) +{ + return batadv_has_timed_out(dat_entry->last_update, + BATADV_DAT_DHT_ENTRY_TIMEOUT); }
/** @@ -202,8 +214,8 @@ static void batadv_dat_purge(struct work_struct *work) priv_dat = container_of(delayed_work, struct batadv_priv_dat, work); bat_priv = container_of(priv_dat, struct batadv_priv, dat);
- __batadv_dat_purge(bat_priv->dat.cache_hash, batadv_dat_to_purge); - __batadv_dat_purge(bat_priv->dat.dht_hash, batadv_dat_to_purge); + __batadv_dat_purge(bat_priv->dat.cache_hash, batadv_dat_cache_to_purge); + __batadv_dat_purge(bat_priv->dat.dht_hash, batadv_dat_dht_to_purge); batadv_dat_start_timer(bat_priv); }
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 7d0e25cef0de..f3ac3b34ef83 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -38,7 +38,8 @@ #define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */ #define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */ #define BATADV_MCAST_WORK_PERIOD 500 /* 0.5 seconds */ -#define BATADV_DAT_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */ +#define BATADV_DAT_CACHE_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */ +#define BATADV_DAT_DHT_ENTRY_TIMEOUT (30 * 60000) /* 30 mins in milliseconds */ /* sliding packet range of received originator messages in sequence numbers * (should be a multiple of our word size) */
b.a.t.m.a.n@lists.open-mesh.org