提交 7da5ee09 编写于 作者: D David S. Miller

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Antonio Quartulli says:

====================
batman-adv 20160229

this is our (hopefully) latest batch of patches intended for net-next.

With this patchset we finally introduce B.A.T.M.A.N. V: the latest
version of our routing protocol.
Technical documentation describing the protocol in more detail can
be found in our wiki[1][2][3][4].

For what concerns this pull request, you can find the high level
description right below.

[1] https://www.open-mesh.org/projects/batman-adv/wiki/BATMAN_V
[2] https://www.open-mesh.org/projects/batman-adv/wiki/OGMv2
[3] https://www.open-mesh.org/projects/batman-adv/wiki/ELP
[4] https://www.open-mesh.org/projects/batman-adv/wiki/BATMAN_V_Tests

 ...

With this patchset we finally introduce our new routing protocol:
B.A.T.M.A.N. V. Its implementation started quite some years ago,
but due to the big changes being introduced it took a while to be
discussed, designed, worked, re-worked, tested and debugged (well,
we're never done with the latest). The entire operation has
basically been a team work involving all the core contributors
together with other people interested in the project.

The new protocol is divided into two main subcomponents, called
respectively ELP and OGMv2. The former is in charge of
dealing with the neighbour discovery and link quality estimation,
while the latter implements the algorithm that spreads the
metrics around the network and computes optimal paths.

The biggest change introduced with B.A.T.M.A.N. V is the new
metric: the protocol won't rely on packet loss anymore, but it
will use the estimated throughput extracted directly from the
wifi driver (when available) by querying cfg80211.
Batman-adv will also send some unicast probing packets when
an interface is not used for payload traffic to make sure that
such values are current.

The new protocol can be compiled-in or not like other
features we have and when selected will pull in CFG80211 as
dependency for the reason described above.

Thanks to the big work brought up in the past by Marek Lindner,
batman-adv can easily deal several protocol implementations,
therefore compiling in this new version does not exclude the
older.
This means that the user is offered the option to choose
the protocol when creating the mesh interface (default is the
old one to keep backward compatibility).

Along with the protocol there are some sysfs knobs that are
introduced to fine tune some of its behaviours, but users
are recommended to keep the default values unless they know
what they are doing.

The last patch is about advertising our own patchwork platform
(thanks to Sven Eckelmann for having set that up!) in the
MAINTAINERS file.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
What: /sys/class/net/<iface>/batman-adv/throughput_override
Date: Feb 2014
Contact: Antonio Quartulli <antonio@meshcoding.com>
description:
Defines the throughput value to be used by B.A.T.M.A.N. V
when estimating the link throughput using this interface.
If the value is set to 0 then batman-adv will try to
estimate the throughput by itself.
What: /sys/class/net/<iface>/batman-adv/elp_interval
Date: Feb 2014
Contact: Linus Lüssing <linus.luessing@web.de>
Description:
Defines the interval in milliseconds in which batman
sends its probing packets for link quality measurements.
What: /sys/class/net/<iface>/batman-adv/iface_status
Date: May 2010
Contact: Marek Lindner <mareklindner@neomailbox.ch>
......@@ -12,4 +28,3 @@ Description:
The /sys/class/net/<iface>/batman-adv/mesh_iface file
displays the batman mesh interface this <iface>
currently is associated with.
......@@ -2152,6 +2152,7 @@ M: Simon Wunderlich <sw@simonwunderlich.de>
M: Antonio Quartulli <a@unstable.cc>
L: b.a.t.m.a.n@lists.open-mesh.org
W: https://www.open-mesh.org/
Q: https://patchwork.open-mesh.org/project/batman/list/
S: Maintained
F: net/batman-adv/
......
......@@ -15,6 +15,20 @@ config BATMAN_ADV
https://www.open-mesh.org/ for more information and user space
tools.
config BATMAN_ADV_BATMAN_V
bool "B.A.T.M.A.N. V protocol (experimental)"
depends on BATMAN_ADV && CFG80211
default n
help
This option enables the B.A.T.M.A.N. V protocol, the successor
of the currently used B.A.T.M.A.N. IV protocol. The main
changes include splitting of the OGM protocol into a neighbor
discovery protocol (Echo Location Protocol, ELP) and a new OGM
Protocol OGMv2 for flooding protocol information through the
network, as well as a throughput based metric.
B.A.T.M.A.N. V is currently considered experimental and not
compatible to B.A.T.M.A.N. IV networks.
config BATMAN_ADV_BLA
bool "Bridge Loop Avoidance"
depends on BATMAN_ADV && INET
......
......@@ -18,6 +18,9 @@
obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
batman-adv-y += bat_iv_ogm.o
batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o
batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_elp.o
batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_ogm.o
batman-adv-y += bitarray.o
batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o
batman-adv-$(CONFIG_DEBUG_FS) += debugfs.o
......
/* Copyright (C) 2011-2016 B.A.T.M.A.N. contributors:
*
* Marek Lindner
* Marek Lindner, Linus Lüssing
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
......@@ -18,6 +18,32 @@
#ifndef _NET_BATMAN_ADV_BAT_ALGO_H_
#define _NET_BATMAN_ADV_BAT_ALGO_H_
struct batadv_priv;
int batadv_iv_init(void);
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
int batadv_v_init(void);
int batadv_v_mesh_init(struct batadv_priv *bat_priv);
void batadv_v_mesh_free(struct batadv_priv *bat_priv);
#else
static inline int batadv_v_init(void)
{
return 0;
}
static inline int batadv_v_mesh_init(struct batadv_priv *bat_priv)
{
return 0;
}
static inline void batadv_v_mesh_free(struct batadv_priv *bat_priv)
{
}
#endif /* CONFIG_BATMAN_ADV_BATMAN_V */
#endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */
......@@ -478,7 +478,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
skb->len + ETH_HLEN);
batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
batadv_send_broadcast_skb(skb, hard_iface);
}
}
......
/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
*
* Linus Lüssing, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "bat_algo.h"
#include "main.h"
#include <linux/atomic.h>
#include <linux/bug.h>
#include <linux/cache.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/netdevice.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include "bat_v_elp.h"
#include "bat_v_ogm.h"
#include "hash.h"
#include "originator.h"
#include "packet.h"
static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
{
int ret;
ret = batadv_v_elp_iface_enable(hard_iface);
if (ret < 0)
return ret;
ret = batadv_v_ogm_iface_enable(hard_iface);
if (ret < 0)
batadv_v_elp_iface_disable(hard_iface);
/* enable link throughput auto-detection by setting the throughput
* override to zero
*/
atomic_set(&hard_iface->bat_v.throughput_override, 0);
return ret;
}
static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
{
batadv_v_elp_iface_disable(hard_iface);
}
static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
{
}
static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
{
batadv_v_elp_primary_iface_set(hard_iface);
batadv_v_ogm_primary_iface_set(hard_iface);
}
static void
batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
{
ewma_throughput_init(&hardif_neigh->bat_v.throughput);
INIT_WORK(&hardif_neigh->bat_v.metric_work,
batadv_v_elp_throughput_metric_update);
}
static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface)
{
}
static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
{
}
/**
* batadv_v_orig_print_neigh - print neighbors for the originator table
* @orig_node: the orig_node for which the neighbors are printed
* @if_outgoing: outgoing interface for these entries
* @seq: debugfs table seq_file struct
*
* Must be called while holding an rcu lock.
*/
static void
batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing,
struct seq_file *seq)
{
struct batadv_neigh_node *neigh_node;
struct batadv_neigh_ifinfo *n_ifinfo;
hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
if (!n_ifinfo)
continue;
seq_printf(seq, " %pM (%9u.%1u)",
neigh_node->addr,
n_ifinfo->bat_v.throughput / 10,
n_ifinfo->bat_v.throughput % 10);
batadv_neigh_ifinfo_put(n_ifinfo);
}
}
/**
* batadv_v_hardif_neigh_print - print a single ELP neighbour node
* @seq: neighbour table seq_file struct
* @hardif_neigh: hardif neighbour information
*/
static void
batadv_v_hardif_neigh_print(struct seq_file *seq,
struct batadv_hardif_neigh_node *hardif_neigh)
{
int last_secs, last_msecs;
u32 throughput;
last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n",
hardif_neigh->addr, last_secs, last_msecs, throughput / 10,
throughput % 10, hardif_neigh->if_incoming->net_dev->name);
}
/**
* batadv_v_neigh_print - print the single hop neighbour list
* @bat_priv: the bat priv with all the soft interface information
* @seq: neighbour table seq_file struct
*/
static void batadv_v_neigh_print(struct batadv_priv *bat_priv,
struct seq_file *seq)
{
struct net_device *net_dev = (struct net_device *)seq->private;
struct batadv_hardif_neigh_node *hardif_neigh;
struct batadv_hard_iface *hard_iface;
int batman_count = 0;
seq_printf(seq, " %-15s %s (%11s) [%10s]\n", "Neighbor",
"last-seen", "throughput", "IF");
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->soft_iface != net_dev)
continue;
hlist_for_each_entry_rcu(hardif_neigh,
&hard_iface->neigh_list, list) {
batadv_v_hardif_neigh_print(seq, hardif_neigh);
batman_count++;
}
}
rcu_read_unlock();
if (batman_count == 0)
seq_puts(seq, "No batman nodes in range ...\n");
}
/**
* batadv_v_orig_print - print the originator table
* @bat_priv: the bat priv with all the soft interface information
* @seq: debugfs table seq_file struct
* @if_outgoing: the outgoing interface for which this should be printed
*/
static void batadv_v_orig_print(struct batadv_priv *bat_priv,
struct seq_file *seq,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_neigh_node *neigh_node;
struct batadv_hashtable *hash = bat_priv->orig_hash;
int last_seen_msecs, last_seen_secs;
struct batadv_orig_node *orig_node;
struct batadv_neigh_ifinfo *n_ifinfo;
unsigned long last_seen_jiffies;
struct hlist_head *head;
int batman_count = 0;
u32 i;
seq_printf(seq, " %-15s %s (%11s) %17s [%10s]: %20s ...\n",
"Originator", "last-seen", "throughput", "Nexthop",
"outgoingIF", "Potential nexthops");
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
neigh_node = batadv_orig_router_get(orig_node,
if_outgoing);
if (!neigh_node)
continue;
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
if_outgoing);
if (!n_ifinfo)
goto next;
last_seen_jiffies = jiffies - orig_node->last_seen;
last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
last_seen_secs = last_seen_msecs / 1000;
last_seen_msecs = last_seen_msecs % 1000;
seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:",
orig_node->orig, last_seen_secs,
last_seen_msecs,
n_ifinfo->bat_v.throughput / 10,
n_ifinfo->bat_v.throughput % 10,
neigh_node->addr,
neigh_node->if_incoming->net_dev->name);
batadv_v_orig_print_neigh(orig_node, if_outgoing, seq);
seq_puts(seq, "\n");
batman_count++;
next:
batadv_neigh_node_put(neigh_node);
if (n_ifinfo)
batadv_neigh_ifinfo_put(n_ifinfo);
}
rcu_read_unlock();
}
if (batman_count == 0)
seq_puts(seq, "No batman nodes in range ...\n");
}
static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2)
{
struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
if (WARN_ON(!ifinfo1 || !ifinfo2))
return 0;
return ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
}
static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2)
{
struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
u32 threshold;
ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
threshold = ifinfo1->bat_v.throughput / 4;
threshold = ifinfo1->bat_v.throughput - threshold;
return ifinfo2->bat_v.throughput > threshold;
}
static struct batadv_algo_ops batadv_batman_v __read_mostly = {
.name = "BATMAN_V",
.bat_iface_enable = batadv_v_iface_enable,
.bat_iface_disable = batadv_v_iface_disable,
.bat_iface_update_mac = batadv_v_iface_update_mac,
.bat_primary_iface_set = batadv_v_primary_iface_set,
.bat_hardif_neigh_init = batadv_v_hardif_neigh_init,
.bat_ogm_emit = batadv_v_ogm_emit,
.bat_ogm_schedule = batadv_v_ogm_schedule,
.bat_orig_print = batadv_v_orig_print,
.bat_neigh_cmp = batadv_v_neigh_cmp,
.bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob,
.bat_neigh_print = batadv_v_neigh_print,
};
/**
* batadv_v_mesh_init - initialize the B.A.T.M.A.N. V private resources for a
* mesh
* @bat_priv: the object representing the mesh interface to initialise
*
* Return: 0 on success or a negative error code otherwise
*/
int batadv_v_mesh_init(struct batadv_priv *bat_priv)
{
return batadv_v_ogm_init(bat_priv);
}
/**
* batadv_v_mesh_free - free the B.A.T.M.A.N. V private resources for a mesh
* @bat_priv: the object representing the mesh interface to free
*/
void batadv_v_mesh_free(struct batadv_priv *bat_priv)
{
batadv_v_ogm_free(bat_priv);
}
/**
* batadv_v_init - B.A.T.M.A.N. V initialization function
*
* Description: Takes care of initializing all the subcomponents.
* It is invoked upon module load only.
*
* Return: 0 on success or a negative error code otherwise
*/
int __init batadv_v_init(void)
{
int ret;
/* B.A.T.M.A.N. V echo location protocol packet */
ret = batadv_recv_handler_register(BATADV_ELP,
batadv_v_elp_packet_recv);
if (ret < 0)
return ret;
ret = batadv_recv_handler_register(BATADV_OGM2,
batadv_v_ogm_packet_recv);
if (ret < 0)
goto elp_unregister;
ret = batadv_algo_register(&batadv_batman_v);
if (ret < 0)
goto ogm_unregister;
return ret;
ogm_unregister:
batadv_recv_handler_unregister(BATADV_OGM2);
elp_unregister:
batadv_recv_handler_unregister(BATADV_ELP);
return ret;
}
/* Copyright (C) 2011-2016 B.A.T.M.A.N. contributors:
*
* Linus Lüssing, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "bat_v_elp.h"
#include "main.h"
#include <linux/atomic.h>
#include <linux/byteorder/generic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/fs.h>
#include <linux/if_ether.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/netdevice.h>
#include <linux/random.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <net/cfg80211.h>
#include "bat_algo.h"
#include "bat_v_ogm.h"
#include "hard-interface.h"
#include "originator.h"
#include "packet.h"
#include "routing.h"
#include "send.h"
/**
* batadv_v_elp_start_timer - restart timer for ELP periodic work
* @hard_iface: the interface for which the timer has to be reset
*/
static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
{
unsigned int msecs;
msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
msecs += prandom_u32() % (2 * BATADV_JITTER);
queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
msecs_to_jiffies(msecs));
}
/**
* batadv_v_elp_get_throughput - get the throughput towards a neighbour
* @neigh: the neighbour for which the throughput has to be obtained
*
* Return: The throughput towards the given neighbour in multiples of 100kpbs
* (a value of '1' equals to 0.1Mbps, '10' equals 1Mbps, etc).
*/
static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
{
struct batadv_hard_iface *hard_iface = neigh->if_incoming;
struct ethtool_link_ksettings link_settings;
struct station_info sinfo;
u32 throughput;
int ret;
/* if the user specified a customised value for this interface, then
* return it directly
*/
throughput = atomic_read(&hard_iface->bat_v.throughput_override);
if (throughput != 0)
return throughput;
/* if this is a wireless device, then ask its throughput through
* cfg80211 API
*/
if (batadv_is_wifi_netdev(hard_iface->net_dev)) {
if (hard_iface->net_dev->ieee80211_ptr) {
ret = cfg80211_get_station(hard_iface->net_dev,
neigh->addr, &sinfo);
if (ret == -ENOENT) {
/* Node is not associated anymore! It would be
* possible to delete this neighbor. For now set
* the throughput metric to 0.
*/
return 0;
}
if (!ret)
return sinfo.expected_throughput / 100;
}
/* unsupported WiFi driver version */
goto default_throughput;
}
/* if not a wifi interface, check if this device provides data via
* ethtool (e.g. an Ethernet adapter)
*/
memset(&link_settings, 0, sizeof(link_settings));
rtnl_lock();
ret = __ethtool_get_link_ksettings(hard_iface->net_dev, &link_settings);
rtnl_unlock();
if (ret == 0) {
/* link characteristics might change over time */
if (link_settings.base.duplex == DUPLEX_FULL)
hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
else
hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
throughput = link_settings.base.speed;
if (throughput && (throughput != SPEED_UNKNOWN))
return throughput * 10;
}
default_throughput:
if (!(hard_iface->bat_v.flags & BATADV_WARNING_DEFAULT)) {
batadv_info(hard_iface->soft_iface,
"WiFi driver or ethtool info does not provide information about link speeds on interface %s, therefore defaulting to hardcoded throughput values of %u.%1u Mbps. Consider overriding the throughput manually or checking your driver.\n",
hard_iface->net_dev->name,
BATADV_THROUGHPUT_DEFAULT_VALUE / 10,
BATADV_THROUGHPUT_DEFAULT_VALUE % 10);
hard_iface->bat_v.flags |= BATADV_WARNING_DEFAULT;
}
/* if none of the above cases apply, return the base_throughput */
return BATADV_THROUGHPUT_DEFAULT_VALUE;
}
/**
* batadv_v_elp_throughput_metric_update - worker updating the throughput metric
* of a single hop neighbour
* @work: the work queue item
*/
void batadv_v_elp_throughput_metric_update(struct work_struct *work)
{
struct batadv_hardif_neigh_node_bat_v *neigh_bat_v;
struct batadv_hardif_neigh_node *neigh;
neigh_bat_v = container_of(work, struct batadv_hardif_neigh_node_bat_v,
metric_work);
neigh = container_of(neigh_bat_v, struct batadv_hardif_neigh_node,
bat_v);
ewma_throughput_add(&neigh->bat_v.throughput,
batadv_v_elp_get_throughput(neigh));
/* decrement refcounter to balance increment performed before scheduling
* this task
*/
batadv_hardif_neigh_put(neigh);
}
/**
* batadv_v_elp_wifi_neigh_probe - send link probing packets to a neighbour
* @neigh: the neighbour to probe
*
* Sends a predefined number of unicast wifi packets to a given neighbour in
* order to trigger the throughput estimation on this link by the RC algorithm.
* Packets are sent only if there there is not enough payload unicast traffic
* towards this neighbour..
*
* Return: True on success and false in case of error during skb preparation.
*/
static bool
batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh)
{
struct batadv_hard_iface *hard_iface = neigh->if_incoming;
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
unsigned long last_tx_diff;
struct sk_buff *skb;
int probe_len, i;
int elp_skb_len;
/* this probing routine is for Wifi neighbours only */
if (!batadv_is_wifi_netdev(hard_iface->net_dev))
return true;
/* probe the neighbor only if no unicast packets have been sent
* to it in the last 100 milliseconds: this is the rate control
* algorithm sampling interval (minstrel). In this way, if not
* enough traffic has been sent to the neighbor, batman-adv can
* generate 2 probe packets and push the RC algorithm to perform
* the sampling
*/
last_tx_diff = jiffies_to_msecs(jiffies - neigh->bat_v.last_unicast_tx);
if (last_tx_diff <= BATADV_ELP_PROBE_MAX_TX_DIFF)
return true;
probe_len = max_t(int, sizeof(struct batadv_elp_packet),
BATADV_ELP_MIN_PROBE_SIZE);
for (i = 0; i < BATADV_ELP_PROBES_PER_NODE; i++) {
elp_skb_len = hard_iface->bat_v.elp_skb->len;
skb = skb_copy_expand(hard_iface->bat_v.elp_skb, 0,
probe_len - elp_skb_len,
GFP_ATOMIC);
if (!skb)
return false;
/* Tell the skb to get as big as the allocated space (we want
* the packet to be exactly of that size to make the link
* throughput estimation effective.
*/
skb_put(skb, probe_len - hard_iface->bat_v.elp_skb->len);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Sending unicast (probe) ELP packet on interface %s to %pM\n",
hard_iface->net_dev->name, neigh->addr);
batadv_send_skb_packet(skb, hard_iface, neigh->addr);
}
return true;
}
/**
* batadv_v_elp_periodic_work - ELP periodic task per interface
* @work: work queue item
*
* Emits broadcast ELP message in regular intervals.
*/
static void batadv_v_elp_periodic_work(struct work_struct *work)
{
struct batadv_hardif_neigh_node *hardif_neigh;
struct batadv_hard_iface *hard_iface;
struct batadv_hard_iface_bat_v *bat_v;
struct batadv_elp_packet *elp_packet;
struct batadv_priv *bat_priv;
struct sk_buff *skb;
u32 elp_interval;
bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
bat_priv = netdev_priv(hard_iface->soft_iface);
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
goto out;
/* we are in the process of shutting this interface down */
if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
(hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
goto out;
/* the interface was enabled but may not be ready yet */
if (hard_iface->if_status != BATADV_IF_ACTIVE)
goto restart_timer;
skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
if (!skb)
goto restart_timer;
elp_packet = (struct batadv_elp_packet *)skb->data;
elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
elp_packet->elp_interval = htonl(elp_interval);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Sending broadcast ELP packet on interface %s, seqno %u\n",
hard_iface->net_dev->name,
atomic_read(&hard_iface->bat_v.elp_seqno));
batadv_send_broadcast_skb(skb, hard_iface);
atomic_inc(&hard_iface->bat_v.elp_seqno);
/* The throughput metric is updated on each sent packet. This way, if a
* node is dead and no longer sends packets, batman-adv is still able to
* react timely to its death.
*
* The throughput metric is updated by following these steps:
* 1) if the hard_iface is wifi => send a number of unicast ELPs for
* probing/sampling to each neighbor
* 2) update the throughput metric value of each neighbor (note that the
* value retrieved in this step might be 100ms old because the
* probing packets at point 1) could still be in the HW queue)
*/
rcu_read_lock();
hlist_for_each_entry_rcu(hardif_neigh, &hard_iface->neigh_list, list) {
if (!batadv_v_elp_wifi_neigh_probe(hardif_neigh))
/* if something goes wrong while probing, better to stop
* sending packets immediately and reschedule the task
*/
break;
if (!kref_get_unless_zero(&hardif_neigh->refcount))
continue;
/* Reading the estimated throughput from cfg80211 is a task that
* may sleep and that is not allowed in an rcu protected
* context. Therefore schedule a task for that.
*/
queue_work(batadv_event_workqueue,
&hardif_neigh->bat_v.metric_work);
}
rcu_read_unlock();
restart_timer:
batadv_v_elp_start_timer(hard_iface);
out:
return;
}
/**
* batadv_v_elp_iface_enable - setup the ELP interface private resources
* @hard_iface: interface for which the data has to be prepared
*
* Return: 0 on success or a -ENOMEM in case of failure.
*/
int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
{
struct batadv_elp_packet *elp_packet;
unsigned char *elp_buff;
u32 random_seqno;
size_t size;
int res = -ENOMEM;
size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN;
hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
if (!hard_iface->bat_v.elp_skb)
goto out;
skb_reserve(hard_iface->bat_v.elp_skb, ETH_HLEN + NET_IP_ALIGN);
elp_buff = skb_push(hard_iface->bat_v.elp_skb, BATADV_ELP_HLEN);
elp_packet = (struct batadv_elp_packet *)elp_buff;
memset(elp_packet, 0, BATADV_ELP_HLEN);
elp_packet->packet_type = BATADV_ELP;
elp_packet->version = BATADV_COMPAT_VERSION;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));
atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
atomic_set(&hard_iface->bat_v.elp_interval, 500);
/* assume full-duplex by default */
hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
/* warn the user (again) if there is no throughput data is available */
hard_iface->bat_v.flags &= ~BATADV_WARNING_DEFAULT;
if (batadv_is_wifi_netdev(hard_iface->net_dev))
hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
batadv_v_elp_periodic_work);
batadv_v_elp_start_timer(hard_iface);
res = 0;
out:
return res;
}
/**
* batadv_v_elp_iface_disable - release ELP interface private resources
* @hard_iface: interface for which the resources have to be released
*/
void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
{
cancel_delayed_work_sync(&hard_iface->bat_v.elp_wq);
dev_kfree_skb(hard_iface->bat_v.elp_skb);
hard_iface->bat_v.elp_skb = NULL;
}
/**
* batadv_v_elp_primary_iface_set - change internal data to reflect the new
* primary interface
* @primary_iface: the new primary interface
*/
void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
{
struct batadv_hard_iface *hard_iface;
struct batadv_elp_packet *elp_packet;
struct sk_buff *skb;
/* update orig field of every elp iface belonging to this mesh */
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (primary_iface->soft_iface != hard_iface->soft_iface)
continue;
if (!hard_iface->bat_v.elp_skb)
continue;
skb = hard_iface->bat_v.elp_skb;
elp_packet = (struct batadv_elp_packet *)skb->data;
ether_addr_copy(elp_packet->orig,
primary_iface->net_dev->dev_addr);
}
rcu_read_unlock();
}
/**
* batadv_v_elp_neigh_update - update an ELP neighbour node
* @bat_priv: the bat priv with all the soft interface information
* @neigh_addr: the neighbour interface address
* @if_incoming: the interface the packet was received through
* @elp_packet: the received ELP packet
*
* Updates the ELP neighbour node state with the data received within the new
* ELP packet.
*/
static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
u8 *neigh_addr,
struct batadv_hard_iface *if_incoming,
struct batadv_elp_packet *elp_packet)
{
struct batadv_neigh_node *neigh;
struct batadv_orig_node *orig_neigh;
struct batadv_hardif_neigh_node *hardif_neigh;
s32 seqno_diff;
s32 elp_latest_seqno;
orig_neigh = batadv_v_ogm_orig_get(bat_priv, elp_packet->orig);
if (!orig_neigh)
return;
neigh = batadv_neigh_node_new(orig_neigh, if_incoming, neigh_addr);
if (!neigh)
goto orig_free;
hardif_neigh = batadv_hardif_neigh_get(if_incoming, neigh_addr);
if (!hardif_neigh)
goto neigh_free;
elp_latest_seqno = hardif_neigh->bat_v.elp_latest_seqno;
seqno_diff = ntohl(elp_packet->seqno) - elp_latest_seqno;
/* known or older sequence numbers are ignored. However always adopt
* if the router seems to have been restarted.
*/
if (seqno_diff < 1 && seqno_diff > -BATADV_ELP_MAX_AGE)
goto hardif_free;
neigh->last_seen = jiffies;
hardif_neigh->last_seen = jiffies;
hardif_neigh->bat_v.elp_latest_seqno = ntohl(elp_packet->seqno);
hardif_neigh->bat_v.elp_interval = ntohl(elp_packet->elp_interval);
hardif_free:
if (hardif_neigh)
batadv_hardif_neigh_put(hardif_neigh);
neigh_free:
if (neigh)
batadv_neigh_node_put(neigh);
orig_free:
if (orig_neigh)
batadv_orig_node_put(orig_neigh);
}
/**
* batadv_v_elp_packet_recv - main ELP packet handler
* @skb: the received packet
* @if_incoming: the interface this packet was received through
*
* Return: NET_RX_SUCCESS and consumes the skb if the packet was peoperly
* processed or NET_RX_DROP in case of failure.
*/
int batadv_v_elp_packet_recv(struct sk_buff *skb,
struct batadv_hard_iface *if_incoming)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batadv_elp_packet *elp_packet;
struct batadv_hard_iface *primary_if;
struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN);
if (!ret)
return NET_RX_DROP;
if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
return NET_RX_DROP;
/* did we receive a B.A.T.M.A.N. V ELP packet on an interface
* that does not have B.A.T.M.A.N. V ELP enabled ?
*/
if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
return NET_RX_DROP;
elp_packet = (struct batadv_elp_packet *)skb->data;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Received ELP packet from %pM seqno %u ORIG: %pM\n",
ethhdr->h_source, ntohl(elp_packet->seqno),
elp_packet->orig);
primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if)
goto out;
batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming,
elp_packet);
out:
if (primary_if)
batadv_hardif_put(primary_if);
consume_skb(skb);
return NET_RX_SUCCESS;
}
/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
*
* Linus Lüssing, Marek Lindner
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_
#define _NET_BATMAN_ADV_BAT_V_ELP_H_
struct sk_buff;
struct work_struct;
int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface);
int batadv_v_elp_packet_recv(struct sk_buff *skb,
struct batadv_hard_iface *if_incoming);
void batadv_v_elp_throughput_metric_update(struct work_struct *work);
#endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
此差异已折叠。
/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
*
* Antonio Quartulli
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BATMAN_ADV_BATADV_V_OGM_H_
#define _BATMAN_ADV_BATADV_V_OGM_H_
#include <linux/types.h>
struct batadv_hard_iface;
struct batadv_priv;
struct sk_buff;
int batadv_v_ogm_init(struct batadv_priv *bat_priv);
void batadv_v_ogm_free(struct batadv_priv *bat_priv);
int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface);
struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
const u8 *addr);
void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface);
int batadv_v_ogm_packet_recv(struct sk_buff *skb,
struct batadv_hard_iface *if_incoming);
#endif /* _BATMAN_ADV_BATADV_V_OGM_H_ */
......@@ -654,9 +654,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
goto free_neigh;
}
send_status = batadv_send_skb_packet(tmp_skb,
neigh_node->if_incoming,
neigh_node->addr);
send_status = batadv_send_unicast_skb(tmp_skb, neigh_node);
if (send_status == NET_XMIT_SUCCESS) {
/* count the sent packet */
switch (packet_subtype) {
......
......@@ -378,8 +378,7 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,
skb->len + ETH_HLEN);
packet->ttl--;
batadv_send_skb_packet(skb, neigh_node->if_incoming,
neigh_node->addr);
batadv_send_unicast_skb(skb, neigh_node);
ret = true;
}
......@@ -486,8 +485,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
skb_fragment->len + ETH_HLEN);
batadv_send_skb_packet(skb_fragment, neigh_node->if_incoming,
neigh_node->addr);
batadv_send_unicast_skb(skb_fragment, neigh_node);
frag_header.no++;
/* The initial check in this function should cover this case */
......@@ -506,7 +504,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
skb->len + ETH_HLEN);
batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
batadv_send_unicast_skb(skb, neigh_node);
ret = true;
......
......@@ -40,8 +40,8 @@
*
* Return: false on parse error and true otherwise.
*/
static bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
const char *description, u32 *throughput)
bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
const char *description, u32 *throughput)
{
enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT;
u64 lthroughput;
......
......@@ -49,5 +49,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv);
void batadv_gw_init(struct batadv_priv *bat_priv);
void batadv_gw_free(struct batadv_priv *bat_priv);
bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
const char *description, u32 *throughput);
#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
......@@ -278,7 +278,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
batadv_send_unicast_skb(skb, neigh_node);
goto out;
dst_unreach:
......
......@@ -87,6 +87,7 @@ static int __init batadv_init(void)
batadv_recv_handler_init();
batadv_v_init();
batadv_iv_init();
batadv_nc_init();
......@@ -159,6 +160,10 @@ int batadv_mesh_init(struct net_device *soft_iface)
INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
ret = batadv_v_mesh_init(bat_priv);
if (ret < 0)
goto err;
ret = batadv_originator_init(bat_priv);
if (ret < 0)
goto err;
......@@ -201,6 +206,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
batadv_purge_outstanding_packets(bat_priv, NULL);
batadv_gw_node_free(bat_priv);
batadv_v_mesh_free(bat_priv);
batadv_nc_mesh_free(bat_priv);
batadv_dat_free(bat_priv);
batadv_bla_free(bat_priv);
......
......@@ -24,12 +24,13 @@
#define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2016.0"
#define BATADV_SOURCE_VERSION "2016.1"
#endif
/* B.A.T.M.A.N. parameters */
#define BATADV_TQ_MAX_VALUE 255
#define BATADV_THROUGHPUT_MAX_VALUE 0xFFFFFFFF
#define BATADV_JITTER 20
/* Time To Live of broadcast messages */
......@@ -60,6 +61,15 @@
#define BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
#define BATADV_TQ_TOTAL_BIDRECT_LIMIT 1
/* B.A.T.M.A.N. V */
#define BATADV_THROUGHPUT_DEFAULT_VALUE 10 /* 1 Mbps */
#define BATADV_ELP_PROBES_PER_NODE 2
#define BATADV_ELP_MIN_PROBE_SIZE 200 /* bytes */
#define BATADV_ELP_PROBE_MAX_TX_DIFF 100 /* milliseconds */
#define BATADV_ELP_MAX_AGE 64
#define BATADV_OGM_MAX_ORIGDIFF 5
#define BATADV_OGM_MAX_AGE 64
/* number of OGMs sent with the last tt diff */
#define BATADV_TT_OGM_APPEND_MAX 3
......
......@@ -575,9 +575,7 @@ batadv_nc_hash_find(struct batadv_hashtable *hash,
*/
static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
{
batadv_send_skb_packet(nc_packet->skb,
nc_packet->neigh_node->if_incoming,
nc_packet->nc_path->next_hop);
batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node);
nc_packet->skb = NULL;
batadv_nc_packet_free(nc_packet);
}
......@@ -1067,11 +1065,11 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
struct batadv_unicast_packet *packet1;
struct batadv_unicast_packet *packet2;
struct batadv_coded_packet *coded_packet;
struct batadv_neigh_node *neigh_tmp, *router_neigh;
struct batadv_neigh_node *router_coding = NULL;
struct batadv_neigh_node *neigh_tmp, *router_neigh, *first_dest;
struct batadv_neigh_node *router_coding = NULL, *second_dest;
struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
u8 *first_source, *first_dest, *second_source, *second_dest;
u8 *first_source, *second_source;
__be32 packet_id1, packet_id2;
size_t count;
bool res = false;
......@@ -1114,9 +1112,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
*/
if (tq_weighted_neigh >= tq_weighted_coding) {
/* Destination from nc_packet is selected for MAC-header */
first_dest = nc_packet->nc_path->next_hop;
first_dest = nc_packet->neigh_node;
first_source = nc_packet->nc_path->prev_hop;
second_dest = neigh_node->addr;
second_dest = neigh_node;
second_source = ethhdr->h_source;
packet1 = (struct batadv_unicast_packet *)nc_packet->skb->data;
packet2 = (struct batadv_unicast_packet *)skb->data;
......@@ -1125,9 +1123,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
skb->data + sizeof(*packet2));
} else {
/* Destination for skb is selected for MAC-header */
first_dest = neigh_node->addr;
first_dest = neigh_node;
first_source = ethhdr->h_source;
second_dest = nc_packet->nc_path->next_hop;
second_dest = nc_packet->neigh_node;
second_source = nc_packet->nc_path->prev_hop;
packet1 = (struct batadv_unicast_packet *)skb->data;
packet2 = (struct batadv_unicast_packet *)nc_packet->skb->data;
......@@ -1169,7 +1167,7 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
coded_packet->first_ttvn = packet1->ttvn;
/* Info about second unicast packet */
ether_addr_copy(coded_packet->second_dest, second_dest);
ether_addr_copy(coded_packet->second_dest, second_dest->addr);
ether_addr_copy(coded_packet->second_source, second_source);
ether_addr_copy(coded_packet->second_orig_dest, packet2->dest);
coded_packet->second_crc = packet_id2;
......@@ -1224,7 +1222,7 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
batadv_nc_packet_free(nc_packet);
/* Send the coded packet and return true */
batadv_send_skb_packet(skb_dest, neigh_node->if_incoming, first_dest);
batadv_send_unicast_skb(skb_dest, first_dest);
res = true;
out:
if (router_neigh)
......
......@@ -26,6 +26,8 @@
* @BATADV_IV_OGM: originator messages for B.A.T.M.A.N. IV
* @BATADV_BCAST: broadcast packets carrying broadcast payload
* @BATADV_CODED: network coded packets
* @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
* @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
*
* @BATADV_UNICAST: unicast packets carrying unicast payload traffic
* @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
......@@ -40,6 +42,8 @@ enum batadv_packettype {
BATADV_IV_OGM = 0x00,
BATADV_BCAST = 0x01,
BATADV_CODED = 0x02,
BATADV_ELP = 0x03,
BATADV_OGM2 = 0x04,
/* 0x40 - 0x7f: unicast */
#define BATADV_UNICAST_MIN 0x40
BATADV_UNICAST = 0x40,
......@@ -234,6 +238,51 @@ struct batadv_ogm_packet {
#define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
/**
* struct batadv_ogm2_packet - ogm2 (routing protocol) packet
* @packet_type: batman-adv packet type, part of the general header
* @version: batman-adv protocol version, part of the general header
* @ttl: time to live for this packet, part of the general header
* @flags: reseved for routing relevant flags - currently always 0
* @seqno: sequence number
* @orig: originator mac address
* @tvlv_len: length of the appended tvlv buffer (in bytes)
* @throughput: the currently flooded path throughput
*/
struct batadv_ogm2_packet {
u8 packet_type;
u8 version;
u8 ttl;
u8 flags;
__be32 seqno;
u8 orig[ETH_ALEN];
__be16 tvlv_len;
__be32 throughput;
/* __packed is not needed as the struct size is divisible by 4,
* and the largest data type in this struct has a size of 4.
*/
};
#define BATADV_OGM2_HLEN sizeof(struct batadv_ogm2_packet)
/**
* struct batadv_elp_packet - elp (neighbor discovery) packet
* @packet_type: batman-adv packet type, part of the general header
* @version: batman-adv protocol version, part of the genereal header
* @orig: originator mac address
* @seqno: sequence number
* @elp_interval: currently used ELP sending interval in ms
*/
struct batadv_elp_packet {
u8 packet_type;
u8 version;
u8 orig[ETH_ALEN];
__be32 seqno;
__be32 elp_interval;
};
#define BATADV_ELP_HLEN sizeof(struct batadv_elp_packet)
/**
* struct batadv_icmp_header - common members among all the ICMP packets
* @packet_type: batman-adv packet type, part of the general header
......
......@@ -49,16 +49,30 @@
static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
/* send out an already prepared packet to the given address via the
* specified batman interface
/**
* batadv_send_skb_packet - send an already prepared packet
* @skb: the packet to send
* @hard_iface: the interface to use to send the broadcast packet
* @dst_addr: the payload destination
*
* Send out an already prepared packet to the given neighbor or broadcast it
* using the specified interface. Either hard_iface or neigh_node must be not
* NULL.
* If neigh_node is NULL, then the packet is broadcasted using hard_iface,
* otherwise it is sent as unicast to the given neighbor.
*
* Return: NET_TX_DROP in case of error or the result of dev_queue_xmit(skb)
* otherwise
*/
int batadv_send_skb_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface,
const u8 *dst_addr)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batadv_priv *bat_priv;
struct ethhdr *ethhdr;
bat_priv = netdev_priv(hard_iface->soft_iface);
if (hard_iface->if_status != BATADV_IF_ACTIVE)
goto send_skb_err;
......@@ -100,6 +114,35 @@ int batadv_send_skb_packet(struct sk_buff *skb,
return NET_XMIT_DROP;
}
int batadv_send_broadcast_skb(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface)
{
return batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
}
int batadv_send_unicast_skb(struct sk_buff *skb,
struct batadv_neigh_node *neigh)
{
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
struct batadv_hardif_neigh_node *hardif_neigh;
#endif
int ret;
ret = batadv_send_skb_packet(skb, neigh->if_incoming, neigh->addr);
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
hardif_neigh = batadv_hardif_neigh_get(neigh->if_incoming, neigh->addr);
if ((hardif_neigh) && (ret != NET_XMIT_DROP))
hardif_neigh->bat_v.last_unicast_tx = jiffies;
if (hardif_neigh)
batadv_hardif_neigh_put(hardif_neigh);
#endif
return ret;
}
/**
* batadv_send_skb_to_orig - Lookup next-hop and transmit skb.
* @skb: Packet to be transmitted.
......@@ -146,8 +189,7 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
if (recv_if && batadv_nc_skb_forward(skb, neigh_node)) {
ret = NET_XMIT_POLICED;
} else {
batadv_send_skb_packet(skb, neigh_node->if_incoming,
neigh_node->addr);
batadv_send_unicast_skb(skb, neigh_node);
ret = NET_XMIT_SUCCESS;
}
......@@ -538,8 +580,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
/* send a copy of the saved skb */
skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
if (skb1)
batadv_send_skb_packet(skb1, hard_iface,
batadv_broadcast_addr);
batadv_send_broadcast_skb(skb1, hard_iface);
}
rcu_read_unlock();
......
......@@ -28,12 +28,16 @@
struct sk_buff;
struct work_struct;
int batadv_send_skb_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface,
const u8 *dst_addr);
int batadv_send_skb_to_orig(struct sk_buff *skb,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if);
int batadv_send_skb_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface,
const u8 *dst_addr);
int batadv_send_broadcast_skb(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface);
int batadv_send_unicast_skb(struct sk_buff *skb,
struct batadv_neigh_node *neigh_node);
void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface);
int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
const struct sk_buff *skb,
......
......@@ -242,6 +242,55 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \
static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \
batadv_store_vlan_##_name)
#define BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, _max, _post_func) \
ssize_t batadv_store_##_name(struct kobject *kobj, \
struct attribute *attr, char *buff, \
size_t count) \
{ \
struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \
struct batadv_hard_iface *hard_iface; \
ssize_t length; \
\
hard_iface = batadv_hardif_get_by_netdev(net_dev); \
if (!hard_iface) \
return 0; \
\
length = __batadv_store_uint_attr(buff, count, _min, _max, \
_post_func, attr, \
&hard_iface->_var, net_dev); \
\
batadv_hardif_put(hard_iface); \
return length; \
}
#define BATADV_ATTR_HIF_SHOW_UINT(_name, _var) \
ssize_t batadv_show_##_name(struct kobject *kobj, \
struct attribute *attr, char *buff) \
{ \
struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \
struct batadv_hard_iface *hard_iface; \
ssize_t length; \
\
hard_iface = batadv_hardif_get_by_netdev(net_dev); \
if (!hard_iface) \
return 0; \
\
length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_var)); \
\
batadv_hardif_put(hard_iface); \
return length; \
}
/* Use this, if you are going to set [name] in hard_iface to an
* unsigned integer value
*/
#define BATADV_ATTR_HIF_UINT(_name, _var, _mode, _min, _max, _post_func)\
static BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, \
_max, _post_func) \
static BATADV_ATTR_HIF_SHOW_UINT(_name, _var) \
static BATADV_ATTR(_name, _mode, batadv_show_##_name, \
batadv_store_##_name)
static int batadv_store_bool_attr(char *buff, size_t count,
struct net_device *net_dev,
const char *attr_name, atomic_t *attr,
......@@ -868,13 +917,94 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj,
return length;
}
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
/**
* batadv_store_throughput_override - parse and store throughput override
* entered by the user
* @kobj: kobject representing the private mesh sysfs directory
* @attr: the batman-adv attribute the user is interacting with
* @buff: the buffer containing the user data
* @count: number of bytes in the buffer
*
* Return: 'count' on success or a negative error code in case of failure
*/
static ssize_t batadv_store_throughput_override(struct kobject *kobj,
struct attribute *attr,
char *buff, size_t count)
{
struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
struct batadv_hard_iface *hard_iface;
u32 tp_override;
u32 old_tp_override;
bool ret;
hard_iface = batadv_hardif_get_by_netdev(net_dev);
if (!hard_iface)
return -EINVAL;
if (buff[count - 1] == '\n')
buff[count - 1] = '\0';
ret = batadv_parse_throughput(net_dev, buff, "throughput_override",
&tp_override);
if (!ret)
return count;
old_tp_override = atomic_read(&hard_iface->bat_v.throughput_override);
if (old_tp_override == tp_override)
goto out;
batadv_info(net_dev, "%s: Changing from: %u.%u MBit to: %u.%u MBit\n",
"throughput_override",
old_tp_override / 10, old_tp_override % 10,
tp_override / 10, tp_override % 10);
atomic_set(&hard_iface->bat_v.throughput_override, tp_override);
out:
batadv_hardif_put(hard_iface);
return count;
}
static ssize_t batadv_show_throughput_override(struct kobject *kobj,
struct attribute *attr,
char *buff)
{
struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
struct batadv_hard_iface *hard_iface;
u32 tp_override;
hard_iface = batadv_hardif_get_by_netdev(net_dev);
if (!hard_iface)
return -EINVAL;
tp_override = atomic_read(&hard_iface->bat_v.throughput_override);
return sprintf(buff, "%u.%u MBit\n", tp_override / 10,
tp_override % 10);
}
#endif
static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface,
batadv_store_mesh_iface);
static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
BATADV_ATTR_HIF_UINT(elp_interval, bat_v.elp_interval, S_IRUGO | S_IWUSR,
2 * BATADV_JITTER, INT_MAX, NULL);
static BATADV_ATTR(throughput_override, S_IRUGO | S_IWUSR,
batadv_show_throughput_override,
batadv_store_throughput_override);
#endif
static struct batadv_attribute *batadv_batman_attrs[] = {
&batadv_attr_mesh_iface,
&batadv_attr_iface_status,
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
&batadv_attr_elp_interval,
&batadv_attr_throughput_override,
#endif
NULL,
};
......
......@@ -22,6 +22,7 @@
#error only "main.h" can be included directly
#endif
#include <linux/average.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/if_ether.h>
......@@ -85,6 +86,36 @@ struct batadv_hard_iface_bat_iv {
atomic_t ogm_seqno;
};
/**
* enum batadv_v_hard_iface_flags - interface flags useful to B.A.T.M.A.N. V
* @BATADV_FULL_DUPLEX: tells if the connection over this link is full-duplex
* @BATADV_WARNING_DEFAULT: tells whether we have warned the user that no
* throughput data is available for this interface and that default values are
* assumed.
*/
enum batadv_v_hard_iface_flags {
BATADV_FULL_DUPLEX = BIT(0),
BATADV_WARNING_DEFAULT = BIT(1),
};
/**
* struct batadv_hard_iface_bat_v - per hard-interface B.A.T.M.A.N. V data
* @elp_interval: time interval between two ELP transmissions
* @elp_seqno: current ELP sequence number
* @elp_skb: base skb containing the ELP message to send
* @elp_wq: workqueue used to schedule ELP transmissions
* @throughput_override: throughput override to disable link auto-detection
* @flags: interface specific flags
*/
struct batadv_hard_iface_bat_v {
atomic_t elp_interval;
atomic_t elp_seqno;
struct sk_buff *elp_skb;
struct delayed_work elp_wq;
atomic_t throughput_override;
u8 flags;
};
/**
* struct batadv_hard_iface - network device known to batman-adv
* @list: list node for batadv_hardif_list
......@@ -99,6 +130,7 @@ struct batadv_hard_iface_bat_iv {
* @soft_iface: the batman-adv interface which uses this network interface
* @rcu: struct used for freeing in an RCU-safe manner
* @bat_iv: per hard-interface B.A.T.M.A.N. IV data
* @bat_v: per hard-interface B.A.T.M.A.N. V data
* @cleanup_work: work queue callback item for hard-interface deinit
* @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
* @neigh_list: list of unique single hop neighbors via this interface
......@@ -116,6 +148,9 @@ struct batadv_hard_iface {
struct net_device *soft_iface;
struct rcu_head rcu;
struct batadv_hard_iface_bat_iv bat_iv;
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
struct batadv_hard_iface_bat_v bat_v;
#endif
struct work_struct cleanup_work;
struct dentry *debug_dir;
struct hlist_head neigh_list;
......@@ -130,6 +165,7 @@ struct batadv_hard_iface {
* @router: router that should be used to reach this originator
* @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @last_seqno_forwarded: seqno of the OGM which was forwarded last
* @batman_seqno_reset: time when the batman seqno window was reset
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
......@@ -140,6 +176,7 @@ struct batadv_orig_ifinfo {
struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
u32 last_real_seqno;
u8 last_ttl;
u32 last_seqno_forwarded;
unsigned long batman_seqno_reset;
struct kref refcount;
struct rcu_head rcu;
......@@ -346,12 +383,32 @@ struct batadv_gw_node {
struct rcu_head rcu;
};
DECLARE_EWMA(throughput, 1024, 8)
/**
* struct batadv_hardif_neigh_node_bat_v - B.A.T.M.A.N. V private neighbor
* information
* @throughput: ewma link throughput towards this neighbor
* @elp_interval: time interval between two ELP transmissions
* @elp_latest_seqno: latest and best known ELP sequence number
* @last_unicast_tx: when the last unicast packet has been sent to this neighbor
* @metric_work: work queue callback item for metric update
*/
struct batadv_hardif_neigh_node_bat_v {
struct ewma_throughput throughput;
u32 elp_interval;
u32 elp_latest_seqno;
unsigned long last_unicast_tx;
struct work_struct metric_work;
};
/**
* struct batadv_hardif_neigh_node - unique neighbor per hard-interface
* @list: list node for batadv_hard_iface::neigh_list
* @addr: the MAC address of the neighboring interface
* @if_incoming: pointer to incoming hard-interface
* @last_seen: when last packet via this neighbor was received
* @bat_v: B.A.T.M.A.N. V private data
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in a RCU-safe manner
*/
......@@ -360,6 +417,9 @@ struct batadv_hardif_neigh_node {
u8 addr[ETH_ALEN];
struct batadv_hard_iface *if_incoming;
unsigned long last_seen;
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
struct batadv_hardif_neigh_node_bat_v bat_v;
#endif
struct kref refcount;
struct rcu_head rcu;
};
......@@ -406,11 +466,23 @@ struct batadv_neigh_ifinfo_bat_iv {
u8 real_packet_count;
};
/**
* struct batadv_neigh_ifinfo_bat_v - neighbor information per outgoing
* interface for B.A.T.M.A.N. V
* @throughput: last throughput metric received from originator via this neigh
* @last_seqno: last sequence number known for this neighbor
*/
struct batadv_neigh_ifinfo_bat_v {
u32 throughput;
u32 last_seqno;
};
/**
* struct batadv_neigh_ifinfo - neighbor information per outgoing interface
* @list: list node for batadv_neigh_node::ifinfo_list
* @if_outgoing: pointer to outgoing hard-interface
* @bat_iv: B.A.T.M.A.N. IV private structure
* @bat_v: B.A.T.M.A.N. V private data
* @last_ttl: last received ttl from this neigh node
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in a RCU-safe manner
......@@ -419,6 +491,9 @@ struct batadv_neigh_ifinfo {
struct hlist_node list;
struct batadv_hard_iface *if_outgoing;
struct batadv_neigh_ifinfo_bat_iv bat_iv;
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
struct batadv_neigh_ifinfo_bat_v bat_v;
#endif
u8 last_ttl;
struct kref refcount;
struct rcu_head rcu;
......@@ -750,6 +825,20 @@ struct batadv_softif_vlan {
struct rcu_head rcu;
};
/**
* struct batadv_priv_bat_v - B.A.T.M.A.N. V per soft-interface private data
* @ogm_buff: buffer holding the OGM packet
* @ogm_buff_len: length of the OGM packet buffer
* @ogm_seqno: OGM sequence number - used to identify each OGM
* @ogm_wq: workqueue used to schedule OGM transmissions
*/
struct batadv_priv_bat_v {
unsigned char *ogm_buff;
int ogm_buff_len;
atomic_t ogm_seqno;
struct delayed_work ogm_wq;
};
/**
* struct batadv_priv - per mesh interface data
* @mesh_state: current status of the mesh (inactive/active/deactivating)
......@@ -804,6 +893,7 @@ struct batadv_softif_vlan {
* @mcast: multicast data
* @network_coding: bool indicating whether network coding is enabled
* @nc: network coding data
* @bat_v: B.A.T.M.A.N. V per soft-interface private data
*/
struct batadv_priv {
atomic_t mesh_state;
......@@ -869,6 +959,9 @@ struct batadv_priv {
atomic_t network_coding;
struct batadv_priv_nc nc;
#endif /* CONFIG_BATMAN_ADV_NC */
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
struct batadv_priv_bat_v bat_v;
#endif
};
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册