The following commit has been merged in the master branch:
commit e300d314664ef6746e697d5b581f85114ab1f843
Author: Linus Lüssing <linus.luessing(a)web.de>
Date: Wed Jul 3 10:40:00 2013 +0200
batman-adv: refine API calls for unicast transmissions of SKBs
With this patch the functions batadv_send_skb_unicast() and
batadv_send_skb_unicast_4addr() are further refined into
batadv_send_skb_via_tt(), batadv_send_skb_via_tt_4addr() and
batadv_send_skb_via_gw(). This way we avoid any "guessing" about where to send
a packet in the unicast forwarding methods and let the callers decide.
This is going to be useful for the upcoming multicast related patches in
particular.
Further, the return values were polished a little to use the more
appropriate NET_XMIT_* defines.
Signed-off-by: Linus Lüssing <linus.luessing(a)web.de>
Acked-by: Antonio Quartulli <antonio(a)meshcoding.com>
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
Signed-off-by: Antonio Quartulli <antonio(a)meshcoding.com>
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 47dbe9a..6c8c393 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -1037,13 +1037,13 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
* that a node not using the 4addr packet format doesn't support it.
*/
if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
- err = batadv_send_skb_unicast_4addr(bat_priv, skb_new,
- BATADV_P_DAT_CACHE_REPLY,
- vid);
+ err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
+ BATADV_P_DAT_CACHE_REPLY,
+ vid);
else
- err = batadv_send_skb_unicast(bat_priv, skb_new, vid);
+ err = batadv_send_skb_via_tt(bat_priv, skb_new, vid);
- if (!err) {
+ if (err != NET_XMIT_DROP) {
batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
ret = true;
}
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index acaa7ff..c83be5e 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -234,35 +234,31 @@ out:
}
/**
- * batadv_send_generic_unicast_skb - send an skb as unicast
+ * batadv_send_skb_unicast - encapsulate and send an skb via unicast
* @bat_priv: the bat priv with all the soft interface information
* @skb: payload to send
* @packet_type: the batman unicast packet type to use
* @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
* 4addr packets)
+ * @orig_node: the originator to send the packet to
* @vid: the vid to be used to search the translation table
*
- * Returns 1 in case of error or 0 otherwise.
+ * Wrap the given skb into a batman-adv unicast or unicast-4addr header
+ * depending on whether BATADV_UNICAST or BATADV_UNICAST_4ADDR was supplied
+ * as packet_type. Then send this frame to the given orig_node and release a
+ * reference to this orig_node.
+ *
+ * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
-int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
- struct sk_buff *skb, int packet_type,
- int packet_subtype,
- unsigned short vid)
+static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
+ struct sk_buff *skb, int packet_type,
+ int packet_subtype,
+ struct batadv_orig_node *orig_node,
+ unsigned short vid)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batadv_unicast_packet *unicast_packet;
- struct batadv_orig_node *orig_node;
- int ret = NET_RX_DROP;
-
- /* get routing information */
- if (is_multicast_ether_addr(ethhdr->h_dest))
- orig_node = batadv_gw_get_selected_orig(bat_priv);
- else
- /* check for tt host - increases orig_node refcount.
- * returns NULL in case of AP isolation
- */
- orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
- ethhdr->h_dest, vid);
+ int ret = NET_XMIT_DROP;
if (!orig_node)
goto out;
@@ -296,16 +292,67 @@ int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
unicast_packet->ttvn = unicast_packet->ttvn - 1;
if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP)
- ret = 0;
+ ret = NET_XMIT_SUCCESS;
out:
if (orig_node)
batadv_orig_node_free_ref(orig_node);
- if (ret == NET_RX_DROP)
+ if (ret == NET_XMIT_DROP)
kfree_skb(skb);
return ret;
}
+/**
+ * batadv_send_skb_via_tt_generic - send an skb via TT lookup
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: payload to send
+ * @packet_type: the batman unicast packet type to use
+ * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
+ * 4addr packets)
+ * @vid: the vid to be used to search the translation table
+ *
+ * Look up the recipient node for the destination address in the ethernet
+ * header via the translation table. Wrap the given skb into a batman-adv
+ * unicast or unicast-4addr header depending on whether BATADV_UNICAST or
+ * BATADV_UNICAST_4ADDR was supplied as packet_type. Then send this frame
+ * to the according destination node.
+ *
+ * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
+ */
+int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
+ struct sk_buff *skb, int packet_type,
+ int packet_subtype, unsigned short vid)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+ struct batadv_orig_node *orig_node;
+
+ orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
+ ethhdr->h_dest, vid);
+ return batadv_send_skb_unicast(bat_priv, skb, packet_type,
+ packet_subtype, orig_node, vid);
+}
+
+/**
+ * batadv_send_skb_via_gw - send an skb via gateway lookup
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: payload to send
+ * @vid: the vid to be used to search the translation table
+ *
+ * Look up the currently selected gateway. Wrap the given skb into a batman-adv
+ * unicast header and send this frame to this gateway node.
+ *
+ * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
+ */
+int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ unsigned short vid)
+{
+ struct batadv_orig_node *orig_node;
+
+ orig_node = batadv_gw_get_selected_orig(bat_priv);
+ return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0,
+ orig_node, vid);
+}
+
void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index c030cb7..aa2e253 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -38,45 +38,54 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
int packet_subtype);
-int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
- struct sk_buff *skb, int packet_type,
- int packet_subtype,
- unsigned short vid);
+int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
+ struct sk_buff *skb, int packet_type,
+ int packet_subtype, unsigned short vid);
+int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ unsigned short vid);
/**
- * batadv_send_unicast_skb - send the skb encapsulated in a unicast packet
+ * batadv_send_skb_via_tt - send an skb via TT lookup
* @bat_priv: the bat priv with all the soft interface information
* @skb: the payload to send
* @vid: the vid to be used to search the translation table
*
- * Returns 1 in case of error or 0 otherwise.
+ * Look up the recipient node for the destination address in the ethernet
+ * header via the translation table. Wrap the given skb into a batman-adv
+ * unicast header. Then send this frame to the according destination node.
+ *
+ * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
-static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
- struct sk_buff *skb,
- unsigned short vid)
+static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
+ struct sk_buff *skb,
+ unsigned short vid)
{
- return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST,
- 0, vid);
+ return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0,
+ vid);
}
/**
- * batadv_send_4addr_unicast_skb - send the skb encapsulated in a unicast 4addr
- * packet
+ * batadv_send_skb_via_tt_4addr - send an skb via TT lookup
* @bat_priv: the bat priv with all the soft interface information
* @skb: the payload to send
* @packet_subtype: the unicast 4addr packet subtype to use
* @vid: the vid to be used to search the translation table
*
- * Returns 1 in case of error or 0 otherwise.
+ * Look up the recipient node for the destination address in the ethernet
+ * header via the translation table. Wrap the given skb into a batman-adv
+ * unicast-4addr header. Then send this frame to the according destination
+ * node.
+ *
+ * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
-static inline int batadv_send_skb_unicast_4addr(struct batadv_priv *bat_priv,
- struct sk_buff *skb,
- int packet_subtype,
- unsigned short vid)
+static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv,
+ struct sk_buff *skb,
+ int packet_subtype,
+ unsigned short vid)
{
- return batadv_send_skb_generic_unicast(bat_priv, skb,
- BATADV_UNICAST_4ADDR,
- packet_subtype, vid);
+ return batadv_send_skb_via_tt_generic(bat_priv, skb,
+ BATADV_UNICAST_4ADDR,
+ packet_subtype, vid);
}
#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index baa74b9..e70f530 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -298,8 +298,12 @@ static int batadv_interface_tx(struct sk_buff *skb,
batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
- ret = batadv_send_skb_unicast(bat_priv, skb, vid);
- if (ret != 0)
+ if (is_multicast_ether_addr(ethhdr->h_dest))
+ ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
+ else
+ ret = batadv_send_skb_via_tt(bat_priv, skb, vid);
+
+ if (ret == NET_XMIT_DROP)
goto dropped_freed;
}
--
LinuxNextTracking
The following commit has been merged in the master branch:
commit e75de4fa41d810113cf81f658a56e3972c7c12b4
Author: Antonio Quartulli <antonio(a)open-mesh.com>
Date: Wed Jul 10 16:52:04 2013 +0200
batman-adv: remove bogus comment
this comment refers to the old batmand codebase and does
not make sense anymore. Remove it
Signed-off-by: Antonio Quartulli <antonio(a)open-mesh.com>
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 4ed410f..20fa053 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -221,11 +221,6 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
struct batadv_neigh_node *router = NULL;
char gw_addr[18] = { '\0' };
- /* The batman daemon checks here if we already passed a full originator
- * cycle in order to make sure we don't choose the first gateway we
- * hear about. This check is based on the daemon's uptime which we
- * don't have.
- */
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
goto out;
--
LinuxNextTracking
The following commit has been merged in the master branch:
commit a70a9aa990bdf24039cb4167993bcc5a0f9cbb18
Author: Antonio Quartulli <antonio(a)open-mesh.com>
Date: Tue Jul 30 22:16:24 2013 +0200
batman-adv: lock around TT operations to avoid sending inconsistent data
A TT response may be prepared and sent while the local or
global translation table is getting updated.
The worst case is when one of the tables is accessed after
its content has been recently updated but the metadata
(TTVN/CRC) has not yet. In this case the reader will get a
table content which does not match the TTVN/CRC.
This will lead to an inconsistent state and so to a TT
recovery.
To avoid entering this situation, put a lock around those TT
operations recomputing the metadata and around the TT
Response creation (the latter is the only reader that
accesses the metadata together with the table).
Signed-off-by: Antonio Quartulli <antonio(a)open-mesh.com>
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 2207551..3159a14 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -110,6 +110,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->tt.req_list_lock);
spin_lock_init(&bat_priv->tt.roam_list_lock);
spin_lock_init(&bat_priv->tt.last_changeset_lock);
+ spin_lock_init(&bat_priv->tt.commit_lock);
spin_lock_init(&bat_priv->gw.list_lock);
spin_lock_init(&bat_priv->tvlv.container_list_lock);
spin_lock_init(&bat_priv->tvlv.handler_list_lock);
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index a591dc5..867778e 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -239,6 +239,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
spin_lock_init(&orig_node->tt_buff_lock);
+ spin_lock_init(&orig_node->tt_lock);
batadv_nc_init_orig(orig_node);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 58794c4..00f4faa 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -2019,6 +2019,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
req_src, tt_data->ttvn,
(tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
+ spin_lock_bh(&bat_priv->tt.commit_lock);
my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
req_ttvn = tt_data->ttvn;
@@ -2091,6 +2092,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
unlock:
spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
out:
+ spin_unlock_bh(&bat_priv->tt.commit_lock);
if (orig_node)
batadv_orig_node_free_ref(orig_node);
if (primary_if)
@@ -2259,6 +2261,8 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
if (!orig_node)
goto out;
+ spin_lock_bh(&orig_node->tt_lock);
+
if (tt_data->flags & BATADV_TT_FULL_TABLE) {
batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries);
} else {
@@ -2267,6 +2271,11 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
tt_data->ttvn, tt_change);
}
+ /* Recalculate the CRC for this orig_node and store it */
+ orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
+
+ spin_unlock_bh(&orig_node->tt_lock);
+
/* Delete the tt_req_node from pending tt_requests list */
spin_lock_bh(&bat_priv->tt.req_list_lock);
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
@@ -2276,9 +2285,6 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
kfree(node);
}
spin_unlock_bh(&bat_priv->tt.req_list_lock);
-
- /* Recalculate the CRC for this orig_node and store it */
- orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
out:
if (orig_node)
batadv_orig_node_free_ref(orig_node);
@@ -2532,10 +2538,12 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
{
uint16_t changed_num = 0;
+ spin_lock_bh(&bat_priv->tt.commit_lock);
+
if (atomic_read(&bat_priv->tt.local_changes) < 1) {
if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
batadv_tt_tvlv_container_update(bat_priv);
- return;
+ goto out;
}
changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash,
@@ -2555,6 +2563,9 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
/* reset the sending counter */
atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
batadv_tt_tvlv_container_update(bat_priv);
+
+out:
+ spin_unlock_bh(&bat_priv->tt.commit_lock);
}
bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
@@ -2631,6 +2642,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
goto request_table;
}
+ spin_lock_bh(&orig_node->tt_lock);
+
tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
ttvn, tt_change);
@@ -2641,6 +2654,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
*/
orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
+ spin_unlock_bh(&orig_node->tt_lock);
+
/* The ttvn alone is not enough to guarantee consistency
* because a single value could represent different states
* (due to the wrap around). Thus a node has to check whether
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 04a0da6..bd95d61 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -128,6 +128,10 @@ struct batadv_frag_list_entry {
* @tt_size: number of global TT entries announced by the orig node
* @tt_initialised: bool keeping track of whether or not this node have received
* any translation table information from the orig node yet
+ * @tt_lock: prevents from updating the table while reading it. Table update is
+ * made up by two operations (data structure update and metdata -CRC/TTVN-
+ * recalculation) and they have to be executed atomically in order to avoid
+ * another thread to read the table/metadata between those.
* @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @bcast_bits: bitfield containing the info which payload broadcast originated
@@ -171,6 +175,8 @@ struct batadv_orig_node {
spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */
atomic_t tt_size;
bool tt_initialised;
+ /* prevents from changing the table while reading it */
+ spinlock_t tt_lock;
uint32_t last_real_seqno;
uint8_t last_ttl;
DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
@@ -388,6 +394,11 @@ enum batadv_counters {
* @last_changeset: last tt changeset this host has generated
* @last_changeset_len: length of last tt changeset this host has generated
* @last_changeset_lock: lock protecting last_changeset & last_changeset_len
+ * @commit_lock: prevents from executing a local TT commit while reading the
+ * local table. The local TT commit is made up by two operations (data
+ * structure update and metdata -CRC/TTVN- recalculation) and they have to be
+ * executed atomically in order to avoid another thread to read the
+ * table/metadata between those.
* @work: work queue callback item for translation table purging
*/
struct batadv_priv_tt {
@@ -408,6 +419,8 @@ struct batadv_priv_tt {
int16_t last_changeset_len;
/* protects last_changeset & last_changeset_len */
spinlock_t last_changeset_lock;
+ /* prevents from executing a commit while reading the table */
+ spinlock_t commit_lock;
struct delayed_work work;
};
--
LinuxNextTracking
The following commit has been merged in the master branch:
commit bbb877ed777236669ed14b5957ae72117f3b3129
Author: Antonio Quartulli <antonio(a)open-mesh.com>
Date: Tue Jun 4 12:11:42 2013 +0200
batman-adv: make the GW module correctly talk to the new VLAN-TT
The gateway code is now adapted in order to correctly
interact with the Translation Table component by using the
vlan ID
Signed-off-by: Antonio Quartulli <antonio(a)open-mesh.com>
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index a920946..4ed410f 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -726,7 +726,20 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
return true;
}
-/* this call might reallocate skb data */
+/**
+ * batadv_gw_out_of_range - check if the dhcp request destination is the best gw
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the outgoing packet
+ *
+ * Check if the skb is a DHCP request and if it is sent to the current best GW
+ * server. Due to topology changes it may be the case that the GW server
+ * previously selected is not the best one anymore.
+ *
+ * Returns true if the packet destination is unicast and it is not the best gw,
+ * false otherwise.
+ *
+ * This call might reallocate skb data.
+ */
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
@@ -737,6 +750,9 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
bool ret, out_of_range = false;
unsigned int header_len = 0;
uint8_t curr_tq_avg;
+ unsigned short vid;
+
+ vid = batadv_get_vid(skb, 0);
ret = batadv_gw_is_dhcp_target(skb, &header_len);
if (!ret)
@@ -744,8 +760,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
ethhdr = (struct ethhdr *)skb->data;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
- ethhdr->h_dest,
- BATADV_NO_FLAGS);
+ ethhdr->h_dest, vid);
if (!orig_dst_node)
goto out;
--
LinuxNextTracking
The following commit has been merged in the master branch:
commit 5d2c05b213377694a2aa8ce1ed9b23f7c39b0569
Author: Antonio Quartulli <antonio(a)open-mesh.com>
Date: Tue Jul 2 11:04:34 2013 +0200
batman-adv: add per VLAN interface attribute framework
Since batman-adv is now fully VLAN-aware, a proper framework
able to handle per-vlan-interface attributes is needed.
Those attributes will affect the associated VLAN interface
only, rather than the real soft_iface (which would result
in every vlan interface having the same attribute
configuration).
To make the code simpler and easier to extend, attributes
associated to the standalone soft_iface are now treated
like belonging to yet another vlan having a special vid.
This vid is different from the others because it is made up
by all zeros and the VLAN_HAS_TAG bit is not set.
Signed-off-by: Antonio Quartulli <antonio(a)open-mesh.com>
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index d564af2..c5f871f 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -643,6 +643,8 @@ static int batadv_hard_if_event(struct notifier_block *this,
if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
batadv_sysfs_add_meshif(net_dev);
+ bat_priv = netdev_priv(net_dev);
+ batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS);
return NOTIFY_DONE;
}
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 80f60d1..2207551 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -113,6 +113,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->gw.list_lock);
spin_lock_init(&bat_priv->tvlv.container_list_lock);
spin_lock_init(&bat_priv->tvlv.handler_list_lock);
+ spin_lock_init(&bat_priv->softif_vlan_list_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
@@ -122,6 +123,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
INIT_LIST_HEAD(&bat_priv->tt.roam_list);
INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
+ INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
ret = batadv_originator_init(bat_priv);
if (ret < 0)
@@ -131,9 +133,6 @@ int batadv_mesh_init(struct net_device *soft_iface)
if (ret < 0)
goto err;
- batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
- BATADV_NO_FLAGS, BATADV_NULL_IFINDEX);
-
ret = batadv_bla_init(bat_priv);
if (ret < 0)
goto err;
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 279e91d..936b83b 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -393,6 +393,166 @@ out:
return;
}
+/**
+ * batadv_softif_vlan_free_ref - decrease the vlan object refcounter and
+ * possibly free it
+ * @softif_vlan: the vlan object to release
+ */
+static void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan)
+{
+ if (atomic_dec_and_test(&softif_vlan->refcount))
+ kfree_rcu(softif_vlan, rcu);
+}
+
+/**
+ * batadv_softif_vlan_get - get the vlan object for a specific vid
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the identifier of the vlan object to retrieve
+ *
+ * Returns the private data of the vlan matching the vid passed as argument or
+ * NULL otherwise. The refcounter of the returned object is incremented by 1.
+ */
+static struct batadv_softif_vlan *
+batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid)
+{
+ struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
+ if (vlan_tmp->vid != vid)
+ continue;
+
+ if (!atomic_inc_not_zero(&vlan_tmp->refcount))
+ continue;
+
+ vlan = vlan_tmp;
+ break;
+ }
+ rcu_read_unlock();
+
+ return vlan;
+}
+
+/**
+ * batadv_create_vlan - allocate the needed resources for a new vlan
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the VLAN identifier
+ *
+ * Returns 0 on success, a negative error otherwise.
+ */
+int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
+{
+ struct batadv_softif_vlan *vlan;
+
+ vlan = batadv_softif_vlan_get(bat_priv, vid);
+ if (vlan) {
+ batadv_softif_vlan_free_ref(vlan);
+ return -EEXIST;
+ }
+
+ vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
+ if (!vlan)
+ return -ENOMEM;
+
+ vlan->vid = vid;
+ atomic_set(&vlan->refcount, 1);
+
+ /* add a new TT local entry. This one will be marked with the NOPURGE
+ * flag
+ */
+ batadv_tt_local_add(bat_priv->soft_iface,
+ bat_priv->soft_iface->dev_addr, vid,
+ BATADV_NULL_IFINDEX);
+
+ spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+ hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
+ spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
+
+ return 0;
+}
+
+/**
+ * batadv_softif_destroy_vlan - remove and destroy a softif_vlan object
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vlan: the object to remove
+ */
+static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
+ struct batadv_softif_vlan *vlan)
+{
+ spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+ hlist_del_rcu(&vlan->list);
+ spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
+
+ /* explicitly remove the associated TT local entry because it is marked
+ * with the NOPURGE flag
+ */
+ batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr,
+ vlan->vid, "vlan interface destroyed", false);
+
+ batadv_softif_vlan_free_ref(vlan);
+}
+
+/**
+ * batadv_interface_add_vid - ndo_add_vid API implementation
+ * @dev: the netdev of the mesh interface
+ * @vid: identifier of the new vlan
+ *
+ * Set up all the internal structures for handling the new vlan on top of the
+ * mesh interface
+ *
+ * Returns 0 on success or a negative error code in case of failure.
+ */
+static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
+ unsigned short vid)
+{
+ struct batadv_priv *bat_priv = netdev_priv(dev);
+
+ /* only 802.1Q vlans are supported.
+ * batman-adv does not know how to handle other types
+ */
+ if (proto != htons(ETH_P_8021Q))
+ return -EINVAL;
+
+ vid |= BATADV_VLAN_HAS_TAG;
+
+ return batadv_softif_create_vlan(bat_priv, vid);
+}
+
+/**
+ * batadv_interface_kill_vid - ndo_kill_vid API implementation
+ * @dev: the netdev of the mesh interface
+ * @vid: identifier of the deleted vlan
+ *
+ * Destroy all the internal structures used to handle the vlan identified by vid
+ * on top of the mesh interface
+ *
+ * Returns 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q
+ * or -ENOENT if the specified vlan id wasn't registered.
+ */
+static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
+ unsigned short vid)
+{
+ struct batadv_priv *bat_priv = netdev_priv(dev);
+ struct batadv_softif_vlan *vlan;
+
+ /* only 802.1Q vlans are supported. batman-adv does not know how to
+ * handle other types
+ */
+ if (proto != htons(ETH_P_8021Q))
+ return -EINVAL;
+
+ vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG);
+ if (!vlan)
+ return -ENOENT;
+
+ batadv_softif_destroy_vlan(bat_priv, vlan);
+
+ /* finally free the vlan object */
+ batadv_softif_vlan_free_ref(vlan);
+
+ return 0;
+}
+
/* batman-adv network devices have devices nesting below it and are a special
* "super class" of normal network devices; split their locks off into a
* separate class since they always nest.
@@ -432,6 +592,7 @@ static void batadv_set_lockdep_class(struct net_device *dev)
*/
static void batadv_softif_destroy_finish(struct work_struct *work)
{
+ struct batadv_softif_vlan *vlan;
struct batadv_priv *bat_priv;
struct net_device *soft_iface;
@@ -439,6 +600,13 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
cleanup_work);
soft_iface = bat_priv->soft_iface;
+ /* destroy the "untagged" VLAN */
+ vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
+ if (vlan) {
+ batadv_softif_destroy_vlan(bat_priv, vlan);
+ batadv_softif_vlan_free_ref(vlan);
+ }
+
batadv_sysfs_del_meshif(soft_iface);
rtnl_lock();
@@ -594,6 +762,8 @@ static const struct net_device_ops batadv_netdev_ops = {
.ndo_open = batadv_interface_open,
.ndo_stop = batadv_interface_release,
.ndo_get_stats = batadv_interface_stats,
+ .ndo_vlan_rx_add_vid = batadv_interface_add_vid,
+ .ndo_vlan_rx_kill_vid = batadv_interface_kill_vid,
.ndo_set_mac_address = batadv_interface_set_mac_addr,
.ndo_change_mtu = batadv_interface_change_mtu,
.ndo_set_rx_mode = batadv_interface_set_rx_mode,
@@ -633,6 +803,7 @@ static void batadv_softif_init_early(struct net_device *dev)
dev->netdev_ops = &batadv_netdev_ops;
dev->destructor = batadv_softif_free;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
dev->tx_queue_len = 0;
/* can't call min_mtu, because the needed variables
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
index 2f2472c..16d9be6 100644
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@ -28,5 +28,6 @@ struct net_device *batadv_softif_create(const char *name);
void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
int batadv_softif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops;
+int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 6954a5d..e5fecd4 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -531,6 +531,22 @@ struct batadv_priv_nc {
};
/**
+ * struct batadv_softif_vlan - per VLAN attributes set
+ * @vid: VLAN identifier
+ * @kobj: kobject for sysfs vlan subdirectory
+ * @list: list node for bat_priv::softif_vlan_list
+ * @refcount: number of context where this object is currently in use
+ * @rcu: struct used for freeing in a RCU-safe manner
+ */
+struct batadv_softif_vlan {
+ unsigned short vid;
+ struct kobject *kobj;
+ struct hlist_node list;
+ atomic_t refcount;
+ struct rcu_head rcu;
+};
+
+/**
* struct batadv_priv - per mesh interface data
* @mesh_state: current status of the mesh (inactive/active/deactivating)
* @soft_iface: net device which holds this struct as private data
@@ -566,6 +582,9 @@ struct batadv_priv_nc {
* @primary_if: one of the hard interfaces assigned to this mesh interface
* becomes the primary interface
* @bat_algo_ops: routing algorithm used by this mesh interface
+ * @softif_vlan_list: a list of softif_vlan structs, one per VLAN created on top
+ * of the mesh interface represented by this object
+ * @softif_vlan_list_lock: lock protecting softif_vlan_list
* @bla: bridge loope avoidance data
* @debug_log: holding debug logging relevant data
* @gw: gateway data
@@ -613,6 +632,8 @@ struct batadv_priv {
struct work_struct cleanup_work;
struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */
struct batadv_algo_ops *bat_algo_ops;
+ struct hlist_head softif_vlan_list;
+ spinlock_t softif_vlan_list_lock; /* protects softif_vlan_list */
#ifdef CONFIG_BATMAN_ADV_BLA
struct batadv_priv_bla bla;
#endif
--
LinuxNextTracking
The following commit has been merged in the master branch:
commit 0ffa9e8d86d665f0f29343e45ecc09e2772ac646
Author: Antonio Quartulli <antonio(a)open-mesh.com>
Date: Tue Jun 4 12:11:40 2013 +0200
batman-adv: use vid when computing local and global TT CRC
now that each TT entry is characterised by a VLAN ID, the
latter has to be taken into consideration when computing the
local/global table CRC as it would be theoretically possible
to have the same client in two different VLANs
Signed-off-by: Antonio Quartulli <antonio(a)open-mesh.com>
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 63adb97..c8fc303 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1506,6 +1506,24 @@ out:
* batadv_tt_global_crc - calculates the checksum of the local table belonging
* to the given orig_node
* @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: originator for which the CRC should be computed
+ *
+ * This function computes the checksum for the global table corresponding to a
+ * specific originator. In particular, the checksum is computed as follows: For
+ * each client connected to the originator the CRC32C of the MAC address and the
+ * VID is computed and then all the CRC32Cs of the various clients are xor'ed
+ * together.
+ *
+ * The idea behind is that CRC32C should be used as much as possible in order to
+ * produce a unique hash of the table, but since the order which is used to feed
+ * the CRC32C function affects the result and since every node in the network
+ * probably sorts the clients differently, the hash function cannot be directly
+ * computed over the entire table. Hence the CRC32C is used only on
+ * the single client entry, while all the results are then xor'ed together
+ * because the XOR operation can combine them all while trying to reduce the
+ * noise as much as possible.
+ *
+ * Returns the checksum of the global table of a given originator.
*/
static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
@@ -1514,7 +1532,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
struct batadv_tt_common_entry *tt_common;
struct batadv_tt_global_entry *tt_global;
struct hlist_head *head;
- uint32_t i, crc = 0;
+ uint32_t i, crc_tmp, crc = 0;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
@@ -1545,7 +1563,9 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
orig_node))
continue;
- crc ^= crc32c(0, tt_common->addr, ETH_ALEN);
+ crc_tmp = crc32c(0, &tt_common->vid,
+ sizeof(tt_common->vid));
+ crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
}
rcu_read_unlock();
}
@@ -1556,13 +1576,18 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
/**
* batadv_tt_local_crc - calculates the checksum of the local table
* @bat_priv: the bat priv with all the soft interface information
+ *
+ * For details about the computation, please refer to the documentation for
+ * batadv_tt_global_crc().
+ *
+ * Returns the checksum of the local table
*/
static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
{
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct batadv_tt_common_entry *tt_common;
struct hlist_head *head;
- uint32_t i, crc = 0;
+ uint32_t i, crc_tmp, crc = 0;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
@@ -1575,7 +1600,9 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
if (tt_common->flags & BATADV_TT_CLIENT_NEW)
continue;
- crc ^= crc32c(0, tt_common->addr, ETH_ALEN);
+ crc_tmp = crc32c(0, &tt_common->vid,
+ sizeof(tt_common->vid));
+ crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
}
rcu_read_unlock();
}
--
LinuxNextTracking