[B.A.T.M.A.N.] [PATCH][RFC] batctl: add IPv6 support to tcpdump parsing capabilities
by Marco Dalla Torre
Extends 'tcpdump' functionality in 'batctl' to parse and report IPv6
communications. 'batctl' now recognizes TCP, UDP packets and the most
common ICMPv6 packet types:
-ECHO request and ECHO reply
-unreachable destination and subcases
-time exceeded
-neighbor discovery protocol 'solicit' and 'advert'
TCP and UDP parsing code has been moved from the IPv4 specific
codepath to separate functions in order to allow reuse regardless
the underlying protocol.
Signed-off-by: Marco Dalla Torre <marco.dallato(a)gmail.com>
---
tcpdump.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 230 insertions(+), 40 deletions(-)
diff --git a/tcpdump.c b/tcpdump.c
index 7e0987b..6dc49ac 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -32,9 +32,11 @@
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
#include <netinet/if_ether.h>
#include "main.h"
@@ -47,6 +49,8 @@
#define ETH_P_BATMAN 0x4305
#endif /* ETH_P_BATMAN */
+#define IPV6_MIN_MTU 1280
+
#define LEN_CHECK(buff_len, check_len, desc) \
if ((size_t)(buff_len) < (check_len)) { \
fprintf(stderr, "Warning - dropping received %s packet as it is smaller than expected (%zu): %zu\n", \
@@ -188,11 +192,219 @@ static void dump_arp(unsigned char *packet_buff, ssize_t buff_len,
}
}
+static void parse_tcp(
+ unsigned char *packet_buff,
+ ssize_t buff_len,
+ size_t header_len,
+ char *src_addr,
+ char *dst_addr)
+{
+ LEN_CHECK((size_t)buff_len - header_len,
+ sizeof(struct tcphdr), "TCP");
+ struct tcphdr *tcphdr;
+
+ tcphdr = (struct tcphdr *)(packet_buff + header_len);
+ printf("IP %s.%i > ", src_addr, ntohs(tcphdr->source));
+ printf("%s.%i: TCP, flags [%c%c%c%c%c%c], length %zu\n",
+ dst_addr, ntohs(tcphdr->dest),
+ (tcphdr->fin ? 'F' : '.'), (tcphdr->syn ? 'S' : '.'),
+ (tcphdr->rst ? 'R' : '.'), (tcphdr->psh ? 'P' : '.'),
+ (tcphdr->ack ? 'A' : '.'), (tcphdr->urg ? 'U' : '.'),
+ (size_t)buff_len - header_len - sizeof(struct tcphdr));
+}
+
+static void parse_udp(
+ unsigned char *packet_buff,
+ ssize_t buff_len,
+ size_t header_len,
+ char *src_addr,
+ char *dst_addr)
+{
+ LEN_CHECK((size_t)buff_len - header_len, sizeof(struct udphdr), "UDP");
+ struct udphdr *udphdr;
+
+ udphdr = (struct udphdr *)(packet_buff + header_len);
+ printf("IP %s.%i > ",
+ src_addr,
+ ntohs(udphdr->source));
+
+ switch (ntohs(udphdr->dest)) {
+ case 67:
+ LEN_CHECK(
+ (size_t)buff_len - header_len - sizeof(struct udphdr),
+ (size_t) 44,
+ "DHCP");
+ printf("%s.67: BOOTP/DHCP, Request from %s, length %zu\n",
+ dst_addr,
+ ether_ntoa_long(
+ (struct ether_addr *)(((char *)udphdr)
+ + sizeof(struct udphdr) + 28)),
+ (size_t)buff_len - header_len - sizeof(struct udphdr));
+ break;
+ case 68:
+ printf("%s.68: BOOTP/DHCP, Reply, length %zu\n",
+ dst_addr,
+ (size_t)buff_len - header_len - sizeof(struct udphdr));
+ break;
+ default:
+ printf("%s.%i: UDP, length %zu\n",
+ dst_addr,
+ ntohs(udphdr->dest),
+ (size_t)buff_len - header_len - sizeof(struct udphdr));
+ break;
+ }
+}
+
+static void dump_ipv6(
+ unsigned char *packet_buff,
+ ssize_t buff_len,
+ int time_printed)
+{
+ struct ip6_hdr *iphdr, *tmp_iphdr;
+ struct udphdr *tmp_udphdr;
+ struct icmp6_hdr *icmphdr;
+
+ iphdr = (struct ip6_hdr *)packet_buff;
+ LEN_CHECK((size_t)buff_len, (size_t)(sizeof(struct ip6_hdr)), "IPv6");
+
+ if (!time_printed)
+ print_time();
+
+ switch (iphdr->ip6_nxt) {
+ case IPPROTO_ICMPV6:
+ LEN_CHECK(
+ (size_t)buff_len - (size_t)(sizeof(struct ip6_hdr)),
+ sizeof(struct icmp6_hdr),
+ "ICMPv6");
+
+ icmphdr = (struct icmp6_hdr *)(packet_buff + sizeof(struct ip6_hdr));
+ char tmp_ipv6_addr[40];
+ inet_ntop(AF_INET6, &(iphdr->ip6_src), tmp_ipv6_addr, 40);
+ printf("IPv6 %s > ", tmp_ipv6_addr);
+ switch (icmphdr->icmp6_type) {
+ case ICMP6_DST_UNREACH:
+ if ((size_t)(buff_len) < IPV6_MIN_MTU) {
+ fprintf(stderr,
+ "Warning - dropping received 'ICMPv6 destination unreached' packet as it is bigger than maximum allowed size (%u): %zu\n",
+ IPV6_MIN_MTU, (size_t)(buff_len));
+ return;
+ }
+
+ switch (icmphdr->icmp6_code) {
+ case ICMP6_DST_UNREACH_NOPORT:
+ tmp_iphdr = (struct ip6_hdr *)(((char *)icmphdr)
+ + sizeof(struct icmp6_hdr));
+
+ tmp_udphdr = (struct udphdr *)((char *)tmp_iphdr)
+ + sizeof(struct ip6_hdr);
+
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s: ICMP ", tmp_ipv6_addr);
+ inet_ntop(AF_INET6, &(tmp_iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s udp port %hu unreachable, length %zu\n",
+ tmp_ipv6_addr,
+ ntohs(tmp_udphdr->dest),
+ (size_t)buff_len - sizeof(struct ip6_hdr));
+ break;
+ default:
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s: ICMP unreachable %hhu, length %zu\n",
+ tmp_ipv6_addr,
+ icmphdr->icmp6_code,
+ (size_t)buff_len - sizeof(struct icmp6_hdr));
+ }
+ break;
+ case ICMP6_ECHO_REQUEST:
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s: ICMPv6 echo request, id: %d, seq: %d, length: %hu\n",
+ tmp_ipv6_addr,
+ icmphdr->icmp6_id,
+ icmphdr->icmp6_seq,
+ iphdr->ip6_plen);
+ break;
+ case ICMP6_ECHO_REPLY:
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s: ICMPv6 echo reply, id: %d, seq: %d, length: %hu\n",
+ tmp_ipv6_addr,
+ icmphdr->icmp6_id,
+ icmphdr->icmp6_seq,
+ iphdr->ip6_plen);
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s: ICMPv6 time exceeded in-transit, length %zu\n",
+ tmp_ipv6_addr,
+ (size_t)buff_len - sizeof(struct icmp6_hdr));
+ break;
+ case ND_NEIGHBOR_SOLICIT:
+ ;
+ struct nd_neighbor_solicit *tmp_ns =
+ (struct nd_neighbor_solicit *)icmphdr;
+
+ inet_ntop(AF_INET6, &(tmp_ns->nd_ns_target), tmp_ipv6_addr, 40);
+ printf("NEIGHBOR SOLICITATION, Request who-has %s", tmp_ipv6_addr);
+
+ inet_ntop(AF_INET6, &(iphdr->ip6_src), tmp_ipv6_addr, 40);
+ printf(" tell %s, length %zd\n",
+ tmp_ipv6_addr,
+ buff_len);
+ break;
+ case ND_NEIGHBOR_ADVERT:
+ ;
+ struct nd_neighbor_advert *tmp_ns2 =
+ (struct nd_neighbor_advert *)icmphdr;
+ char tmp_na_target[40];
+
+ inet_ntop(AF_INET6, &(tmp_ns2->nd_na_target), tmp_na_target, 40);
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("NEIGHBOR ADVERTISEMENT, Reply to %s for target %s, length %zd\n",
+ tmp_na_target,
+ tmp_ipv6_addr,
+ buff_len);
+ break;
+ default:
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_ipv6_addr, 40);
+ printf("%s: ICMPv6 type %hhu, length %zu\n",
+ tmp_ipv6_addr,
+ icmphdr->icmp6_type,
+ (size_t)buff_len - sizeof(struct icmp6_hdr));
+ }
+ break;
+ case IPPROTO_TCP:
+ ;
+ char tmp_saddr_t[40];
+ char tmp_daddr_t[40];
+ inet_ntop(AF_INET6, &(iphdr->ip6_src), tmp_saddr_t, 40);
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_daddr_t, 40);
+ parse_tcp(
+ packet_buff,
+ buff_len,
+ sizeof(struct ip6_hdr),
+ tmp_saddr_t,
+ tmp_daddr_t);
+ break;
+ case IPPROTO_UDP:
+ ;
+ char tmp_saddr_u[40];
+ char tmp_daddr_u[40];
+ inet_ntop(AF_INET6, &(iphdr->ip6_src), tmp_saddr_u, 40);
+ inet_ntop(AF_INET6, &(iphdr->ip6_dst), tmp_daddr_u, 40);
+ parse_udp(
+ packet_buff,
+ buff_len,
+ sizeof(struct ip6_hdr),
+ tmp_saddr_u,
+ tmp_daddr_u);
+ break;
+ default:
+ printf("IPv6 unknown protocol: %i\n", iphdr->ip6_nxt);
+ }
+}
+
static void dump_ip(unsigned char *packet_buff, ssize_t buff_len, int time_printed)
{
struct iphdr *iphdr, *tmp_iphdr;
- struct tcphdr *tcphdr;
- struct udphdr *udphdr, *tmp_udphdr;
+ struct udphdr *tmp_udphdr;
struct icmphdr *icmphdr;
iphdr = (struct iphdr *)packet_buff;
@@ -257,46 +469,20 @@ static void dump_ip(unsigned char *packet_buff, ssize_t buff_len, int time_print
break;
case IPPROTO_TCP:
- LEN_CHECK((size_t)buff_len - (iphdr->ihl * 4), sizeof(struct tcphdr), "TCP");
-
- tcphdr = (struct tcphdr *)(packet_buff + (iphdr->ihl * 4));
- printf("IP %s.%i > ", inet_ntoa(*(struct in_addr *)&iphdr->saddr), ntohs(tcphdr->source));
- printf("%s.%i: TCP, flags [%c%c%c%c%c%c], length %zu\n",
- inet_ntoa(*(struct in_addr *)&iphdr->daddr), ntohs(tcphdr->dest),
- (tcphdr->fin ? 'F' : '.'), (tcphdr->syn ? 'S' : '.'),
- (tcphdr->rst ? 'R' : '.'), (tcphdr->psh ? 'P' : '.'),
- (tcphdr->ack ? 'A' : '.'), (tcphdr->urg ? 'U' : '.'),
- (size_t)buff_len - (iphdr->ihl * 4) - sizeof(struct tcphdr));
+ parse_tcp(
+ packet_buff,
+ buff_len,
+ iphdr->ihl * 4,
+ inet_ntoa(*(struct in_addr *)&iphdr->saddr),
+ inet_ntoa(*(struct in_addr *)&iphdr->daddr));
break;
case IPPROTO_UDP:
- LEN_CHECK((size_t)buff_len - (iphdr->ihl * 4), sizeof(struct udphdr), "UDP");
-
- udphdr = (struct udphdr *)(packet_buff + (iphdr->ihl * 4));
- printf("IP %s.%i > ", inet_ntoa(*(struct in_addr *)&iphdr->saddr), ntohs(udphdr->source));
-
- switch (ntohs(udphdr->dest)) {
- case 67:
- LEN_CHECK((size_t)buff_len - (iphdr->ihl * 4) - sizeof(struct udphdr), (size_t) 44, "DHCP");
- printf("%s.67: BOOTP/DHCP, Request from %s, length %zu\n",
- inet_ntoa(*(struct in_addr *)&iphdr->daddr),
- ether_ntoa_long((struct ether_addr *)(((char *)udphdr) + sizeof(struct udphdr) + 28)),
- (size_t)buff_len - (iphdr->ihl * 4) - sizeof(struct udphdr));
- break;
- case 68:
- printf("%s.68: BOOTP/DHCP, Reply, length %zu\n",
- inet_ntoa(*(struct in_addr *)&iphdr->daddr),
- (size_t)buff_len - (iphdr->ihl * 4) - sizeof(struct udphdr));
- break;
- default:
- printf("%s.%i: UDP, length %zu\n",
- inet_ntoa(*(struct in_addr *)&iphdr->daddr), ntohs(udphdr->dest),
- (size_t)buff_len - (iphdr->ihl * 4) - sizeof(struct udphdr));
- break;
- }
-
- break;
- case IPPROTO_IPV6:
- printf("IP6: not implemented yet\n");
+ parse_udp(
+ packet_buff,
+ buff_len,
+ iphdr->ihl * 4,
+ inet_ntoa(*(struct in_addr *)&iphdr->saddr),
+ inet_ntoa(*(struct in_addr *)&iphdr->daddr));
break;
default:
printf("IP unknown protocol: %i\n", iphdr->protocol);
@@ -497,6 +683,10 @@ static void parse_eth_hdr(unsigned char *packet_buff, ssize_t buff_len, int read
if ((dump_level & DUMP_TYPE_NONBAT) || (time_printed))
dump_ip(packet_buff + ETH_HLEN, buff_len - ETH_HLEN, time_printed);
break;
+ case ETH_P_IPV6:
+ if ((dump_level & DUMP_TYPE_NONBAT) || (time_printed))
+ dump_ipv6(packet_buff + ETH_HLEN, buff_len - ETH_HLEN, time_printed);
+ break;
case ETH_P_8021Q:
if ((dump_level & DUMP_TYPE_NONBAT) || (time_printed))
dump_vlan(packet_buff, buff_len, read_opt, time_printed);
--
1.8.3.2
7 years, 6 months
[B.A.T.M.A.N.] [PATCHv2] batman-adv: limit local translation table max size
by Marek Lindner
The local translation table size is limited by what can be
transferred from one node to another via a full table request.
The number of entries fitting into a full table request depend
on whether the fragmentation is enabled or not. Therefore this
patch introduces a max table size check and refuses to add
more local clients when that size is reached. Moreover, if the
max full table packet size changes (MTU change or fragmentation
is disabled) the local table is downsized instantaneously.
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
---
hard-interface.c | 41 ++++++++------
soft-interface.c | 12 +++--
translation-table.c | 148 +++++++++++++++++++++++++++++++++++++++++++++------
translation-table.h | 3 +-
types.h | 3 ++
5 files changed, 172 insertions(+), 35 deletions(-)
Changes since v1:
* sort variable declaration by line length
* re-adding tt_diff_len check
diff --git a/hard-interface.c b/hard-interface.c
index c5f871f..c60d3ed 100644
--- a/hard-interface.c
+++ b/hard-interface.c
@@ -266,16 +266,9 @@ static void batadv_check_known_mac_addr(const struct net_device *net_dev)
int batadv_hardif_min_mtu(struct net_device *soft_iface)
{
- const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
+ struct batadv_priv *bat_priv = netdev_priv(soft_iface);
const struct batadv_hard_iface *hard_iface;
- /* allow big frames if all devices are capable to do so
- * (have MTU > 1500 + batadv_max_header_len())
- */
int min_mtu = ETH_DATA_LEN;
- int max_header_len = batadv_max_header_len();
-
- if (atomic_read(&bat_priv->fragmentation))
- goto out;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
@@ -286,22 +279,40 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
if (hard_iface->soft_iface != soft_iface)
continue;
- min_mtu = min_t(int, hard_iface->net_dev->mtu - max_header_len,
- min_mtu);
+ min_mtu = min_t(int, hard_iface->net_dev->mtu, min_mtu);
}
rcu_read_unlock();
+
+ atomic_set(&bat_priv->packet_size_max, min_mtu);
+
+ if (atomic_read(&bat_priv->fragmentation) == 0)
+ goto out;
+
+ /* with fragmentation enabled the maximum size of internally generated
+ * packets such as translation table exchanges or tvlv containers, etc
+ * has to be calculated
+ */
+ min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE);
+ min_mtu -= sizeof(struct batadv_frag_packet);
+ min_mtu *= BATADV_FRAG_MAX_FRAGMENTS;
+ atomic_set(&bat_priv->packet_size_max, min_mtu);
+
+ /* with fragmentation enabled we can fragment external packets easily */
+ min_mtu = min_t(int, min_mtu, ETH_DATA_LEN);
+
out:
- return min_mtu;
+ return min_mtu - batadv_max_header_len();
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
void batadv_update_min_mtu(struct net_device *soft_iface)
{
- int min_mtu;
+ soft_iface->mtu = batadv_hardif_min_mtu(soft_iface);
- min_mtu = batadv_hardif_min_mtu(soft_iface);
- if (soft_iface->mtu != min_mtu)
- soft_iface->mtu = min_mtu;
+ /* Check if the local translate table should be cleaned up to match a
+ * new (and smaller) MTU.
+ */
+ batadv_tt_local_resize_to_mtu(soft_iface);
}
static void
diff --git a/soft-interface.c b/soft-interface.c
index bafc811..a1f00e8 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -166,7 +166,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
unsigned int header_len = 0;
int data_len = skb->len, ret;
unsigned long brd_delay = 1;
- bool do_bcast = false;
+ bool do_bcast = false, client_added;
unsigned short vid;
uint32_t seqno;
@@ -196,9 +196,12 @@ static int batadv_interface_tx(struct sk_buff *skb,
ethhdr = (struct ethhdr *)skb->data;
/* Register the client MAC in the transtable */
- if (!is_multicast_ether_addr(ethhdr->h_source))
- batadv_tt_local_add(soft_iface, ethhdr->h_source, vid,
- skb->skb_iif);
+ if (!is_multicast_ether_addr(ethhdr->h_source)) {
+ client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
+ vid, skb->skb_iif);
+ if (!client_added)
+ goto dropped;
+ }
/* don't accept stp packets. STP does not help in meshes.
* better use the bridge loop avoidance ...
@@ -674,6 +677,7 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->log_level, 0);
#endif
atomic_set(&bat_priv->fragmentation, 1);
+ atomic_set(&bat_priv->packet_size_max, ETH_DATA_LEN);
atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN);
atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN);
diff --git a/translation-table.c b/translation-table.c
index 2b4d9ed..e1b6f46 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -401,6 +401,35 @@ static uint16_t batadv_tt_entries(uint16_t tt_len)
return tt_len / batadv_tt_len(1);
}
+/**
+ * batadv_tt_local_table_transmit_size - calculates the local translation table
+ * size when transmitted over the air
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns local translation table size in bytes.
+ */
+static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
+{
+ uint16_t num_vlan = 0, tt_local_entries = 0;
+ struct batadv_softif_vlan *vlan;
+ int hdr_size;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+ num_vlan++;
+ tt_local_entries += atomic_read(&vlan->tt.num_entries);
+ }
+ rcu_read_unlock();
+
+ /* header size of tvlv encapsulated tt response payload */
+ hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
+ hdr_size += sizeof(struct batadv_tvlv_hdr);
+ hdr_size += sizeof(struct batadv_tvlv_tt_data);
+ hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
+
+ return hdr_size + batadv_tt_len(tt_local_entries);
+}
+
static int batadv_tt_local_init(struct batadv_priv *bat_priv)
{
if (bat_priv->tt.local_hash)
@@ -439,8 +468,10 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
* @vid: VLAN identifier
* @ifindex: index of the interface where the client is connected to (useful to
* identify wireless clients)
+ *
+ * Returns true if the client was successfully added, false otherwise.
*/
-void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
unsigned short vid, int ifindex)
{
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
@@ -448,8 +479,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
struct batadv_tt_global_entry *tt_global;
struct hlist_head *head;
struct batadv_tt_orig_list_entry *orig_entry;
- int hash_added;
- bool roamed_back = false;
+ int hash_added, table_size, packet_size_max;
+ bool ret = false, roamed_back = false;
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
@@ -484,6 +515,17 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
goto check_roaming;
}
+ /* Ignore the client if we cannot send it in a full table response. */
+ table_size = batadv_tt_local_table_transmit_size(bat_priv);
+ table_size += batadv_tt_len(1);
+ packet_size_max = atomic_read(&bat_priv->packet_size_max);
+ if (table_size > packet_size_max) {
+ net_ratelimited_function(batadv_info, soft_iface,
+ "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
+ table_size, packet_size_max, addr);
+ goto out;
+ }
+
tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
if (!tt_local)
goto out;
@@ -550,11 +592,14 @@ check_roaming:
}
}
+ ret = true;
+
out:
if (tt_local)
batadv_tt_local_entry_free_ref(tt_local);
if (tt_global)
batadv_tt_global_entry_free_ref(tt_global);
+ return ret;
}
/**
@@ -926,8 +971,16 @@ out:
return curr_flags;
}
+/**
+ * batadv_tt_local_purge_list - purge inactive tt local entries
+ * @bat_priv: the bat priv with all the soft interface information
+ * @head: pointer to the list containing the local tt entries
+ * @timeout: parameter deciding whether a given tt local entry is considered
+ * inactive or not
+ */
static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
- struct hlist_head *head)
+ struct hlist_head *head,
+ int timeout)
{
struct batadv_tt_local_entry *tt_local_entry;
struct batadv_tt_common_entry *tt_common_entry;
@@ -945,8 +998,7 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
continue;
- if (!batadv_has_timed_out(tt_local_entry->last_seen,
- BATADV_TT_LOCAL_TIMEOUT))
+ if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
continue;
batadv_tt_local_set_pending(bat_priv, tt_local_entry,
@@ -954,7 +1006,14 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
}
}
-static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
+/**
+ * batadv_tt_local_purge - purge inactive tt local entries
+ * @bat_priv: the bat priv with all the soft interface information
+ * @timeout: parameter deciding whether a given tt local entry is considered
+ * inactive or not
+ */
+static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
+ int timeout)
{
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct hlist_head *head;
@@ -966,7 +1025,7 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock);
- batadv_tt_local_purge_list(bat_priv, head);
+ batadv_tt_local_purge_list(bat_priv, head, timeout);
spin_unlock_bh(list_lock);
}
}
@@ -2370,6 +2429,15 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
req_dst_orig_node);
}
+ /* Don't send the response, if larger than fragmented packet. */
+ tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
+ if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
+ net_ratelimited_function(batadv_info, bat_priv->soft_iface,
+ "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
+ res_dst_orig_node->orig);
+ goto out;
+ }
+
tvlv_tt_data->flags = BATADV_TT_RESPONSE;
tvlv_tt_data->ttvn = req_ttvn;
@@ -2846,7 +2914,7 @@ static void batadv_tt_purge(struct work_struct *work)
priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
bat_priv = container_of(priv_tt, struct batadv_priv, tt);
- batadv_tt_local_purge(bat_priv);
+ batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
batadv_tt_global_purge(bat_priv);
batadv_tt_req_purge(bat_priv);
batadv_tt_roam_purge(bat_priv);
@@ -2959,18 +3027,18 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
}
/**
- * batadv_tt_local_commit_changes - commit all pending local tt changes which
+ * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes which
* have been queued in the time since the last commit
* @bat_priv: the bat priv with all the soft interface information
+ *
+ * Caller must hold tt->commit_lock.
*/
-void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
+void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
{
- spin_lock_bh(&bat_priv->tt.commit_lock);
-
if (atomic_read(&bat_priv->tt.local_changes) < 1) {
if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
batadv_tt_tvlv_container_update(bat_priv);
- goto out;
+ return;
}
batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
@@ -2987,8 +3055,17 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
/* reset the sending counter */
atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
batadv_tt_tvlv_container_update(bat_priv);
+}
-out:
+/**
+ * batadv_tt_local_commit_changes - commit all pending local tt changes which
+ * have been queued in the time since the last commit
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
+{
+ spin_lock_bh(&bat_priv->tt.commit_lock);
+ batadv_tt_local_commit_changes_nolock(bat_priv);
spin_unlock_bh(&bat_priv->tt.commit_lock);
}
@@ -3184,6 +3261,47 @@ out:
}
/**
+ * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
+ * maximum packet size that can be transported through the mesh
+ * @soft_iface: netdev struct of the mesh interface
+ *
+ * Remove entries older than 'timeout' and half timeout if more entries need
+ * to be removed.
+ */
+void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
+{
+ int packet_size_max = atomic_read(&bat_priv->packet_size_max);
+ struct batadv_priv *bat_priv = netdev_priv(soft_iface);
+ int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
+ bool reduced = false;
+
+ spin_lock_bh(&bat_priv->tt.commit_lock);
+
+ while (true) {
+ table_size = batadv_tt_local_table_transmit_size(bat_priv);
+ if (packet_size_max >= table_size)
+ break;
+
+ batadv_tt_local_purge(bat_priv, timeout);
+ batadv_tt_local_purge_pending_clients(bat_priv);
+
+ timeout /= 2;
+ reduced = true;
+ net_ratelimited_function(batadv_info, soft_iface,
+ "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
+ packet_size_max);
+ }
+
+ /* commit these changes immediately, to avoid synchronization problem
+ * with the TTVN
+ */
+ if (reduced)
+ batadv_tt_local_commit_changes_nolock(bat_priv);
+
+ spin_unlock_bh(&bat_priv->tt.commit_lock);
+}
+
+/**
* batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
* @bat_priv: the bat priv with all the soft interface information
* @orig: the orig_node of the ogm
diff --git a/translation-table.h b/translation-table.h
index dc6db4e..026b1ff 100644
--- a/translation-table.h
+++ b/translation-table.h
@@ -21,7 +21,7 @@
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
int batadv_tt_init(struct batadv_priv *bat_priv);
-void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
unsigned short vid, int ifindex);
uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
const uint8_t *addr, unsigned short vid,
@@ -45,6 +45,7 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
uint8_t *addr, unsigned short vid);
bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
uint8_t *addr, unsigned short vid);
+void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface);
bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *addr,
diff --git a/types.h b/types.h
index 0f938c2..d395bb8 100644
--- a/types.h
+++ b/types.h
@@ -595,6 +595,8 @@ struct batadv_softif_vlan {
* @aggregated_ogms: bool indicating whether OGM aggregation is enabled
* @bonding: bool indicating whether traffic bonding is enabled
* @fragmentation: bool indicating whether traffic fragmentation is enabled
+ * @packet_size_max: max packet size that can be transmitted via
+ * multiple fragmented skbs or a single frame if fragmentation is disabled
* @frag_seqno: incremental counter to identify chains of egress fragments
* @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is
* enabled
@@ -641,6 +643,7 @@ struct batadv_priv {
atomic_t aggregated_ogms;
atomic_t bonding;
atomic_t fragmentation;
+ atomic_t packet_size_max;
atomic_t frag_seqno;
#ifdef CONFIG_BATMAN_ADV_BLA
atomic_t bridge_loop_avoidance;
--
1.7.10.4
7 years, 6 months
[B.A.T.M.A.N.] [PATCHv7 0/9] Improving the routing protocol abstraction
by Antonio Quartulli
Hello list,
This is the *seventh* version of the "improved routing abstraction" patchset.
This patchset is introducing a new set of routing API functions meant to
improve the routing protocol abstraction.
Also the orig_node and the neigh_node structure have been heavily modified in
order to split their generic members from those which are metric related.
****** API functions changed starting from v4 ******
+ neigh comparison related:
- bat_neigh_cmp
- bat_neigh_is_equiv_or_better
+ orig_node related:
- bat_orig_print: print the originator table
- bat_orig_free
- bat_orig_add_if
- bat_orig_del_if
Changes from v1:
- removed bat_metric_compare() API. This is not really useful since we are
assuming all the metrics are in the same domain (uint32_t) so a simple
comparison is more than enough.
Changes from v2:
- initialise best_metric in the neighbor purging routine
- don't optimise ntohs. Will be done in a separate patch
Changes from v3:
- bat_metric_is_equiv_or_better is now called bat_neigh_is_equiv_or_better and
now directly takes two neigh_node as parameters. This allows to do not export
the metric at all: all the metric magic is handled inside the function.
- bat_metric_compare has been re-introduced again with the bat_neigh_cmp name. As
for bat_neigh_is_equiv_or_better it also takes two neigh_node as parameters
and the metric is handled inside only.
- as result of the two changes above bat_metric_get has been removed. The
metric is always handled inside the routing protocol code and there is no need
to export it to the rest of the module. This simplified the code and reduced
code duplication. (Thanks Marek for the hint!)
Changes from v4:
- fixed typ0 in 9/9
Changes from v5:
- add neigh_node to the neighbor list only after having completed the whole
initialisation phase (in 1/9)
Changes from v6:
- remove misplaced hlist_add_head_rcu() in batadv_neigh_node_new()
- add a newly created orig_node to the originator hash at the end of
batadv_iv_ogm_orig_get() rather than inside of batadv_orig_node_new(). In this
way the originator is added only after having been completely initialised.
- fix bat_neigh_is_equiv_or_better doc
- fix bat_neigh_is_equiv_or_better implementation in bat_iv: the comparison was
not done in the correct way.
Cheers,
Antonio Quartulli (9):
batman-adv: make struct batadv_neigh_node algorithm agnostic
batman-adv: make struct batadv_orig_node algorithm agnostic
batman-adv: add bat_orig_print API function
batman-adv: add bat_neigh_cmp API function
batman-adv: add bat_neigh_is_equiv_or_better API function
batman-adv: adapt bonding to use the new API functions
batman-adv: adapt the neighbor purging routine to use the new API
functions
batman-adv: provide orig_node routing API
batman-adv: adapt the TT component to use the new API functions
bat_iv_ogm.c | 399 ++++++++++++++++++++++++++++++++++++++++++++--------
gateway_client.c | 16 +--
main.c | 4 +-
main.h | 6 +
network-coding.c | 8 +-
originator.c | 220 +++++++++--------------------
originator.h | 6 +-
routing.c | 39 +++--
routing.h | 3 +-
translation-table.c | 35 +++--
types.h | 92 ++++++++----
11 files changed, 559 insertions(+), 269 deletions(-)
--
1.8.1.5
7 years, 6 months
[B.A.T.M.A.N.] [PATCH] batman-adv: limit local translation table max size
by Marek Lindner
The local translation table size is limited by what can be
transferred from one node to another via a full table request.
The number of entries fitting into a full table request depend
on whether the fragmentation is enabled or not. Therefore this
patch introduces a max table size check and refuses to add
more local clients when that size is reached. Moreover, if the
max full table packet size changes (MTU change or fragmentation
is disabled) the local table is downsized instantaneously.
Signed-off-by: Marek Lindner <lindner_marek(a)yahoo.de>
---
hard-interface.c | 41 +++++++++-----
soft-interface.c | 12 ++--
translation-table.c | 154 ++++++++++++++++++++++++++++++++++++++++++++-------
translation-table.h | 3 +-
types.h | 3 +
5 files changed, 172 insertions(+), 41 deletions(-)
diff --git a/hard-interface.c b/hard-interface.c
index c5f871f..c60d3ed 100644
--- a/hard-interface.c
+++ b/hard-interface.c
@@ -266,16 +266,9 @@ static void batadv_check_known_mac_addr(const struct net_device *net_dev)
int batadv_hardif_min_mtu(struct net_device *soft_iface)
{
- const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
+ struct batadv_priv *bat_priv = netdev_priv(soft_iface);
const struct batadv_hard_iface *hard_iface;
- /* allow big frames if all devices are capable to do so
- * (have MTU > 1500 + batadv_max_header_len())
- */
int min_mtu = ETH_DATA_LEN;
- int max_header_len = batadv_max_header_len();
-
- if (atomic_read(&bat_priv->fragmentation))
- goto out;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
@@ -286,22 +279,40 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
if (hard_iface->soft_iface != soft_iface)
continue;
- min_mtu = min_t(int, hard_iface->net_dev->mtu - max_header_len,
- min_mtu);
+ min_mtu = min_t(int, hard_iface->net_dev->mtu, min_mtu);
}
rcu_read_unlock();
+
+ atomic_set(&bat_priv->packet_size_max, min_mtu);
+
+ if (atomic_read(&bat_priv->fragmentation) == 0)
+ goto out;
+
+ /* with fragmentation enabled the maximum size of internally generated
+ * packets such as translation table exchanges or tvlv containers, etc
+ * has to be calculated
+ */
+ min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE);
+ min_mtu -= sizeof(struct batadv_frag_packet);
+ min_mtu *= BATADV_FRAG_MAX_FRAGMENTS;
+ atomic_set(&bat_priv->packet_size_max, min_mtu);
+
+ /* with fragmentation enabled we can fragment external packets easily */
+ min_mtu = min_t(int, min_mtu, ETH_DATA_LEN);
+
out:
- return min_mtu;
+ return min_mtu - batadv_max_header_len();
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
void batadv_update_min_mtu(struct net_device *soft_iface)
{
- int min_mtu;
+ soft_iface->mtu = batadv_hardif_min_mtu(soft_iface);
- min_mtu = batadv_hardif_min_mtu(soft_iface);
- if (soft_iface->mtu != min_mtu)
- soft_iface->mtu = min_mtu;
+ /* Check if the local translate table should be cleaned up to match a
+ * new (and smaller) MTU.
+ */
+ batadv_tt_local_resize_to_mtu(soft_iface);
}
static void
diff --git a/soft-interface.c b/soft-interface.c
index bafc811..a1f00e8 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -166,7 +166,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
unsigned int header_len = 0;
int data_len = skb->len, ret;
unsigned long brd_delay = 1;
- bool do_bcast = false;
+ bool do_bcast = false, client_added;
unsigned short vid;
uint32_t seqno;
@@ -196,9 +196,12 @@ static int batadv_interface_tx(struct sk_buff *skb,
ethhdr = (struct ethhdr *)skb->data;
/* Register the client MAC in the transtable */
- if (!is_multicast_ether_addr(ethhdr->h_source))
- batadv_tt_local_add(soft_iface, ethhdr->h_source, vid,
- skb->skb_iif);
+ if (!is_multicast_ether_addr(ethhdr->h_source)) {
+ client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
+ vid, skb->skb_iif);
+ if (!client_added)
+ goto dropped;
+ }
/* don't accept stp packets. STP does not help in meshes.
* better use the bridge loop avoidance ...
@@ -674,6 +677,7 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->log_level, 0);
#endif
atomic_set(&bat_priv->fragmentation, 1);
+ atomic_set(&bat_priv->packet_size_max, ETH_DATA_LEN);
atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN);
atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN);
diff --git a/translation-table.c b/translation-table.c
index 2b4d9ed..6a69510 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -401,6 +401,35 @@ static uint16_t batadv_tt_entries(uint16_t tt_len)
return tt_len / batadv_tt_len(1);
}
+/**
+ * batadv_tt_local_table_transmit_size - calculates the local translation table
+ * size when transmitted over the air
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns local translation table size in bytes.
+ */
+static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
+{
+ struct batadv_softif_vlan *vlan;
+ uint16_t num_vlan = 0, tt_local_entries = 0;
+ int hdr_size;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+ num_vlan++;
+ tt_local_entries += atomic_read(&vlan->tt.num_entries);
+ }
+ rcu_read_unlock();
+
+ /* header size of tvlv encapsulated tt response payload */
+ hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
+ hdr_size += sizeof(struct batadv_tvlv_hdr);
+ hdr_size += sizeof(struct batadv_tvlv_tt_data);
+ hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
+
+ return hdr_size + batadv_tt_len(tt_local_entries);
+}
+
static int batadv_tt_local_init(struct batadv_priv *bat_priv)
{
if (bat_priv->tt.local_hash)
@@ -439,8 +468,10 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
* @vid: VLAN identifier
* @ifindex: index of the interface where the client is connected to (useful to
* identify wireless clients)
+ *
+ * Returns true if the client was successfully added, false otherwise.
*/
-void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
unsigned short vid, int ifindex)
{
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
@@ -448,8 +479,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
struct batadv_tt_global_entry *tt_global;
struct hlist_head *head;
struct batadv_tt_orig_list_entry *orig_entry;
- int hash_added;
- bool roamed_back = false;
+ int hash_added, table_size, packet_size_max;
+ bool ret = false, roamed_back = false;
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
@@ -484,6 +515,17 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
goto check_roaming;
}
+ /* Ignore the client if we cannot send it in a full table response. */
+ table_size = batadv_tt_local_table_transmit_size(bat_priv);
+ table_size += batadv_tt_len(1);
+ packet_size_max = atomic_read(&bat_priv->packet_size_max);
+ if (table_size > packet_size_max) {
+ net_ratelimited_function(batadv_info, soft_iface,
+ "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
+ table_size, packet_size_max, addr);
+ goto out;
+ }
+
tt_local = kmalloc(sizeof(*tt_local), GFP_ATOMIC);
if (!tt_local)
goto out;
@@ -550,11 +592,14 @@ check_roaming:
}
}
+ ret = true;
+
out:
if (tt_local)
batadv_tt_local_entry_free_ref(tt_local);
if (tt_global)
batadv_tt_global_entry_free_ref(tt_global);
+ return ret;
}
/**
@@ -717,12 +762,6 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
tt_diff_len = batadv_tt_len(tt_diff_entries_num);
- /* if we have too many changes for one packet don't send any
- * and wait for the tt table request which will be fragmented
- */
- if (tt_diff_len > bat_priv->soft_iface->mtu)
- tt_diff_len = 0;
-
tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
&tt_change, &tt_diff_len);
if (!tvlv_len)
@@ -926,8 +965,16 @@ out:
return curr_flags;
}
+/**
+ * batadv_tt_local_purge_list - purge inactive tt local entries
+ * @bat_priv: the bat priv with all the soft interface information
+ * @head: pointer to the list containing the local tt entries
+ * @timeout: parameter deciding whether a given tt local entry is considered
+ * inactive or not
+ */
static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
- struct hlist_head *head)
+ struct hlist_head *head,
+ int timeout)
{
struct batadv_tt_local_entry *tt_local_entry;
struct batadv_tt_common_entry *tt_common_entry;
@@ -945,8 +992,7 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
continue;
- if (!batadv_has_timed_out(tt_local_entry->last_seen,
- BATADV_TT_LOCAL_TIMEOUT))
+ if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
continue;
batadv_tt_local_set_pending(bat_priv, tt_local_entry,
@@ -954,7 +1000,14 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
}
}
-static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
+/**
+ * batadv_tt_local_purge - purge inactive tt local entries
+ * @bat_priv: the bat priv with all the soft interface information
+ * @timeout: parameter deciding whether a given tt local entry is considered
+ * inactive or not
+ */
+static void batadv_tt_local_purge(struct batadv_priv *bat_priv,
+ int timeout)
{
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct hlist_head *head;
@@ -966,7 +1019,7 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv)
list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock);
- batadv_tt_local_purge_list(bat_priv, head);
+ batadv_tt_local_purge_list(bat_priv, head, timeout);
spin_unlock_bh(list_lock);
}
}
@@ -2370,6 +2423,15 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
req_dst_orig_node);
}
+ /* Don't send the response, if larger than fragmented packet. */
+ tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len;
+ if (tt_len > atomic_read(&bat_priv->packet_size_max)) {
+ net_ratelimited_function(batadv_info, bat_priv->soft_iface,
+ "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n",
+ res_dst_orig_node->orig);
+ goto out;
+ }
+
tvlv_tt_data->flags = BATADV_TT_RESPONSE;
tvlv_tt_data->ttvn = req_ttvn;
@@ -2846,7 +2908,7 @@ static void batadv_tt_purge(struct work_struct *work)
priv_tt = container_of(delayed_work, struct batadv_priv_tt, work);
bat_priv = container_of(priv_tt, struct batadv_priv, tt);
- batadv_tt_local_purge(bat_priv);
+ batadv_tt_local_purge(bat_priv, BATADV_TT_LOCAL_TIMEOUT);
batadv_tt_global_purge(bat_priv);
batadv_tt_req_purge(bat_priv);
batadv_tt_roam_purge(bat_priv);
@@ -2959,18 +3021,18 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
}
/**
- * batadv_tt_local_commit_changes - commit all pending local tt changes which
+ * batadv_tt_local_commit_changes_nolock - commit all pending local tt changes which
* have been queued in the time since the last commit
* @bat_priv: the bat priv with all the soft interface information
+ *
+ * Caller must hold tt->commit_lock.
*/
-void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
+void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
{
- spin_lock_bh(&bat_priv->tt.commit_lock);
-
if (atomic_read(&bat_priv->tt.local_changes) < 1) {
if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
batadv_tt_tvlv_container_update(bat_priv);
- goto out;
+ return;
}
batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
@@ -2987,8 +3049,17 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
/* reset the sending counter */
atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
batadv_tt_tvlv_container_update(bat_priv);
+}
-out:
+/**
+ * batadv_tt_local_commit_changes - commit all pending local tt changes which
+ * have been queued in the time since the last commit
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
+{
+ spin_lock_bh(&bat_priv->tt.commit_lock);
+ batadv_tt_local_commit_changes_nolock(bat_priv);
spin_unlock_bh(&bat_priv->tt.commit_lock);
}
@@ -3184,6 +3255,47 @@ out:
}
/**
+ * batadv_tt_local_resize_to_mtu - resize the local translation table fit the
+ * maximum packet size that can be transported through the mesh
+ * @soft_iface: netdev struct of the mesh interface
+ *
+ * Remove entries older than 'timeout' and half timeout if more entries need
+ * to be removed.
+ */
+void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface)
+{
+ struct batadv_priv *bat_priv = netdev_priv(soft_iface);
+ int packet_size_max = atomic_read(&bat_priv->packet_size_max);
+ int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
+ bool reduced = false;
+
+ spin_lock_bh(&bat_priv->tt.commit_lock);
+
+ while (true) {
+ table_size = batadv_tt_local_table_transmit_size(bat_priv);
+ if (packet_size_max >= table_size)
+ break;
+
+ batadv_tt_local_purge(bat_priv, timeout);
+ batadv_tt_local_purge_pending_clients(bat_priv);
+
+ timeout /= 2;
+ reduced = true;
+ net_ratelimited_function(batadv_info, soft_iface,
+ "Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
+ packet_size_max);
+ }
+
+ /* commit this changes immediately, to avoid synchronization problem
+ * with the TTVN
+ */
+ if (reduced)
+ batadv_tt_local_commit_changes_nolock(bat_priv);
+
+ spin_unlock_bh(&bat_priv->tt.commit_lock);
+}
+
+/**
* batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container
* @bat_priv: the bat priv with all the soft interface information
* @orig: the orig_node of the ogm
diff --git a/translation-table.h b/translation-table.h
index dc6db4e..026b1ff 100644
--- a/translation-table.h
+++ b/translation-table.h
@@ -21,7 +21,7 @@
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
int batadv_tt_init(struct batadv_priv *bat_priv);
-void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
unsigned short vid, int ifindex);
uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
const uint8_t *addr, unsigned short vid,
@@ -45,6 +45,7 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
uint8_t *addr, unsigned short vid);
bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
uint8_t *addr, unsigned short vid);
+void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface);
bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
const unsigned char *addr,
diff --git a/types.h b/types.h
index 0f938c2..d395bb8 100644
--- a/types.h
+++ b/types.h
@@ -595,6 +595,8 @@ struct batadv_softif_vlan {
* @aggregated_ogms: bool indicating whether OGM aggregation is enabled
* @bonding: bool indicating whether traffic bonding is enabled
* @fragmentation: bool indicating whether traffic fragmentation is enabled
+ * @packet_size_max: max packet size that can be transmitted via
+ * multiple fragmented skbs or a single frame if fragmentation is disabled
* @frag_seqno: incremental counter to identify chains of egress fragments
* @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is
* enabled
@@ -641,6 +643,7 @@ struct batadv_priv {
atomic_t aggregated_ogms;
atomic_t bonding;
atomic_t fragmentation;
+ atomic_t packet_size_max;
atomic_t frag_seqno;
#ifdef CONFIG_BATMAN_ADV_BLA
atomic_t bridge_loop_avoidance;
--
1.7.10.4
7 years, 6 months