Commit be1db4f6615b5e6156c807ea8985171c215c2d57

Authored by Antonio Quartulli
Committed by Antonio Quartulli
1 parent bbb877ed77

batman-adv: make the Distributed ARP Table vlan aware

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>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>

Showing 2 changed files with 107 additions and 48 deletions Side-by-side Diff

net/batman-adv/distributed-arp-table.c
... ... @@ -19,6 +19,7 @@
19 19  
20 20 #include <linux/if_ether.h>
21 21 #include <linux/if_arp.h>
  22 +#include <linux/if_vlan.h>
22 23 #include <net/arp.h>
23 24  
24 25 #include "main.h"
25 26  
26 27  
... ... @@ -205,15 +206,11 @@
205 206 */
206 207 static uint32_t batadv_hash_dat(const void *data, uint32_t size)
207 208 {
208   - const unsigned char *key = data;
209 209 uint32_t hash = 0;
210   - size_t i;
  210 + const struct batadv_dat_entry *dat = data;
211 211  
212   - for (i = 0; i < 4; i++) {
213   - hash += key[i];
214   - hash += (hash << 10);
215   - hash ^= (hash >> 6);
216   - }
  212 + hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip));
  213 + hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid));
217 214  
218 215 hash += (hash << 3);
219 216 hash ^= (hash >> 11);
220 217  
221 218  
222 219  
... ... @@ -227,21 +224,26 @@
227 224 * table
228 225 * @bat_priv: the bat priv with all the soft interface information
229 226 * @ip: search key
  227 + * @vid: VLAN identifier
230 228 *
231 229 * Returns the dat_entry if found, NULL otherwise.
232 230 */
233 231 static struct batadv_dat_entry *
234   -batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip)
  232 +batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
  233 + unsigned short vid)
235 234 {
236 235 struct hlist_head *head;
237   - struct batadv_dat_entry *dat_entry, *dat_entry_tmp = NULL;
  236 + struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL;
238 237 struct batadv_hashtable *hash = bat_priv->dat.hash;
239 238 uint32_t index;
240 239  
241 240 if (!hash)
242 241 return NULL;
243 242  
244   - index = batadv_hash_dat(&ip, hash->size);
  243 + to_find.ip = ip;
  244 + to_find.vid = vid;
  245 +
  246 + index = batadv_hash_dat(&to_find, hash->size);
245 247 head = &hash->table[index];
246 248  
247 249 rcu_read_lock();
248 250  
249 251  
250 252  
... ... @@ -265,22 +267,24 @@
265 267 * @bat_priv: the bat priv with all the soft interface information
266 268 * @ip: ipv4 to add/edit
267 269 * @mac_addr: mac address to assign to the given ipv4
  270 + * @vid: VLAN identifier
268 271 */
269 272 static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
270   - uint8_t *mac_addr)
  273 + uint8_t *mac_addr, unsigned short vid)
271 274 {
272 275 struct batadv_dat_entry *dat_entry;
273 276 int hash_added;
274 277  
275   - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip);
  278 + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
276 279 /* if this entry is already known, just update it */
277 280 if (dat_entry) {
278 281 if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
279 282 memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
280 283 dat_entry->last_update = jiffies;
281 284 batadv_dbg(BATADV_DBG_DAT, bat_priv,
282   - "Entry updated: %pI4 %pM\n", &dat_entry->ip,
283   - dat_entry->mac_addr);
  285 + "Entry updated: %pI4 %pM (vid: %d)\n",
  286 + &dat_entry->ip, dat_entry->mac_addr,
  287 + BATADV_PRINT_VID(vid));
284 288 goto out;
285 289 }
286 290  
287 291  
... ... @@ -289,12 +293,13 @@
289 293 goto out;
290 294  
291 295 dat_entry->ip = ip;
  296 + dat_entry->vid = vid;
292 297 memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
293 298 dat_entry->last_update = jiffies;
294 299 atomic_set(&dat_entry->refcount, 2);
295 300  
296 301 hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat,
297   - batadv_hash_dat, &dat_entry->ip,
  302 + batadv_hash_dat, dat_entry,
298 303 &dat_entry->hash_entry);
299 304  
300 305 if (unlikely(hash_added != 0)) {
... ... @@ -303,8 +308,8 @@
303 308 goto out;
304 309 }
305 310  
306   - batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM\n",
307   - &dat_entry->ip, dat_entry->mac_addr);
  311 + batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n",
  312 + &dat_entry->ip, dat_entry->mac_addr, BATADV_PRINT_VID(vid));
308 313  
309 314 out:
310 315 if (dat_entry)
... ... @@ -756,8 +761,8 @@
756 761 goto out;
757 762  
758 763 seq_printf(seq, "Distributed ARP Table (%s):\n", net_dev->name);
759   - seq_printf(seq, " %-7s %-13s %5s\n", "IPv4", "MAC",
760   - "last-seen");
  764 + seq_printf(seq, " %-7s %-9s %4s %11s\n", "IPv4",
  765 + "MAC", "VID", "last-seen");
761 766  
762 767 for (i = 0; i < hash->size; i++) {
763 768 head = &hash->table[i];
764 769  
... ... @@ -770,8 +775,9 @@
770 775 last_seen_msecs = last_seen_msecs % 60000;
771 776 last_seen_secs = last_seen_msecs / 1000;
772 777  
773   - seq_printf(seq, " * %15pI4 %14pM %6i:%02i\n",
  778 + seq_printf(seq, " * %15pI4 %14pM %4i %6i:%02i\n",
774 779 &dat_entry->ip, dat_entry->mac_addr,
  780 + BATADV_PRINT_VID(dat_entry->vid),
775 781 last_seen_mins, last_seen_secs);
776 782 }
777 783 rcu_read_unlock();
... ... @@ -858,6 +864,31 @@
858 864 }
859 865  
860 866 /**
  867 + * batadv_dat_get_vid - extract the VLAN identifier from skb if any
  868 + * @skb: the buffer containing the packet to extract the VID from
  869 + * @hdr_size: the size of the batman-adv header encapsulating the packet
  870 + *
  871 + * If the packet embedded in the skb is vlan tagged this function returns the
  872 + * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned.
  873 + */
  874 +static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size)
  875 +{
  876 + unsigned short vid;
  877 +
  878 + vid = batadv_get_vid(skb, *hdr_size);
  879 +
  880 + /* ARP parsing functions jump forward of hdr_size + ETH_HLEN.
  881 + * If the header contained in the packet is a VLAN one (which is longer)
  882 + * hdr_size is updated so that the functions will still skip the
  883 + * correct amount of bytes.
  884 + */
  885 + if (vid & BATADV_VLAN_HAS_TAG)
  886 + *hdr_size += VLAN_HLEN;
  887 +
  888 + return vid;
  889 +}
  890 +
  891 +/**
861 892 * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to
862 893 * answer using DAT
863 894 * @bat_priv: the bat priv with all the soft interface information
864 895  
865 896  
866 897  
867 898  
868 899  
... ... @@ -876,26 +907,31 @@
876 907 bool ret = false;
877 908 struct batadv_dat_entry *dat_entry = NULL;
878 909 struct sk_buff *skb_new;
  910 + int hdr_size = 0;
  911 + unsigned short vid;
879 912  
880 913 if (!atomic_read(&bat_priv->distributed_arp_table))
881 914 goto out;
882 915  
883   - type = batadv_arp_get_type(bat_priv, skb, 0);
  916 + vid = batadv_dat_get_vid(skb, &hdr_size);
  917 +
  918 + type = batadv_arp_get_type(bat_priv, skb, hdr_size);
884 919 /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast
885 920 * message to the selected DHT candidates
886 921 */
887 922 if (type != ARPOP_REQUEST)
888 923 goto out;
889 924  
890   - batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REQUEST");
  925 + batadv_dbg_arp(bat_priv, skb, type, hdr_size,
  926 + "Parsing outgoing ARP REQUEST");
891 927  
892   - ip_src = batadv_arp_ip_src(skb, 0);
893   - hw_src = batadv_arp_hw_src(skb, 0);
894   - ip_dst = batadv_arp_ip_dst(skb, 0);
  928 + ip_src = batadv_arp_ip_src(skb, hdr_size);
  929 + hw_src = batadv_arp_hw_src(skb, hdr_size);
  930 + ip_dst = batadv_arp_ip_dst(skb, hdr_size);
895 931  
896   - batadv_dat_entry_add(bat_priv, ip_src, hw_src);
  932 + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
897 933  
898   - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
  934 + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
899 935 if (dat_entry) {
900 936 /* If the ARP request is destined for a local client the local
901 937 * client will answer itself. DAT would only generate a
902 938  
... ... @@ -917,11 +953,15 @@
917 953 if (!skb_new)
918 954 goto out;
919 955  
  956 + if (vid & BATADV_VLAN_HAS_TAG)
  957 + skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
  958 + vid & VLAN_VID_MASK);
  959 +
920 960 skb_reset_mac_header(skb_new);
921 961 skb_new->protocol = eth_type_trans(skb_new,
922 962 bat_priv->soft_iface);
923 963 bat_priv->stats.rx_packets++;
924   - bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
  964 + bat_priv->stats.rx_bytes += skb->len + ETH_HLEN + hdr_size;
925 965 bat_priv->soft_iface->last_rx = jiffies;
926 966  
927 967 netif_rx(skb_new);
928 968  
... ... @@ -956,11 +996,14 @@
956 996 struct sk_buff *skb_new;
957 997 struct batadv_dat_entry *dat_entry = NULL;
958 998 bool ret = false;
  999 + unsigned short vid;
959 1000 int err;
960 1001  
961 1002 if (!atomic_read(&bat_priv->distributed_arp_table))
962 1003 goto out;
963 1004  
  1005 + vid = batadv_dat_get_vid(skb, &hdr_size);
  1006 +
964 1007 type = batadv_arp_get_type(bat_priv, skb, hdr_size);
965 1008 if (type != ARPOP_REQUEST)
966 1009 goto out;
967 1010  
... ... @@ -972,9 +1015,9 @@
972 1015 batadv_dbg_arp(bat_priv, skb, type, hdr_size,
973 1016 "Parsing incoming ARP REQUEST");
974 1017  
975   - batadv_dat_entry_add(bat_priv, ip_src, hw_src);
  1018 + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
976 1019  
977   - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
  1020 + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
978 1021 if (!dat_entry)
979 1022 goto out;
980 1023  
... ... @@ -985,6 +1028,10 @@
985 1028 if (!skb_new)
986 1029 goto out;
987 1030  
  1031 + if (vid & BATADV_VLAN_HAS_TAG)
  1032 + skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
  1033 + vid & VLAN_VID_MASK);
  1034 +
988 1035 /* To preserve backwards compatibility, the node has choose the outgoing
989 1036 * format based on the incoming request packet type. The assumption is
990 1037 * that a node not using the 4addr packet format doesn't support it.
991 1038  
... ... @@ -992,10 +1039,9 @@
992 1039 if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
993 1040 err = batadv_send_skb_unicast_4addr(bat_priv, skb_new,
994 1041 BATADV_P_DAT_CACHE_REPLY,
995   - BATADV_NO_FLAGS);
  1042 + vid);
996 1043 else
997   - err = batadv_send_skb_unicast(bat_priv, skb_new,
998   - BATADV_NO_FLAGS);
  1044 + err = batadv_send_skb_unicast(bat_priv, skb_new, vid);
999 1045  
1000 1046 if (!err) {
1001 1047 batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
1002 1048  
1003 1049  
1004 1050  
1005 1051  
... ... @@ -1020,23 +1066,28 @@
1020 1066 uint16_t type;
1021 1067 __be32 ip_src, ip_dst;
1022 1068 uint8_t *hw_src, *hw_dst;
  1069 + int hdr_size = 0;
  1070 + unsigned short vid;
1023 1071  
1024 1072 if (!atomic_read(&bat_priv->distributed_arp_table))
1025 1073 return;
1026 1074  
1027   - type = batadv_arp_get_type(bat_priv, skb, 0);
  1075 + vid = batadv_dat_get_vid(skb, &hdr_size);
  1076 +
  1077 + type = batadv_arp_get_type(bat_priv, skb, hdr_size);
1028 1078 if (type != ARPOP_REPLY)
1029 1079 return;
1030 1080  
1031   - batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY");
  1081 + batadv_dbg_arp(bat_priv, skb, type, hdr_size,
  1082 + "Parsing outgoing ARP REPLY");
1032 1083  
1033   - hw_src = batadv_arp_hw_src(skb, 0);
1034   - ip_src = batadv_arp_ip_src(skb, 0);
1035   - hw_dst = batadv_arp_hw_dst(skb, 0);
1036   - ip_dst = batadv_arp_ip_dst(skb, 0);
  1084 + hw_src = batadv_arp_hw_src(skb, hdr_size);
  1085 + ip_src = batadv_arp_ip_src(skb, hdr_size);
  1086 + hw_dst = batadv_arp_hw_dst(skb, hdr_size);
  1087 + ip_dst = batadv_arp_ip_dst(skb, hdr_size);
1037 1088  
1038   - batadv_dat_entry_add(bat_priv, ip_src, hw_src);
1039   - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst);
  1089 + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
  1090 + batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
1040 1091  
1041 1092 /* Send the ARP reply to the candidates for both the IP addresses that
1042 1093 * the node obtained from the ARP reply
1043 1094  
... ... @@ -1058,10 +1109,13 @@
1058 1109 __be32 ip_src, ip_dst;
1059 1110 uint8_t *hw_src, *hw_dst;
1060 1111 bool ret = false;
  1112 + unsigned short vid;
1061 1113  
1062 1114 if (!atomic_read(&bat_priv->distributed_arp_table))
1063 1115 goto out;
1064 1116  
  1117 + vid = batadv_dat_get_vid(skb, &hdr_size);
  1118 +
1065 1119 type = batadv_arp_get_type(bat_priv, skb, hdr_size);
1066 1120 if (type != ARPOP_REPLY)
1067 1121 goto out;
1068 1122  
... ... @@ -1077,13 +1131,13 @@
1077 1131 /* Update our internal cache with both the IP addresses the node got
1078 1132 * within the ARP reply
1079 1133 */
1080   - batadv_dat_entry_add(bat_priv, ip_src, hw_src);
1081   - batadv_dat_entry_add(bat_priv, ip_dst, hw_dst);
  1134 + batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
  1135 + batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
1082 1136  
1083 1137 /* if this REPLY is directed to a client of mine, let's deliver the
1084 1138 * packet to the interface
1085 1139 */
1086   - ret = !batadv_is_my_client(bat_priv, hw_dst, BATADV_NO_FLAGS);
  1140 + ret = !batadv_is_my_client(bat_priv, hw_dst, vid);
1087 1141 out:
1088 1142 if (ret)
1089 1143 kfree_skb(skb);
... ... @@ -1106,7 +1160,8 @@
1106 1160 __be32 ip_dst;
1107 1161 struct batadv_dat_entry *dat_entry = NULL;
1108 1162 bool ret = false;
1109   - const size_t bcast_len = sizeof(struct batadv_bcast_packet);
  1163 + int hdr_size = sizeof(struct batadv_bcast_packet);
  1164 + unsigned short vid;
1110 1165  
1111 1166 if (!atomic_read(&bat_priv->distributed_arp_table))
1112 1167 goto out;
1113 1168  
... ... @@ -1117,12 +1172,14 @@
1117 1172 if (forw_packet->num_packets)
1118 1173 goto out;
1119 1174  
1120   - type = batadv_arp_get_type(bat_priv, forw_packet->skb, bcast_len);
  1175 + vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);
  1176 +
  1177 + type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size);
1121 1178 if (type != ARPOP_REQUEST)
1122 1179 goto out;
1123 1180  
1124   - ip_dst = batadv_arp_ip_dst(forw_packet->skb, bcast_len);
1125   - dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
  1181 + ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size);
  1182 + dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
1126 1183 /* check if the node already got this entry */
1127 1184 if (!dat_entry) {
1128 1185 batadv_dbg(BATADV_DBG_DAT, bat_priv,
net/batman-adv/types.h
... ... @@ -933,6 +933,7 @@
933 933 * is used to stored ARP entries needed for the global DAT cache
934 934 * @ip: the IPv4 corresponding to this DAT/ARP entry
935 935 * @mac_addr: the MAC address associated to the stored IPv4
  936 + * @vid: the vlan ID associated to this entry
936 937 * @last_update: time in jiffies when this entry was refreshed last time
937 938 * @hash_entry: hlist node for batadv_priv_dat::hash
938 939 * @refcount: number of contexts the object is used
... ... @@ -941,6 +942,7 @@
941 942 struct batadv_dat_entry {
942 943 __be32 ip;
943 944 uint8_t mac_addr[ETH_ALEN];
  945 + unsigned short vid;
944 946 unsigned long last_update;
945 947 struct hlist_node hash_entry;
946 948 atomic_t refcount;