Hello people,
with this patchset I want to introduce a new feature in the TT code which makes it VLAN aware. This means that now clients belonging to different VLANs created on top of a generic bat0 are treated differently.
This change gives the possibility to: - enable AP isolation only on a selected VLAN rather than on all the traffic - make DAT work correctly when the same IP subnet is used on different VLANs - leave the possibility to future developers to implement more VLAN specific attributes
This code is based on top of hundeboll/fragmentation.
Cheers,
Antonio Quartulli (7): batman-adv: add the VLAN ID attribute to the TT entry batman-adv: use vid when computing local and global TT CRC batman-adv: print the VID together with the TT entries batman-adv: make the GW module correctly talk to the new VLAN-TT batman-adv: make the Distributed ARP Table vlan aware batman-adv: add per VLAN interface attribute framework batman-adv: make the AP isolation attribute VLAN specific
distributed-arp-table.c | 129 ++++++++++++------ gateway_client.c | 10 +- main.c | 46 ++++++- main.h | 11 +- packet.h | 12 ++ routing.c | 27 +++- send.c | 8 +- send.h | 16 ++- soft-interface.c | 99 ++++++++++++-- sysfs.c | 140 ++++++++++++++++++++ sysfs.h | 10 ++ translation-table.c | 343 +++++++++++++++++++++++++++++++++++------------- translation-table.h | 25 ++-- types.h | 27 ++++ 14 files changed, 732 insertions(+), 171 deletions(-)
From: Antonio Quartulli antonio@open-mesh.com
To make the translation table code VLAN-aware, each entry must carry the VLAN ID which it belongs to. This patch adds such attribute to the related TT structures.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- distributed-arp-table.c | 8 +- gateway_client.c | 3 +- main.c | 2 +- main.h | 8 -- packet.h | 12 +++ routing.c | 27 ++++-- send.c | 8 +- send.h | 16 ++-- soft-interface.c | 18 ++-- translation-table.c | 237 +++++++++++++++++++++++++++++++++++++----------- translation-table.h | 23 +++-- types.h | 2 + 12 files changed, 266 insertions(+), 98 deletions(-)
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index c489ed1..2123ab2 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -977,9 +977,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, */ if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) err = batadv_send_skb_4addr_unicast(bat_priv, skb_new, - BATADV_P_DAT_CACHE_REPLY); + BATADV_P_DAT_CACHE_REPLY, + BATADV_NO_FLAGS); else - err = batadv_send_skb_unicast(bat_priv, skb_new); + err = batadv_send_skb_unicast(bat_priv, skb_new, + BATADV_NO_FLAGS);
if (!err) { batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); @@ -1067,7 +1069,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, /* if this REPLY is directed to a client of mine, let's deliver the * packet to the interface */ - ret = !batadv_is_my_client(bat_priv, hw_dst); + ret = !batadv_is_my_client(bat_priv, hw_dst, BATADV_NO_FLAGS); out: if (ret) kfree_skb(skb); diff --git a/gateway_client.c b/gateway_client.c index f105219..8812965 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -649,7 +649,8 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, goto out;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, - ethhdr->h_dest); + ethhdr->h_dest, + BATADV_NO_FLAGS); if (!orig_dst_node) goto out;
diff --git a/main.c b/main.c index 392c4d2..689cf49 100644 --- a/main.c +++ b/main.c @@ -127,7 +127,7 @@ int batadv_mesh_init(struct net_device *soft_iface) goto err;
batadv_tt_local_add(soft_iface, soft_iface->dev_addr, - BATADV_NULL_IFINDEX); + BATADV_NULL_IFINDEX, BATADV_NO_FLAGS);
ret = batadv_bla_init(bat_priv); if (ret < 0) diff --git a/main.h b/main.h index 0417675..a60ab1b 100644 --- a/main.h +++ b/main.h @@ -168,14 +168,6 @@ enum batadv_uev_type {
#include "types.h"
-/** - * batadv_vlan_flags - flags for the four MSB of any vlan ID field - * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not - */ -enum batadv_vlan_flags { - BATADV_VLAN_HAS_TAG = BIT(15), -}; - /* mask needed to extract the vlan ID (12bits) from a 16bits variable */ #define BATADV_VID_MASK 0x0FFF #define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \ diff --git a/packet.h b/packet.h index 9a7896b..32ebfbe 100644 --- a/packet.h +++ b/packet.h @@ -124,6 +124,14 @@ enum batadv_tt_client_flags { BATADV_TT_CLIENT_TEMP = BIT(11), };
+/** + * batadv_vlan_flags - flags for the four MSB of any vlan ID field + * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not + */ +enum batadv_vlan_flags { + BATADV_VLAN_HAS_TAG = BIT(15), +}; + /* claim frame types for the bridge loop avoidance */ enum batadv_bla_claimframe { BATADV_CLAIM_TYPE_CLAIM = 0x00, @@ -389,19 +397,23 @@ struct batadv_tvlv_tt_data { * batadv_tt_client_flags) * @reserved: reserved field * @addr: mac address of non-mesh client that triggered this tt change + * @vid: VLAN identifier */ struct batadv_tvlv_tt_change { uint8_t flags; uint8_t reserved; uint8_t addr[ETH_ALEN]; + __be16 vid; };
/** * struct batadv_tvlv_roam_adv - roaming advertisement * @client: mac address of roaming client + * @vid: VLAN identifier */ struct batadv_tvlv_roam_adv { uint8_t client[ETH_ALEN]; + __be16 vid; };
#endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/routing.c b/routing.c index b803f43..e55c962 100644 --- a/routing.c +++ b/routing.c @@ -30,6 +30,8 @@ #include "network-coding.h" #include "fragmentation.h"
+#include <linux/if_vlan.h> + static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if);
@@ -706,6 +708,7 @@ out: * @bat_priv: the bat priv with all the soft interface information * @unicast_packet: the unicast header to be updated * @dst_addr: the payload destination + * @vid: VLAN identifier * * Search the translation table for dst_addr and update the unicast header with * the new corresponding information (originator address where the destination @@ -716,21 +719,22 @@ out: static bool batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct batadv_unicast_packet *unicast_packet, - uint8_t *dst_addr) + uint8_t *dst_addr, unsigned short vid) { struct batadv_orig_node *orig_node = NULL; struct batadv_hard_iface *primary_if = NULL; bool ret = false; uint8_t *orig_addr, orig_ttvn;
- if (batadv_is_my_client(bat_priv, dst_addr)) { + if (batadv_is_my_client(bat_priv, dst_addr, vid)) { primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) goto out; orig_addr = primary_if->net_dev->dev_addr; orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); } else { - orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr); + orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr, + vid); if (!orig_node) goto out;
@@ -760,9 +764,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, uint8_t curr_ttvn, old_ttvn; struct batadv_orig_node *orig_node; struct ethhdr *ethhdr; + struct vlan_ethhdr *vhdr; struct batadv_hard_iface *primary_if; struct batadv_unicast_packet *unicast_packet; int is_old_ttvn; + unsigned short vid = 0;
/* check if there is enough data before accessing it */ if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0) @@ -775,14 +781,21 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, unicast_packet = (struct batadv_unicast_packet *)skb->data; ethhdr = (struct ethhdr *)(skb->data + hdr_len);
+ /* get the vlan id (if this is a vlan eth frame) */ + if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { + vhdr = (struct vlan_ethhdr *)ethhdr; + vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + vid |= BATADV_VLAN_HAS_TAG; + } + /* check if the destination client was served by this node and it is now * roaming. In this case, it means that the node has got a ROAM_ADV * message and that it knows the new destination in the mesh to re-route * the packet to */ - if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest)) { + if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, - ethhdr->h_dest)) + ethhdr->h_dest, vid)) net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", @@ -828,7 +841,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, * target host */ if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, - ethhdr->h_dest)) { + ethhdr->h_dest, vid)) { net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", unicast_packet->dest, ethhdr->h_dest, @@ -840,7 +853,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, * currently served by this node or there is no destination at all and * it is possible to drop the packet */ - if (!batadv_is_my_client(bat_priv, ethhdr->h_dest)) + if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid)) return 0;
/* update the header in order to let the packet be delivered to this diff --git a/send.c b/send.c index 6fc812a..35a514c 100644 --- a/send.c +++ b/send.c @@ -240,12 +240,14 @@ out: * @packet_type: the batman unicast packet type to use * @packet_subtype: the batman packet subtype. It is ignored if packet_type is * not BATADV_UNICAT_4ADDR + * @vid: the vid to be used to search the translation table * * Returns 1 in case of error or 0 otherwise */ int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv, struct sk_buff *skb, int packet_type, - int packet_subtype) + int packet_subtype, + unsigned short vid) { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batadv_unicast_packet *unicast_packet; @@ -264,7 +266,7 @@ int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv, * returns NULL in case of AP isolation */ orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source, - ethhdr->h_dest); + ethhdr->h_dest, vid);
find_router: /* find_router(): @@ -298,7 +300,7 @@ find_router: * try to reroute it because the ttvn contained in the header is less * than the current one */ - if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest)) + if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) unicast_packet->ttvn = unicast_packet->ttvn - 1;
if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) diff --git a/send.h b/send.h index be62c8f..468a9f5 100644 --- a/send.h +++ b/send.h @@ -40,19 +40,21 @@ bool batadv_send_skb_4addr_prepare_unicast(struct batadv_priv *bat_priv, int packet_subtype); int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv, struct sk_buff *skb, int packet_type, - int packet_subtype); - + int packet_subtype, + unsigned short vid);
/** * batadv_send_unicast_skb - send the skb encapsulated in a unicast packet * @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 */ static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv, - struct sk_buff *skb) + struct sk_buff *skb, + unsigned short vid) { return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST, - 0); + 0, vid); }
/** @@ -61,14 +63,16 @@ static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv, * @bat_priv: the bat priv with all the soft interface information * @skb: the payload to send * @packet_subtype: the batman 4addr packet subtype to use + * @vid: the vid to be used to search the translation table */ static inline int batadv_send_skb_4addr_unicast(struct batadv_priv *bat_priv, struct sk_buff *skb, - int packet_subtype) + int packet_subtype, + unsigned short vid) { return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST_4ADDR, - packet_subtype); + packet_subtype, vid); }
#endif /* _NET_BATMAN_ADV_SEND_H_ */ diff --git a/soft-interface.c b/soft-interface.c index 5d08c6c..8911fe5 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -118,9 +118,10 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
/* only modify transtable if it has been initialized before */ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { - batadv_tt_local_remove(bat_priv, old_addr, + batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, "mac address changed", false); - batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX); + batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX, + BATADV_NO_FLAGS); }
return 0; @@ -165,7 +166,8 @@ static int batadv_interface_tx(struct sk_buff *skb, switch (ntohs(ethhdr->h_proto)) { case ETH_P_8021Q: vhdr = (struct vlan_ethhdr *)skb->data; - vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + vid = ntohs(vhdr->h_vlan_TCI); + vid |= BATADV_VLAN_HAS_TAG;
if (vhdr->h_vlan_encapsulated_proto != ethertype) break; @@ -180,7 +182,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
/* Register the client MAC in the transtable */ if (!is_multicast_ether_addr(ethhdr->h_source)) - batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); + batadv_tt_local_add(soft_iface, ethhdr->h_source, vid, + skb->skb_iif);
/* don't accept stp packets. STP does not help in meshes. * better use the bridge loop avoidance ... @@ -274,7 +277,7 @@ 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); + ret = batadv_send_skb_unicast(bat_priv, skb, vid); if (ret != 0) goto dropped_freed; } @@ -319,7 +322,8 @@ void batadv_interface_rx(struct net_device *soft_iface, switch (ntohs(ethhdr->h_proto)) { case ETH_P_8021Q: vhdr = (struct vlan_ethhdr *)skb->data; - vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + vid = ntohs(vhdr->h_vlan_TCI); + vid |= BATADV_VLAN_HAS_TAG;
if (vhdr->h_vlan_encapsulated_proto != ethertype) break; @@ -355,7 +359,7 @@ void batadv_interface_rx(struct net_device *soft_iface,
if (orig_node) batadv_tt_add_temporary_global_entry(bat_priv, orig_node, - ethhdr->h_source); + ethhdr->h_source, vid);
if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest)) goto dropped; diff --git a/translation-table.c b/translation-table.c index 185d2d7..ae8fad0 100644 --- a/translation-table.c +++ b/translation-table.c @@ -34,6 +34,7 @@ static struct lock_class_key batadv_tt_local_hash_lock_class_key; static struct lock_class_key batadv_tt_global_hash_lock_class_key;
static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, + unsigned short vid, struct batadv_orig_node *orig_node); static void batadv_tt_purge(struct work_struct *work); static void @@ -41,7 +42,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); static void batadv_tt_global_del(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const unsigned char *addr, - const char *message, bool roaming); + unsigned short vid, const char *message, + bool roaming);
/* returns 1 if they are the same mac addr */ static int batadv_compare_tt(const struct hlist_node *node, const void *data2) @@ -52,43 +54,90 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2) return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); }
+/** + * batadv_choose_tt - return the index of the tt entry in the hash table + * @data: pointer to the tt_common_entry object to map + * @size: the size of the hash table + */ +static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) +{ + struct batadv_tt_common_entry *tt; + uint32_t hash = 0; + + tt = (struct batadv_tt_common_entry *)data; + hash = batadv_hash_bytes(hash, &tt->addr, ETH_ALEN); + hash = batadv_hash_bytes(hash, &tt->vid, sizeof(tt->vid)); + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash % size; +} + +/** + * batadv_tt_hash_find - looks for a client in the given hash table + * @hash: the hash table to search + * @addr: the mac address of the client to look for + * @vid: VLAN identifier + * + * Return a pointer to the tt_common struct belonging to the searched client if + * found, NULL otherwise + */ static struct batadv_tt_common_entry * -batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data) +batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, + unsigned short vid) { struct hlist_head *head; - struct batadv_tt_common_entry *tt_common_entry; - struct batadv_tt_common_entry *tt_common_entry_tmp = NULL; + struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; uint32_t index;
if (!hash) return NULL;
- index = batadv_choose_orig(data, hash->size); + memcpy(to_search.addr, addr, ETH_ALEN); + to_search.vid = vid; + + index = batadv_choose_tt(&to_search, hash->size); head = &hash->table[index];
rcu_read_lock(); - hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) { - if (!batadv_compare_eth(tt_common_entry, data)) + hlist_for_each_entry_rcu(tt, head, hash_entry) { + if (!batadv_compare_eth(tt, addr)) continue;
- if (!atomic_inc_not_zero(&tt_common_entry->refcount)) + if (tt->vid != vid) continue;
- tt_common_entry_tmp = tt_common_entry; + if (!atomic_inc_not_zero(&tt->refcount)) + continue; + + tt_tmp = tt; break; } rcu_read_unlock();
- return tt_common_entry_tmp; + return tt_tmp; }
+/** + * batadv_tt_local_hash_find - Search the local table for a given client + * @bat_priv: the bat priv with all the soft interface information + * @addr: the mac address of the client to look for + * @vid: VLAN identifier + * + * Return a pointer to the corresponding tt_local_entry struct if the client is + * found, NULL otherwise + */ static struct batadv_tt_local_entry * -batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) +batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, + unsigned short vid) { struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_local_entry *tt_local_entry = NULL;
- tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data); + tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, + vid); if (tt_common_entry) tt_local_entry = container_of(tt_common_entry, struct batadv_tt_local_entry, @@ -96,13 +145,24 @@ batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) return tt_local_entry; }
+/** + * batadv_tt_global_hash_find - Search the global table for a given client + * @bat_priv: the bat priv with all the soft interface information + * @addr: the mac address of the client to look for + * @vid: VLAN identifier + * + * Return a pointer to the corresponding tt_global_entry struct if the client is + * found, NULL otherwise + */ static struct batadv_tt_global_entry * -batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data) +batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, + unsigned short vid) { struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_global_entry *tt_global_entry = NULL;
- tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data); + tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, + vid); if (tt_common_entry) tt_global_entry = container_of(tt_common_entry, struct batadv_tt_global_entry, @@ -186,6 +246,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, tt_change_node->change.flags = flags; tt_change_node->change.reserved = 0; memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); + tt_change_node->change.vid = htons(common->vid);
del_op_requested = flags & BATADV_TT_CLIENT_DEL;
@@ -265,12 +326,21 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, tt_global->common.addr, message);
batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, - batadv_choose_orig, tt_global->common.addr); + batadv_choose_tt, &tt_global->common); batadv_tt_global_entry_free_ref(tt_global); }
+/** + * batadv_tt_local_add - add a new client to the local table or update it if + * already exists + * @soft_iface: netdev struct of the mesh interface + * @addr: the mac address of the client to add + * @vid: VLAN identifier + * @ifindex: index of the interface where the client is connected to (useful to + * identify wireless clients) + */ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, - int ifindex) + unsigned short vid, int ifindex) { struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_tt_local_entry *tt_local; @@ -280,8 +350,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, int hash_added; bool roamed_back = false;
- tt_local = batadv_tt_local_hash_find(bat_priv, addr); - tt_global = batadv_tt_global_hash_find(bat_priv, addr); + tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); + tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (tt_local) { tt_local->last_seen = jiffies; @@ -326,6 +396,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, * (consistency check) */ tt_local->common.flags = BATADV_TT_CLIENT_NEW; + tt_local->common.vid = vid; if (batadv_is_wifi_iface(ifindex)) tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; atomic_set(&tt_local->common.refcount, 2); @@ -337,7 +408,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, - batadv_choose_orig, &tt_local->common, + batadv_choose_tt, &tt_local->common, &tt_local->common.hash_entry);
if (unlikely(hash_added != 0)) { @@ -359,6 +430,7 @@ check_roaming: rcu_read_lock(); hlist_for_each_entry_rcu(orig_entry, head, list) { batadv_send_roam_adv(bat_priv, tt_global->common.addr, + tt_global->common.vid, orig_entry->orig_node); } rcu_read_unlock(); @@ -547,19 +619,20 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv, * batadv_tt_local_remove - logically remove an entry from the local table * @bat_priv: the bat priv with all the soft interface information * @addr: the MAC address of the client to remove + * @vid: VLAN identifier * @message: message to append to the log on deletion * @roaming: true if the deletion is due to a roaming event * * Returns the flags assigned to the local entry before being deleted */ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, - const uint8_t *addr, const char *message, - bool roaming) + const uint8_t *addr, unsigned short vid, + const char *message, bool roaming) { struct batadv_tt_local_entry *tt_local_entry; uint16_t flags, curr_flags = BATADV_NO_FLAGS;
- tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) goto out;
@@ -795,6 +868,7 @@ out: * @bat_priv: the bat priv with all the soft interface information * @orig_node: the originator announcing the client * @tt_addr: the mac address of the non-mesh client + * @vid: VLAN identifier * @flags: TT flags that have to be set for this non-mesh client * @ttvn: the tt version number ever announcing this non-mesh client * @@ -808,8 +882,8 @@ out: */ int batadv_tt_global_add(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const unsigned char *tt_addr, uint16_t flags, - uint8_t ttvn) + const unsigned char *tt_addr, unsigned short vid, + uint16_t flags, uint8_t ttvn) { struct batadv_tt_global_entry *tt_global_entry; struct batadv_tt_local_entry *tt_local_entry; @@ -818,8 +892,8 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv, struct batadv_tt_common_entry *common; uint16_t local_flags;
- tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); - tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr); + tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
/* if the node already has a local client for this entry, it has to wait * for a roaming advertisement instead of manually messing up the global @@ -836,6 +910,7 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
common = &tt_global_entry->common; memcpy(common->addr, tt_addr, ETH_ALEN); + common->vid = vid;
common->flags = flags; tt_global_entry->roam_at = 0; @@ -853,7 +928,7 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
hash_added = batadv_hash_add(bat_priv->tt.global_hash, batadv_compare_tt, - batadv_choose_orig, common, + batadv_choose_tt, common, &common->hash_entry);
if (unlikely(hash_added != 0)) { @@ -919,7 +994,7 @@ add_orig_entry: out_remove:
/* remove address from local hash if present */ - local_flags = batadv_tt_local_remove(bat_priv, tt_addr, + local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, "global tt received", flags & BATADV_TT_CLIENT_ROAM); tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; @@ -1142,17 +1217,24 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, orig_node, message); }
- - +/** + * batadv_tt_global_del - remove a client from the global table + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: an originator serving this client + * @addr: the mac address of the client + * @vid: VLAN identifier + * @message: a message explaining the reason for deleting the client to print + * for debugging purpose + */ static void batadv_tt_global_del(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const unsigned char *addr, + const unsigned char *addr, unsigned short vid, const char *message, bool roaming) { struct batadv_tt_global_entry *tt_global_entry; struct batadv_tt_local_entry *local_entry = NULL;
- tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); + tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global_entry) goto out;
@@ -1181,7 +1263,8 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv, * the global entry, since it is useless now. */ local_entry = batadv_tt_local_hash_find(bat_priv, - tt_global_entry->common.addr); + tt_global_entry->common.addr, + vid); if (local_entry) { /* local entry exists, case 2: client roamed to us. */ batadv_tt_global_del_orig_list(tt_global_entry); @@ -1349,9 +1432,24 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, return ret; }
+/** + * batadv_transtable_search - get the mesh destination for a given client + * @bat_priv: the bat priv with all the soft interface information + * @src: mac address of the source client + * @addr: mac address of the destination client + * @vid: VLAN identifier + * + * Return a pointer to the originator being the node selected as destination in + * the mesh for contacting the client 'addr', NULL otherwise. + * In case of multiple originators serving the same client, the function returns + * the best one (best in terms of TQ). + * + * If the two clients are AP isolated the function returns NULL. + */ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const uint8_t *src, - const uint8_t *addr) + const uint8_t *addr, + unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; @@ -1359,13 +1457,13 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, struct batadv_tt_orig_list_entry *best_entry;
if (src && atomic_read(&bat_priv->ap_isolation)) { - tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); if (!tt_local_entry || (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) goto out; }
- tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); + tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global_entry) goto out;
@@ -1396,7 +1494,7 @@ out:
/** * batadv_tt_global_crc - calculates the checksum of the local table of a - * given orig_node + * given orig_node * @bat_priv: the bat priv with all the soft interface information */ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, @@ -1646,6 +1744,7 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, memcpy(tt_change->addr, tt_common_entry->addr, ETH_ALEN); tt_change->flags = tt_common_entry->flags; + tt_change->vid = htons(tt_common_entry->vid); tt_change->reserved = 0;
tt_num_entries++; @@ -1976,11 +2075,13 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; batadv_tt_global_del(bat_priv, orig_node, (tt_change + i)->addr, + ntohs((tt_change + i)->vid), "tt removed by changes", roams); } else { if (!batadv_tt_global_add(bat_priv, orig_node, (tt_change + i)->addr, + ntohs((tt_change + i)->vid), (tt_change + i)->flags, ttvn)) /* In case of problem while storing a * global_entry, we stop the updating @@ -2037,12 +2138,21 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv, atomic_set(&orig_node->last_ttvn, ttvn); }
-bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr) +/** + * batadv_is_my_client - check if a client is served by the local node + * @bat_priv: the bat priv with all the soft interface information + * @addr: the mac adress of the client to check + * @vid: VLAN identifier + * + * Return true if the client is served by this node, false otherwise + */ +bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, + unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry; bool ret = false;
- tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) goto out; /* Check if the client has been logically deleted (but is kept for @@ -2191,7 +2301,19 @@ unlock: return ret; }
+/** + * batadv_send_roam_adv - send a roaming advertisement message + * @bat_priv: the bat priv with all the soft interface information + * @client: mac address of the roaming client + * @vid: VLAN identifier + * @orig_node: message destination + * + * Send a ROAMING_ADV message to the node which was previously serving this + * client. This is done to inform the originator that now all the traffic + * directed to the provided mac address has to be forwarded here + */ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, + unsigned short vid, struct batadv_orig_node *orig_node) { struct batadv_hard_iface *primary_if; @@ -2214,6 +2336,7 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); + tvlv_roam.vid = htons(vid);
batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, orig_node->orig, BATADV_TVLV_ROAM, 1, @@ -2379,11 +2502,13 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, if (!atomic_read(&bat_priv->ap_isolation)) goto out;
- tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, + BATADV_NO_FLAGS); if (!tt_local_entry) goto out;
- tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); + tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, + BATADV_NO_FLAGS); if (!tt_global_entry) goto out;
@@ -2478,17 +2603,23 @@ request_table: } }
-/* returns true whether we know that the client has moved from its old - * originator to another one. This entry is kept is still kept for consistency - * purposes +/** + * batadv_tt_global_client_is_roaming - check if a client is marked as roaming + * @bat_priv: the bat priv with all the soft interface information + * @addr: the mac address of the client to check + * @vid: VLAN identifier + * + * Return true whether we know that the client has moved from its old originator + * to another one. This entry is still kept for consistency purposes and will be + * deleted later by a DEL or because of timeout */ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr) + uint8_t *addr, unsigned short vid) { struct batadv_tt_global_entry *tt_global_entry; bool ret = false;
- tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); + tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); if (!tt_global_entry) goto out;
@@ -2501,19 +2632,20 @@ out: /** * batadv_tt_local_client_is_roaming - tells whether the client is roaming * @bat_priv: the bat priv with all the soft interface information - * @addr: the MAC address of the local client to query + * @addr: the mac address of the local client to query + * @vid: VLAN identifier * * Returns true if the local client is known to be roaming (it is not served by * this node anymore) or not. If yes, the client is still present in the table * to keep the latter consistent with the node TTVN */ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr) + uint8_t *addr, unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry; bool ret = false;
- tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) goto out;
@@ -2525,7 +2657,8 @@ out:
bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const unsigned char *addr) + const unsigned char *addr, + unsigned short vlan) { bool ret = false;
@@ -2536,7 +2669,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) goto out;
- if (!batadv_tt_global_add(bat_priv, orig_node, addr, + if (!batadv_tt_global_add(bat_priv, orig_node, addr, vlan, BATADV_TT_CLIENT_TEMP, atomic_read(&orig_node->last_ttvn))) goto out; @@ -2702,7 +2835,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, src, roaming_adv->client);
batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, - BATADV_TT_CLIENT_ROAM, + ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, atomic_read(&orig_node->last_ttvn) + 1);
out: diff --git a/translation-table.h b/translation-table.h index b4b6dea..1944ba5 100644 --- a/translation-table.h +++ b/translation-table.h @@ -22,36 +22,39 @@
int batadv_tt_init(struct batadv_priv *bat_priv); void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, - int ifindex); + unsigned short vid, int ifindex); uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, - const uint8_t *addr, const char *message, - bool roaming); + const uint8_t *addr, unsigned short vid, + const char *message, bool roaming); int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); void batadv_tt_global_add_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const unsigned char *tt_buff, int tt_buff_len); int batadv_tt_global_add(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const unsigned char *addr, uint16_t flags, - uint8_t ttvn); + const unsigned char *addr, unsigned short vid, + uint16_t flags, uint8_t ttvn); int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const char *message); struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const uint8_t *src, - const uint8_t *addr); + const uint8_t *addr, + unsigned short vid); void batadv_tt_free(struct batadv_priv *bat_priv); -bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr); +bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, + unsigned short vid); bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, uint8_t *dst); void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr); + uint8_t *addr, unsigned short vid); bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr); + uint8_t *addr, unsigned short vid); bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const unsigned char *addr); + const unsigned char *addr, + unsigned short vid);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ diff --git a/types.h b/types.h index b9bc2b6..20bf2e6 100644 --- a/types.h +++ b/types.h @@ -712,6 +712,7 @@ struct batadv_bla_claim { /** * struct batadv_tt_common_entry - tt local & tt global common data * @addr: mac address of non-mesh client + * @vid: VLAN identifier * @hash_entry: hlist node for batadv_priv_tt::local_hash or for * batadv_priv_tt::global_hash * @flags: various state handling flags (see batadv_tt_client_flags) @@ -721,6 +722,7 @@ struct batadv_bla_claim { */ struct batadv_tt_common_entry { uint8_t addr[ETH_ALEN]; + unsigned short vid; struct hlist_node hash_entry; uint16_t flags; unsigned long added_at;
On Tuesday, April 23, 2013 22:34:29 Antonio Quartulli wrote:
/**
- batadv_send_unicast_skb - send the skb encapsulated in a unicast packet
- @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
static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
Returns ?
@@ -61,14 +63,16 @@ static inline int batadv_send_skb_unicast(struct
batadv_priv *bat_priv,
- @bat_priv: the bat priv with all the soft interface information
- @skb: the payload to send
- @packet_subtype: the batman 4addr packet subtype to use
*/
- @vid: the vid to be used to search the translation table
static inline int batadv_send_skb_4addr_unicast(struct batadv_priv
*bat_priv,
Returns ?
+/**
- batadv_tt_local_add - add a new client to the local table or update it
if + * already exists
- @soft_iface: netdev struct of the mesh interface
- @addr: the mac address of the client to add
- @vid: VLAN identifier
- @ifindex: index of the interface where the client is connected to
(useful to + * identify wireless clients)
- */
Multi-line kernel doc should be indented by a space.
+/**
- batadv_choose_tt - return the index of the tt entry in the hash table
- @data: pointer to the tt_common_entry object to map
- @size: the size of the hash table
- */
+static inline uint32_t batadv_choose_tt(const void *data, uint32_t size)
Returns ?
+/**
- batadv_tt_local_add - add a new client to the local table or update it
if
- already exists
- @soft_iface: netdev struct of the mesh interface
- @addr: the mac address of the client to add
- @vid: VLAN identifier
- @ifindex: index of the interface where the client is connected to
(useful to
- identify wireless clients)
- */
Space indentation in the title ..
+/**
- batadv_tt_global_del - remove a client from the global table
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: an originator serving this client
- @addr: the mac address of the client
- @vid: VLAN identifier
- @message: a message explaining the reason for deleting the client to
- for debugging purpose
- */
static void batadv_tt_global_del(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
const unsigned char *addr,
const unsigned char *addr, unsigned short
vid,
const char *message, bool roaming)
Kernel doc for roaming is missing and a space as well. :)
Cheers, Marek
From: Antonio Quartulli antonio@open-mesh.com
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@open-mesh.com --- translation-table.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/translation-table.c b/translation-table.c index ae8fad0..c6effd3 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1504,7 +1504,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]; @@ -1535,7 +1535,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(); } @@ -1552,7 +1554,7 @@ 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]; @@ -1565,7 +1567,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(); }
On Tuesday, April 23, 2013 22:34:30 Antonio Quartulli wrote:
@@ -1535,7 +1535,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();
Is it necessary to define another variable ? Why not:
crc = crc32c(0, &tt_common->vid, sizeof(tt_common->vid)); crc ^= crc32c(crc, tt_common->addr, ETH_ALEN);
@@ -1565,7 +1567,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); }
Dito.
Cheers, Marek
On Wed, Apr 24, 2013 at 03:58:56AM +0800, Marek Lindner wrote:
On Tuesday, April 23, 2013 22:34:30 Antonio Quartulli wrote:
@@ -1535,7 +1535,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();
Is it necessary to define another variable ?
yes
Why not:
crc = crc32c(0, &tt_common->vid, sizeof(tt_common->vid)); crc ^= crc32c(crc, tt_common->addr, ETH_ALEN);
because crc_tmp is the result of the CRC operation on the VID and the MAC address (so one per client), while crc is the container of all the crc_tmp xor'ed together..
@@ -1565,7 +1567,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); }
Dito.
Idem.
Cheers,
On Wednesday, April 24, 2013 04:04:34 Antonio Quartulli wrote:
On Wed, Apr 24, 2013 at 03:58:56AM +0800, Marek Lindner wrote:
On Tuesday, April 23, 2013 22:34:30 Antonio Quartulli wrote:
@@ -1535,7 +1535,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();
Is it necessary to define another variable ?
yes
Why not:
crc = crc32c(0, &tt_common->vid, sizeof(tt_common->vid)); crc ^= crc32c(crc, tt_common->addr, ETH_ALEN);
because crc_tmp is the result of the CRC operation on the VID and the MAC address (so one per client), while crc is the container of all the crc_tmp xor'ed together..
As we discussed on IRC please add a big comment here explaining why we do things this way and not differently.
Cheers, Marek
On Sat, May 04, 2013 at 08:12:22PM +0800, Marek Lindner wrote:
On Wednesday, April 24, 2013 04:04:34 Antonio Quartulli wrote:
On Wed, Apr 24, 2013 at 03:58:56AM +0800, Marek Lindner wrote:
On Tuesday, April 23, 2013 22:34:30 Antonio Quartulli wrote:
@@ -1535,7 +1535,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();
Is it necessary to define another variable ?
yes
Why not:
crc = crc32c(0, &tt_common->vid, sizeof(tt_common->vid)); crc ^= crc32c(crc, tt_common->addr, ETH_ALEN);
because crc_tmp is the result of the CRC operation on the VID and the MAC address (so one per client), while crc is the container of all the crc_tmp xor'ed together..
As we discussed on IRC please add a big comment here explaining why we do things this way and not differently.
Yeah, as I told you on IRC the comment is ready :-) Will add it in the next version
Cheers,
From: Antonio Quartulli antonio@open-mesh.com
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- translation-table.c | 82 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 32 deletions(-)
diff --git a/translation-table.c b/translation-table.c index c6effd3..fc4d10e 100644 --- a/translation-table.c +++ b/translation-table.c @@ -322,8 +322,9 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, const char *message) { batadv_dbg(BATADV_DBG_TT, bat_priv, - "Deleting global tt entry %pM: %s\n", - tt_global->common.addr, message); + "Deleting global tt entry %pM (vid: %d): %s\n", + tt_global->common.addr, + BATADV_PRINT_VID(tt_global->common.vid), message);
batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, batadv_choose_tt, &tt_global->common); @@ -357,7 +358,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, tt_local->last_seen = jiffies; if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { batadv_dbg(BATADV_DBG_TT, bat_priv, - "Re-adding pending client %pM\n", addr); + "Re-adding pending client %pM (vid: %d)\n", + addr, BATADV_PRINT_VID(vid)); /* whatever the reason why the PENDING flag was set, * this is a client which was enqueued to be removed in * this orig_interval. Since it popped up again, the @@ -369,8 +371,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { batadv_dbg(BATADV_DBG_TT, bat_priv, - "Roaming client %pM came back to its original location\n", - addr); + "Roaming client %pM (vid: %d) came back to its original location\n", + addr, BATADV_PRINT_VID(vid)); /* the ROAM flag is set because this client roamed away * and the node got a roaming_advertisement message. Now * that the client popped up again at its original @@ -387,7 +389,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, goto out;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Creating new local tt entry: %pM (ttvn: %d)\n", addr, + "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", + addr, BATADV_PRINT_VID(vid), (uint8_t)atomic_read(&bat_priv->tt.vn));
memcpy(tt_local->common.addr, addr, ETH_ALEN); @@ -556,8 +559,8 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.8x):\n", net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn), bat_priv->tt.local_crc); - seq_printf(seq, " %-13s %-7s %-10s\n", "Client", "Flags", - "Last seen"); + seq_printf(seq, " %-13s %s %-7s %-10s\n", "Client", "VID", + "Flags", "Last seen");
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -575,8 +578,9 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
no_purge = tt_common_entry->flags & np_flag;
- seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n", + seq_printf(seq, " * %pM %4i [%c%c%c%c%c] %3u.%03u\n", tt_common_entry->addr, + BATADV_PRINT_VID(tt_common_entry->vid), (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), no_purge ? 'P' : '.', @@ -611,8 +615,9 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv, tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Local tt entry (%pM) pending to be removed: %s\n", - tt_local_entry->common.addr, message); + "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", + tt_local_entry->common.addr, + BATADV_PRINT_VID(tt_local_entry->common.vid), message); }
/** @@ -987,8 +992,9 @@ add_orig_entry: batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Creating new global tt entry: %pM (via %pM)\n", - common->addr, orig_node->orig); + "Creating new global tt entry: %pM (vid: %d, via %pM)\n", + common->addr, BATADV_PRINT_VID(common->vid), + orig_node->orig); ret = 1;
out_remove: @@ -1068,8 +1074,9 @@ batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, if (best_entry) { last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); seq_printf(seq, - " %c %pM (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", + " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", '*', tt_global_entry->common.addr, + BATADV_PRINT_VID(tt_global_entry->common.vid), best_entry->ttvn, best_entry->orig_node->orig, last_ttvn, best_entry->orig_node->tt_crc, (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), @@ -1084,8 +1091,10 @@ batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, continue;
last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); - seq_printf(seq, " %c %pM (%3u) via %pM (%3u) [%c%c%c]\n", + seq_printf(seq, + " %c %pM %4d (%3u) via %pM (%3u) [%c%c%c]\n", '+', tt_global_entry->common.addr, + BATADV_PRINT_VID(tt_global_entry->common.vid), orig_entry->ttvn, orig_entry->orig_node->orig, last_ttvn, (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), @@ -1112,9 +1121,9 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "Globally announced TT entries received via the mesh %s\n", net_dev->name); - seq_printf(seq, " %-13s %s %-15s %s (%-10s) %s\n", - "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC", - "Flags"); + seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n", + "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", + "CRC", "Flags");
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -1161,15 +1170,18 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, struct hlist_head *head; struct hlist_node *safe; struct batadv_tt_orig_list_entry *orig_entry; + unsigned short vid;
spin_lock_bh(&tt_global_entry->list_lock); head = &tt_global_entry->orig_list; hlist_for_each_entry_safe(orig_entry, safe, head, list) { if (orig_entry->orig_node == orig_node) { + vid = tt_global_entry->common.vid; batadv_dbg(BATADV_DBG_TT, bat_priv, - "Deleting %pM from global tt entry %pM: %s\n", + "Deleting %pM from global tt entry %pM (vid: %d): %s\n", orig_node->orig, - tt_global_entry->common.addr, message); + tt_global_entry->common.addr, + BATADV_PRINT_VID(vid), message); hlist_del_rcu(&orig_entry->list); batadv_tt_orig_list_entry_free_ref(orig_entry); } @@ -1293,6 +1305,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct hlist_node *safe; struct hlist_head *head; spinlock_t *list_lock; /* protects write access to the hash lists */ + unsigned short vid;
if (!hash) return; @@ -1312,9 +1325,11 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, orig_node, message);
if (hlist_empty(&tt_global->orig_list)) { + vid = tt_global->common.vid; batadv_dbg(BATADV_DBG_TT, bat_priv, - "Deleting global tt entry %pM: %s\n", - tt_global->common.addr, message); + "Deleting global tt entry %pM (vid: %d): %s\n", + tt_global->common.addr, + BATADV_PRINT_VID(vid), message); hlist_del_rcu(&tt_common_entry->hash_entry); batadv_tt_global_entry_free_ref(tt_global); } @@ -1372,8 +1387,10 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv) continue;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Deleting global tt entry (%pM): %s\n", - tt_global->common.addr, msg); + "Deleting global tt entry %pM (vid: %d): %s\n", + tt_global->common.addr, + BATADV_PRINT_VID(tt_global->common.vid), + msg);
hlist_del_rcu(&tt_common->hash_entry);
@@ -2334,8 +2351,8 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, goto out;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Sending ROAMING_ADV to %pM (client %pM)\n", - orig_node->orig, client); + "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", + orig_node->orig, client, BATADV_PRINT_VID(vid));
batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
@@ -2448,8 +2465,9 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) continue;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Deleting local tt entry (%pM): pending\n", - tt_common->addr); + "Deleting local tt entry (%pM, vid: %d): pending\n", + tt_common->addr, + BATADV_PRINT_VID(tt_common->vid));
atomic_dec(&bat_priv->tt.local_entry_num); hlist_del_rcu(&tt_common->hash_entry); @@ -2662,7 +2680,7 @@ out: bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const unsigned char *addr, - unsigned short vlan) + unsigned short vid) { bool ret = false;
@@ -2673,14 +2691,14 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) goto out;
- if (!batadv_tt_global_add(bat_priv, orig_node, addr, vlan, + if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, BATADV_TT_CLIENT_TEMP, atomic_read(&orig_node->last_ttvn))) goto out;
batadv_dbg(BATADV_DBG_TT, bat_priv, - "Added temporary global client (addr: %pM orig: %pM)\n", - addr, orig_node->orig); + "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", + addr, BATADV_PRINT_VID(vid), orig_node->orig); ret = true; out: return ret;
From: Antonio Quartulli antonio@open-mesh.com
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@open-mesh.com --- gateway_client.c | 6 +++--- gateway_client.h | 3 ++- soft-interface.c | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/gateway_client.c b/gateway_client.c index 8812965..5862cff 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -635,7 +635,8 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) }
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, - struct sk_buff *skb, struct ethhdr *ethhdr) + struct sk_buff *skb, struct ethhdr *ethhdr, + unsigned short vid) { struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; @@ -649,8 +650,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, goto out;
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;
diff --git a/gateway_client.h b/gateway_client.h index 039902d..e276d70 100644 --- a/gateway_client.h +++ b/gateway_client.h @@ -35,6 +35,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len); bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, - struct sk_buff *skb, struct ethhdr *ethhdr); + struct sk_buff *skb, struct ethhdr *ethhdr, + unsigned short vid);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/soft-interface.c b/soft-interface.c index 8911fe5..1559854 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -267,7 +267,8 @@ static int batadv_interface_tx(struct sk_buff *skb, /* unicast packet */ } else { if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) { - ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr); + ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr, + vid); if (ret) goto dropped; }
On Tue, Apr 23, 2013 at 04:34:32PM +0200, Antonio Quartulli wrote:
From: Antonio Quartulli antonio@open-mesh.com
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@open-mesh.com
Ooops, this patch has been sent by accident. Please ignore it. There is another patch correct patch 4 on the ml.
Cheers,
On Tuesday, April 23, 2013 22:34:32 Antonio Quartulli wrote:
@@ -635,7 +635,8 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) }
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct ethhdr *ethhdr)
struct sk_buff *skb, struct ethhdr *ethhdr,
unsigned short vid)
Kernel doc ?
Cheers, Marek
On Sat, May 04, 2013 at 08:42:44PM +0800, Marek Lindner wrote:
On Tuesday, April 23, 2013 22:34:32 Antonio Quartulli wrote:
@@ -635,7 +635,8 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) }
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct ethhdr *ethhdr)
struct sk_buff *skb, struct ethhdr *ethhdr,
unsigned short vid)
Kernel doc ?
Sorry but as written my previous email, this patch has been sent by mistake. There is another 4/7 in the patchset which is the correct one.
I'll simply ignore this comment :)
Cheers,
From: Antonio Quartulli antonio@open-mesh.com
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@open-mesh.com --- gateway_client.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/gateway_client.c b/gateway_client.c index 8812965..a2cd2df 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -640,17 +640,24 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; struct batadv_gw_node *curr_gw = NULL; + struct vlan_ethhdr *vhdr; bool ret, out_of_range = false; unsigned int header_len = 0; + unsigned short vid = BATADV_NO_FLAGS; uint8_t curr_tq_avg;
+ if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { + vhdr = (struct vlan_ethhdr *)ethhdr; + vid = ntohs(vhdr->h_vlan_TCI); + vid |= BATADV_VLAN_HAS_TAG; + } + ret = batadv_gw_is_dhcp_target(skb, &header_len); if (!ret) goto out;
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;
From: Antonio Quartulli antonio@open-mesh.com
The same IP subnet can be used on different VLANs, therefore DAT has to differentiate whether the IP to resolve belongs to one or the other virtual LAN. To accomplish this task DAT has to deal with the VLAN tag and store it together with each ARP entry.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- distributed-arp-table.c | 129 +++++++++++++++++++++++++++++++++--------------- types.h | 2 + 2 files changed, 92 insertions(+), 39 deletions(-)
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index 2123ab2..d05de52 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -19,6 +19,7 @@
#include <linux/if_ether.h> #include <linux/if_arp.h> +#include <linux/if_vlan.h> #include <net/arp.h>
#include "main.h" @@ -205,15 +206,11 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size) */ static uint32_t batadv_hash_dat(const void *data, uint32_t size) { - const unsigned char *key = data; uint32_t hash = 0; - size_t i; + const struct batadv_dat_entry *dat = data;
- for (i = 0; i < 4; i++) { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } + hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip)); + hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid));
hash += (hash << 3); hash ^= (hash >> 11); @@ -227,21 +224,26 @@ static uint32_t batadv_hash_dat(const void *data, uint32_t size) * table * @bat_priv: the bat priv with all the soft interface information * @ip: search key + * @vid: VLAN identifier * * Returns the dat_entry if found, NULL otherwise. */ static struct batadv_dat_entry * -batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip) +batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, + unsigned short vid) { struct hlist_head *head; - struct batadv_dat_entry *dat_entry, *dat_entry_tmp = NULL; + struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL; struct batadv_hashtable *hash = bat_priv->dat.hash; uint32_t index;
if (!hash) return NULL;
- index = batadv_hash_dat(&ip, hash->size); + to_find.ip = ip; + to_find.vid = vid; + + index = batadv_hash_dat(&to_find, hash->size); head = &hash->table[index];
rcu_read_lock(); @@ -267,20 +269,20 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip) * @mac_addr: mac address to assign to the given ipv4 */ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, - uint8_t *mac_addr) + uint8_t *mac_addr, unsigned short vid) { struct batadv_dat_entry *dat_entry; int hash_added;
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip); + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid); /* if this entry is already known, just update it */ if (dat_entry) { if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); dat_entry->last_update = jiffies; batadv_dbg(BATADV_DBG_DAT, bat_priv, - "Entry updated: %pI4 %pM\n", &dat_entry->ip, - dat_entry->mac_addr); + "Entry updated: %pI4 %pM (vid: %u)\n", + &dat_entry->ip, dat_entry->mac_addr, vid); goto out; }
@@ -289,12 +291,13 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, goto out;
dat_entry->ip = ip; + dat_entry->vid = vid; memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); dat_entry->last_update = jiffies; atomic_set(&dat_entry->refcount, 2);
hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, - batadv_hash_dat, &dat_entry->ip, + batadv_hash_dat, dat_entry, &dat_entry->hash_entry);
if (unlikely(hash_added != 0)) { @@ -303,8 +306,8 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, goto out; }
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM\n", - &dat_entry->ip, dat_entry->mac_addr); + batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %u)\n", + &dat_entry->ip, dat_entry->mac_addr, vid);
out: if (dat_entry) @@ -858,6 +861,38 @@ out: }
/** + * batadv_dat_get_vid - extract the VLAN identifier from skb if any + * @skb: the buffer containing the packet to extract the VID from + * @hdr_size: the size of the batman-adv header encapsulating the packet + * + * If the packet contained in skb is vlan tagged then this function returns the + * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise returns BATADV_NO_FLAGS + */ +static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) +{ + struct ethhdr *ethhdr; + struct vlan_ethhdr *vhdr; + unsigned short vid; + + ethhdr = (struct ethhdr *)skb->data + *hdr_size; + + if (ntohs(ethhdr->h_proto) != ETH_P_8021Q) + return BATADV_NO_FLAGS; + + vhdr = (struct vlan_ethhdr *)ethhdr; + vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + vid |= BATADV_VLAN_HAS_TAG; + /* ARP parsing functions jump forward of hdr_size + ETH_HLEN. + * If the header contained in the packet is a VLAN one (which is longer) + * hdr_size is updated so that the functions will still jump the + * correct amount of bytes + */ + *hdr_size += VLAN_HLEN; + + return vid; +} + +/** * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to * answer using DAT * @bat_priv: the bat priv with all the soft interface information @@ -876,11 +911,15 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, bool ret = false; struct batadv_dat_entry *dat_entry = NULL; struct sk_buff *skb_new; + int hdr_size = 0; + unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table)) goto out;
- type = batadv_arp_get_type(bat_priv, skb, 0); + vid = batadv_dat_get_vid(skb, &hdr_size); + + type = batadv_arp_get_type(bat_priv, skb, hdr_size); /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast * message to the selected DHT candidates */ @@ -893,9 +932,9 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, hw_src = batadv_arp_hw_src(skb, 0); ip_dst = batadv_arp_ip_dst(skb, 0);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src); + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); if (dat_entry) { skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src, bat_priv->soft_iface, ip_dst, hw_src, @@ -942,11 +981,14 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb_new; struct batadv_dat_entry *dat_entry = NULL; bool ret = false; + unsigned short vid; int err;
if (!atomic_read(&bat_priv->distributed_arp_table)) goto out;
+ vid = batadv_dat_get_vid(skb, &hdr_size); + type = batadv_arp_get_type(bat_priv, skb, hdr_size); if (type != ARPOP_REQUEST) goto out; @@ -958,9 +1000,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, batadv_dbg_arp(bat_priv, skb, type, hdr_size, "Parsing incoming ARP REQUEST");
- batadv_dat_entry_add(bat_priv, ip_src, hw_src); + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); if (!dat_entry) goto out;
@@ -978,10 +1020,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) err = batadv_send_skb_4addr_unicast(bat_priv, skb_new, BATADV_P_DAT_CACHE_REPLY, - BATADV_NO_FLAGS); + vid); else - err = batadv_send_skb_unicast(bat_priv, skb_new, - BATADV_NO_FLAGS); + err = batadv_send_skb_unicast(bat_priv, skb_new, vid);
if (!err) { batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); @@ -1006,23 +1047,27 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, uint16_t type; __be32 ip_src, ip_dst; uint8_t *hw_src, *hw_dst; + int hdr_size = 0; + unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table)) return;
- type = batadv_arp_get_type(bat_priv, skb, 0); + vid = batadv_dat_get_vid(skb, &hdr_size); + + type = batadv_arp_get_type(bat_priv, skb, hdr_size); if (type != ARPOP_REPLY) return;
batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY");
- hw_src = batadv_arp_hw_src(skb, 0); - ip_src = batadv_arp_ip_src(skb, 0); - hw_dst = batadv_arp_hw_dst(skb, 0); - ip_dst = batadv_arp_ip_dst(skb, 0); + hw_src = batadv_arp_hw_src(skb, hdr_size); + ip_src = batadv_arp_ip_src(skb, hdr_size); + hw_dst = batadv_arp_hw_dst(skb, hdr_size); + ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src); - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
/* Send the ARP reply to the candidates for both the IP addresses that * the node obtained from the ARP reply @@ -1044,10 +1089,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, __be32 ip_src, ip_dst; uint8_t *hw_src, *hw_dst; bool ret = false; + unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table)) goto out;
+ vid = batadv_dat_get_vid(skb, &hdr_size); + type = batadv_arp_get_type(bat_priv, skb, hdr_size); if (type != ARPOP_REPLY) goto out; @@ -1063,13 +1111,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, /* Update our internal cache with both the IP addresses the node got * within the ARP reply */ - batadv_dat_entry_add(bat_priv, ip_src, hw_src); - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); + batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
/* if this REPLY is directed to a client of mine, let's deliver the * packet to the interface */ - ret = !batadv_is_my_client(bat_priv, hw_dst, BATADV_NO_FLAGS); + ret = !batadv_is_my_client(bat_priv, hw_dst, vid); out: if (ret) kfree_skb(skb); @@ -1092,7 +1140,8 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, __be32 ip_dst; struct batadv_dat_entry *dat_entry = NULL; bool ret = false; - const size_t bcast_len = sizeof(struct batadv_bcast_packet); + int hdr_size = sizeof(struct batadv_bcast_packet); + unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table)) goto out; @@ -1103,12 +1152,14 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, if (forw_packet->num_packets) goto out;
- type = batadv_arp_get_type(bat_priv, forw_packet->skb, bcast_len); + vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size); + + type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size); if (type != ARPOP_REQUEST) goto out;
- ip_dst = batadv_arp_ip_dst(forw_packet->skb, bcast_len); - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); + ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size); + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); /* check if the node already got this entry */ if (!dat_entry) { batadv_dbg(BATADV_DBG_DAT, bat_priv, diff --git a/types.h b/types.h index 20bf2e6..ddeb497 100644 --- a/types.h +++ b/types.h @@ -930,6 +930,7 @@ struct batadv_algo_ops { * is used to stored ARP entries needed for the global DAT cache * @ip: the IPv4 corresponding to this DAT/ARP entry * @mac_addr: the MAC address associated to the stored IPv4 + * @vid: the vlan ID associated to this entry * @last_update: time in jiffies when this entry was refreshed last time * @hash_entry: hlist node for batadv_priv_dat::hash * @refcount: number of contexts the object is used @@ -938,6 +939,7 @@ struct batadv_algo_ops { struct batadv_dat_entry { __be32 ip; uint8_t mac_addr[ETH_ALEN]; + unsigned short vid; unsigned long last_update; struct hlist_node hash_entry; atomic_t refcount;
On Tuesday, April 23, 2013 22:34:34 Antonio Quartulli wrote:
/**
- batadv_dat_get_vid - extract the VLAN identifier from skb if any
- @skb: the buffer containing the packet to extract the VID from
- @hdr_size: the size of the batman-adv header encapsulating the packet
- If the packet contained in skb is vlan tagged then this function
returns the + * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise returns BATADV_NO_FLAGS + */ +static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) +{
struct ethhdr *ethhdr;
struct vlan_ethhdr *vhdr;
unsigned short vid;
ethhdr = (struct ethhdr *)skb->data + *hdr_size;
if (ntohs(ethhdr->h_proto) != ETH_P_8021Q)
return BATADV_NO_FLAGS;
vhdr = (struct vlan_ethhdr *)ethhdr;
vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
vid |= BATADV_VLAN_HAS_TAG;
/* ARP parsing functions jump forward of hdr_size + ETH_HLEN.
* If the header contained in the packet is a VLAN one (which is
longer) + * hdr_size is updated so that the functions will still jump the + * correct amount of bytes
*/
*hdr_size += VLAN_HLEN;
return vid;
+}
This is a very useful function. Why do you make it DAT specific ? The other patches contain the same vid extraction code over and over again. It would make more sense if you added this function with your first patch and make everybody use it.
Cheers, Marek
On Mon, May 06, 2013 at 11:31:00AM +0800, Marek Lindner wrote:
On Tuesday, April 23, 2013 22:34:34 Antonio Quartulli wrote:
/**
- batadv_dat_get_vid - extract the VLAN identifier from skb if any
- @skb: the buffer containing the packet to extract the VID from
- @hdr_size: the size of the batman-adv header encapsulating the packet
- If the packet contained in skb is vlan tagged then this function
returns the + * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise returns BATADV_NO_FLAGS + */ +static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) +{
struct ethhdr *ethhdr;
struct vlan_ethhdr *vhdr;
unsigned short vid;
ethhdr = (struct ethhdr *)skb->data + *hdr_size;
if (ntohs(ethhdr->h_proto) != ETH_P_8021Q)
return BATADV_NO_FLAGS;
vhdr = (struct vlan_ethhdr *)ethhdr;
vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
vid |= BATADV_VLAN_HAS_TAG;
/* ARP parsing functions jump forward of hdr_size + ETH_HLEN.
* If the header contained in the packet is a VLAN one (which is
longer) + * hdr_size is updated so that the functions will still jump the + * correct amount of bytes
*/
*hdr_size += VLAN_HLEN;
return vid;
+}
This is a very useful function. Why do you make it DAT specific ? The other patches contain the same vid extraction code over and over again. It would make more sense if you added this function with your first patch and make everybody use it.
mh, I agree, I simply have to remove the last line (about hdr_size - this is DAT specific) and then I can export it. Ok. Actually I did not introduced this patch before, because most of the code to check for a VID was already in batman-adv and I simply extended it.
Anyhow, will do this in the next iteration.
Thanks
From: Antonio Quartulli antonio@open-mesh.com
Since batman-adv is now fully VLAN-aware, a proper framework able to handle per-vlan-interface attributes is now 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)
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- main.c | 44 ++++++++++++++++++++++++++++++++++++ main.h | 3 +++ soft-interface.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ types.h | 21 +++++++++++++++++ 4 files changed, 137 insertions(+)
diff --git a/main.c b/main.c index 689cf49..d1a049d 100644 --- a/main.c +++ b/main.c @@ -108,6 +108,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->priv_vlan_list_lock);
INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); @@ -117,6 +118,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_LIST_HEAD(&bat_priv->priv_vlan_list);
ret = batadv_originator_init(bat_priv); if (ret < 0) @@ -1099,6 +1101,48 @@ out: batadv_orig_node_free_ref(orig_node); }
+/** + * batadv_priv_vlan_free_ref - decrease vlan refcounter and possibly free it + * @priv_vlan: the vlan object to release + */ +void batadv_priv_vlan_free_ref(struct batadv_priv_vlan *priv_vlan) +{ + if (atomic_dec_and_test(&priv_vlan->refcount)) + kfree_rcu(priv_vlan, rcu); +} + +/** + * batadv_get_priv_vlan - get VLAN priv data + * @bat_priv: the bat priv with all the soft interface information + * @vid: the identifier of the VLAN data to retrieve + * + * Return the private data of the VLAN matching vid and increments its + * refcounter or NULL otherwise. + */ +struct batadv_priv_vlan *batadv_get_priv_vlan(struct batadv_priv *bat_priv, + unsigned short vid) +{ + struct batadv_priv_vlan *vlan, *vlan_tmp = NULL; + + if (!(vid & BATADV_VID_MASK)) + return NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(vlan, &bat_priv->priv_vlan_list, list) { + if (vlan->vid != (vid & BATADV_VID_MASK)) + continue; + + if (!atomic_inc_not_zero(&vlan->refcount)) + continue; + + vlan_tmp = vlan; + break; + } + rcu_read_unlock(); + + return vlan_tmp; +} + static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) { struct batadv_algo_ops *bat_algo_ops; diff --git a/main.h b/main.h index a60ab1b..175c0d1 100644 --- a/main.h +++ b/main.h @@ -196,6 +196,9 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); int batadv_algo_select(struct batadv_priv *bat_priv, char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr); +void batadv_priv_vlan_free_ref(struct batadv_priv_vlan *priv_vlan); +struct batadv_priv_vlan *batadv_get_priv_vlan(struct batadv_priv *bat_priv, + unsigned short vid);
/** * enum batadv_dbg_level - available log levels diff --git a/soft-interface.c b/soft-interface.c index 8911fe5..986e8e5 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -373,6 +373,72 @@ out: return; }
+/** + * batadv_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 + */ +static int batadv_add_vid(struct net_device *dev, unsigned short vid) +{ + struct batadv_priv *bat_priv = netdev_priv(dev); + struct batadv_priv_vlan *vlan; + + vlan = kmalloc(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(dev, dev->dev_addr, vid | BATADV_VLAN_HAS_TAG, + BATADV_NULL_IFINDEX); + + spin_lock_bh(&bat_priv->priv_vlan_list_lock); + list_add_rcu(&vlan->list, &bat_priv->priv_vlan_list); + spin_unlock_bh(&bat_priv->priv_vlan_list_lock); + + return 0; +} + +/** + * batadv_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 + */ +static int batadv_kill_vid(struct net_device *dev, unsigned short vid) +{ + struct batadv_priv *bat_priv = netdev_priv(dev); + struct batadv_priv_vlan *vlan, *vlan_tmp = NULL; + + list_for_each_entry_rcu(vlan, &bat_priv->priv_vlan_list, list) { + if (vlan->vid != vid) + continue; + vlan_tmp = vlan; + break; + } + + spin_lock_bh(&bat_priv->priv_vlan_list_lock); + list_del_rcu(&vlan->list); + spin_unlock_bh(&bat_priv->priv_vlan_list_lock); + + /* explicitly remove the associated TT local entry because it is marked + * with the NOPURGE flag + */ + batadv_tt_local_remove(bat_priv, dev->dev_addr, vid, + "vlan interface destroyed", false); + + 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. @@ -573,6 +639,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_add_vid, + .ndo_vlan_rx_kill_vid = batadv_kill_vid, .ndo_set_mac_address = batadv_interface_set_mac_addr, .ndo_change_mtu = batadv_interface_change_mtu, .ndo_start_xmit = batadv_interface_tx, @@ -611,6 +679,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_FILTER; dev->tx_queue_len = 0;
/* can't call min_mtu, because the needed variables diff --git a/types.h b/types.h index ddeb497..956d66b 100644 --- a/types.h +++ b/types.h @@ -526,6 +526,22 @@ struct batadv_priv_nc { struct batadv_hashtable *decoding_hash; };
+/* + * struct batadv_priv_vlan - per VLAN attributes set + * @vid: VLAN identifier + * @kobj: kobject for sysfs vlan subdirectory + * @list: list node for bat_priv::priv_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_priv_vlan { + unsigned short vid; + struct kobject *kobj; + struct list_head 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) @@ -562,6 +578,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 + * @priv_vlan_list: a list of priv_vlan structs, one per VLAN created on top of + * the mesh interface represented by this object + * @priv_vlan_list_lock: lock protecting priv_vlan_list * @bla: bridge loope avoidance data * @debug_log: holding debug logging relevant data * @gw: gateway data @@ -610,6 +629,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; + spinlock_t priv_vlan_list_lock; /* protects priv_vlan_list */ + struct list_head priv_vlan_list; #ifdef CONFIG_BATMAN_ADV_BLA struct batadv_priv_bla bla; #endif
On Tue, Apr 23, 2013 at 04:34:35PM +0200, Antonio Quartulli wrote:
+/**
- batadv_priv_vlan_free_ref - decrease vlan refcounter and possibly free it
- @priv_vlan: the vlan object to release
- */
+void batadv_priv_vlan_free_ref(struct batadv_priv_vlan *priv_vlan) +{
- if (atomic_dec_and_test(&priv_vlan->refcount))
kfree_rcu(priv_vlan, rcu);
I was just looking at compat.h....I guess this kfree_rcu needs some compat work for kernels older than 3.0.0.
Will add it during the next respin.
Cheers,
From: Antonio Quartulli antonio@open-mesh.com
AP isolation has to be enabled on one VLAN interface only. This patch moves the AP isolation attribute to the per-vlan interface attribute set, enabling it to have a different value depending on the selected vlan.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com --- soft-interface.c | 12 ++++- sysfs.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sysfs.h | 10 ++++ translation-table.c | 24 ++++++--- translation-table.h | 2 +- types.h | 2 + 6 files changed, 182 insertions(+), 8 deletions(-)
diff --git a/soft-interface.c b/soft-interface.c index 986e8e5..5104a8a 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/ethtool.h> #include <linux/etherdevice.h> +#include <linux/netdevice.h> #include <linux/if_vlan.h> #include "bridge_loop_avoidance.h" #include "network-coding.h" @@ -361,7 +362,8 @@ void batadv_interface_rx(struct net_device *soft_iface, batadv_tt_add_temporary_global_entry(bat_priv, orig_node, ethhdr->h_source, vid);
- if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest)) + if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest, + vid)) goto dropped;
netif_rx(skb); @@ -385,6 +387,7 @@ static int batadv_add_vid(struct net_device *dev, unsigned short vid) { struct batadv_priv *bat_priv = netdev_priv(dev); struct batadv_priv_vlan *vlan; + int err;
vlan = kmalloc(sizeof(*vlan), GFP_ATOMIC); if (!vlan) @@ -398,6 +401,11 @@ static int batadv_add_vid(struct net_device *dev, unsigned short vid) */ batadv_tt_local_add(dev, dev->dev_addr, vid | BATADV_VLAN_HAS_TAG, BATADV_NULL_IFINDEX); + atomic_set(&vlan->ap_isolation, 0); + + err = batadv_sysfs_add_vlan(dev, vlan); + if (err) + return err;
spin_lock_bh(&bat_priv->priv_vlan_list_lock); list_add_rcu(&vlan->list, &bat_priv->priv_vlan_list); @@ -430,6 +438,8 @@ static int batadv_kill_vid(struct net_device *dev, unsigned short vid) list_del_rcu(&vlan->list); spin_unlock_bh(&bat_priv->priv_vlan_list_lock);
+ batadv_sysfs_del_vlan(bat_priv, vlan); + /* explicitly remove the associated TT local entry because it is marked * with the NOPURGE flag */ diff --git a/sysfs.c b/sysfs.c index 88f3c73..e554f70 100644 --- a/sysfs.c +++ b/sysfs.c @@ -39,6 +39,31 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj) return netdev_priv(net_dev); }
+/** + * batadv_kobj_to_vlan - convert a kobj in the associated priv_vlan struct + * @obj: kobject to covert + * + * Return the associated priv_vlan struct if cound, NULL otherwise + */ +static struct batadv_priv_vlan *batadv_kobj_to_vlan(struct kobject *obj) +{ + struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(obj->parent); + struct batadv_priv_vlan *vlan, *vlan_tmp = NULL; + + list_for_each_entry_rcu(vlan, &bat_priv->priv_vlan_list, list) { + if (vlan->kobj != obj) + continue; + + if (!atomic_inc_not_zero(&vlan->refcount)) + continue; + + vlan_tmp = vlan; + break; + } + + return vlan_tmp; +} + #define BATADV_UEV_TYPE_VAR "BATTYPE=" #define BATADV_UEV_ACTION_VAR "BATACTION=" #define BATADV_UEV_DATA_VAR "BATDATA=" @@ -53,6 +78,15 @@ static char *batadv_uev_type_str[] = { "gw" };
+/* Use this, if you have customized show and store functions for vlan attrs */ +#define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \ +struct batadv_attribute batadv_attr_vlan_##_name = { \ + .attr = {.name = __stringify(_name), \ + .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + /* Use this, if you have customized show and store functions */ #define BATADV_ATTR(_name, _mode, _show, _store) \ struct batadv_attribute batadv_attr_##_name = { \ @@ -122,6 +156,38 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \ static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ batadv_store_##_name)
+#define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ +ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \ + struct attribute *attr, char *buff, \ + size_t count) \ +{ \ + struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj->parent);\ + struct batadv_priv_vlan *vlan = batadv_kobj_to_vlan(kobj); \ + size_t res = __batadv_store_bool_attr(buff, count, _post_func, attr,\ + &vlan->_name, \ + bat_priv->soft_iface); \ + batadv_priv_vlan_free_ref(vlan); \ + return res; \ +} + +#define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ +ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \ + struct attribute *attr, char *buff) \ +{ \ + struct batadv_priv_vlan *vlan = batadv_kobj_to_vlan(kobj); \ + size_t res = sprintf(buff, "%s\n", \ + atomic_read(&vlan->_name) == 0 ? \ + "disabled" : "enabled"); \ + batadv_priv_vlan_free_ref(vlan); \ + return res; \ +} + +/* Use this, if you are going to turn a [name] in the vlan struct on or off */ +#define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \ + static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ + static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ + static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \ + batadv_store_vlan_##_name)
static int batadv_store_bool_attr(char *buff, size_t count, struct net_device *net_dev, @@ -405,6 +471,17 @@ static struct batadv_attribute *batadv_mesh_attrs[] = { NULL, };
+/* vlan attributes below */ +BATADV_ATTR_VLAN_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); + +/** + * batadv_vlan_attrs - array of vlan specific sysfs attributes + */ +static struct batadv_attribute *batadv_vlan_attrs[] = { + &batadv_attr_vlan_ap_isolation, + NULL, +}; + int batadv_sysfs_add_meshif(struct net_device *dev) { struct kobject *batif_kobject = &dev->dev.kobj; @@ -455,6 +532,69 @@ void batadv_sysfs_del_meshif(struct net_device *dev) bat_priv->mesh_obj = NULL; }
+/** + * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan + * @dev: netdev of the mesh interface + * @vlan: private data of the newly added VLAN interface + * + * Return 0 on success and -ENOMEM if any of the structure allocations fails + */ +int batadv_sysfs_add_vlan(struct net_device *dev, struct batadv_priv_vlan *vlan) +{ + struct batadv_priv *bat_priv = netdev_priv(dev); + struct batadv_attribute **bat_attr; + char vlan_subdir[256]; + int err; + + sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%u", vlan->vid); + + vlan->kobj = kobject_create_and_add(vlan_subdir, bat_priv->mesh_obj); + if (!vlan->kobj) { + batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, + vlan_subdir); + goto out; + } + + for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) { + err = sysfs_create_file(vlan->kobj, + &((*bat_attr)->attr)); + if (err) { + batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", + dev->name, vlan_subdir, + ((*bat_attr)->attr).name); + goto rem_attr; + } + } + + return 0; + +rem_attr: + for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) + sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); + + kobject_put(vlan->kobj); + vlan->kobj = NULL; +out: + return -ENOMEM; +} + +/** + * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN + * @bat_priv: the bat priv with all the soft interface information + * @vlan: the private data of the VLAN to destroy + */ +void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, + struct batadv_priv_vlan *vlan) +{ + struct batadv_attribute **bat_attr; + + for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) + sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); + + kobject_put(vlan->kobj); + vlan->kobj = NULL; +} + static ssize_t batadv_show_mesh_iface(struct kobject *kobj, struct attribute *attr, char *buff) { diff --git a/sysfs.h b/sysfs.h index 479acf4..d105e4b 100644 --- a/sysfs.h +++ b/sysfs.h @@ -22,6 +22,12 @@
#define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" +/** + * BATADV_SYSFS_VLAN_SUBDIR_PREFIX - prefix of the subfolder that will be + * created in the sysfs hierarchy for each VLAN interface. The subfolder will + * be named "BATADV_SYSFS_VLAN_SUBDIR_PREFIX%vid" + */ +#define BATADV_SYSFS_VLAN_SUBDIR_PREFIX "vlan"
struct batadv_attribute { struct attribute attr; @@ -36,6 +42,10 @@ void batadv_sysfs_del_meshif(struct net_device *dev); int batadv_sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev); void batadv_sysfs_del_hardif(struct kobject **hardif_obj); +int batadv_sysfs_add_vlan(struct net_device *dev, + struct batadv_priv_vlan *vlan); +void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, + struct batadv_priv_vlan *vlan); int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, enum batadv_uev_action action, const char *data);
diff --git a/translation-table.c b/translation-table.c index fc4d10e..87c4a44 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1468,12 +1468,26 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid) { + bool ap_isolation_enabled = atomic_read(&bat_priv->ap_isolation); struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; struct batadv_orig_node *orig_node = NULL; struct batadv_tt_orig_list_entry *best_entry; + struct batadv_priv_vlan *vlan;
- if (src && atomic_read(&bat_priv->ap_isolation)) { + /* if the AP isolation is requested on a VLAN, then check for the + * its setting in the proper VLAN private data structure + */ + if (vid & BATADV_VLAN_HAS_TAG) { + ap_isolation_enabled = false; + vlan = batadv_get_priv_vlan(bat_priv, vid); + if (vlan) { + ap_isolation_enabled = atomic_read(&vlan->ap_isolation); + batadv_priv_vlan_free_ref(vlan); + } + } + + if (src && ap_isolation_enabled) { tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); if (!tt_local_entry || (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) @@ -2515,7 +2529,7 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) }
bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, - uint8_t *dst) + uint8_t *dst, unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; @@ -2524,13 +2538,11 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, if (!atomic_read(&bat_priv->ap_isolation)) goto out;
- tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, - BATADV_NO_FLAGS); + tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); if (!tt_local_entry) goto out;
- tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, - BATADV_NO_FLAGS); + tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); if (!tt_global_entry) goto out;
diff --git a/translation-table.h b/translation-table.h index 1944ba5..e86df9b 100644 --- a/translation-table.h +++ b/translation-table.h @@ -46,7 +46,7 @@ void batadv_tt_free(struct batadv_priv *bat_priv); bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, unsigned short vid); bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, - uint8_t *dst); + uint8_t *dst, unsigned short vid); void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, uint8_t *addr, unsigned short vid); diff --git a/types.h b/types.h index 956d66b..8329202 100644 --- a/types.h +++ b/types.h @@ -530,6 +530,7 @@ struct batadv_priv_nc { * struct batadv_priv_vlan - per VLAN attributes set * @vid: VLAN identifier * @kobj: kobject for sysfs vlan subdirectory + * @ap_isolation: AP isolation state * @list: list node for bat_priv::priv_vlan_list * @refcount: number of context where this object is currently in use * @rcu: struct used for freeing in a RCU-safe manner @@ -537,6 +538,7 @@ struct batadv_priv_nc { struct batadv_priv_vlan { unsigned short vid; struct kobject *kobj; + atomic_t ap_isolation; /* boolean */ struct list_head list; atomic_t refcount; struct rcu_head rcu;
b.a.t.m.a.n@lists.open-mesh.org