aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/network-coding.c
diff options
context:
space:
mode:
authorMartin Hundebøll <martin@hundeboll.net>2013-01-25 05:12:41 -0500
committerAntonio Quartulli <ordex@autistici.org>2013-03-13 17:53:50 -0400
commit3c12de9a5c756b23fe7c9ab332474ece1568914c (patch)
treef7b28653483b0115eb6416d9112febb63136ec01 /net/batman-adv/network-coding.c
parent953324776d6d23eb81f5b825870027b9c069db29 (diff)
batman-adv: network coding - code and transmit packets if possible
Before adding forward-skbs to the coding buffer, the buffer is searched for a potential coding opportunity. If one is found, the two packets are network coded and transmitted right away. If not, the forward-skb is added to the buffer. Network coded packets are transmitted with information about the two receivers and the two coded packets. The first receiver is given by the MAC header, while the second is given in the payload/bat-header. The second receiver uses promiscuous mode to receive the packet and check the second destination. Signed-off-by: Martin Hundebøll <martin@hundeboll.net> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/network-coding.c')
-rw-r--r--net/batman-adv/network-coding.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index 2c38c540c6db..fce2846e9656 100644
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -798,6 +798,403 @@ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv,
798} 798}
799 799
800/** 800/**
801 * batadv_nc_random_weight_tq - scale the receivers TQ-value to avoid unfair
802 * selection of a receiver with slightly lower TQ than the other
803 * @tq: to be weighted tq value
804 */
805static uint8_t batadv_nc_random_weight_tq(uint8_t tq)
806{
807 uint8_t rand_val, rand_tq;
808
809 get_random_bytes(&rand_val, sizeof(rand_val));
810
811 /* randomize the estimated packet loss (max TQ - estimated TQ) */
812 rand_tq = rand_val * (BATADV_TQ_MAX_VALUE - tq);
813
814 /* normalize the randomized packet loss */
815 rand_tq /= BATADV_TQ_MAX_VALUE;
816
817 /* convert to (randomized) estimated tq again */
818 return BATADV_TQ_MAX_VALUE - rand_tq;
819}
820
821/**
822 * batadv_nc_memxor - XOR destination with source
823 * @dst: byte array to XOR into
824 * @src: byte array to XOR from
825 * @len: length of destination array
826 */
827static void batadv_nc_memxor(char *dst, const char *src, unsigned int len)
828{
829 unsigned int i;
830
831 for (i = 0; i < len; ++i)
832 dst[i] ^= src[i];
833}
834
835/**
836 * batadv_nc_code_packets - code a received unicast_packet with an nc packet
837 * into a coded_packet and send it
838 * @bat_priv: the bat priv with all the soft interface information
839 * @skb: data skb to forward
840 * @ethhdr: pointer to the ethernet header inside the skb
841 * @nc_packet: structure containing the packet to the skb can be coded with
842 * @neigh_node: next hop to forward packet to
843 *
844 * Returns true if both packets are consumed, false otherwise.
845 */
846static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
847 struct sk_buff *skb,
848 struct ethhdr *ethhdr,
849 struct batadv_nc_packet *nc_packet,
850 struct batadv_neigh_node *neigh_node)
851{
852 uint8_t tq_weighted_neigh, tq_weighted_coding;
853 struct sk_buff *skb_dest, *skb_src;
854 struct batadv_unicast_packet *packet1;
855 struct batadv_unicast_packet *packet2;
856 struct batadv_coded_packet *coded_packet;
857 struct batadv_neigh_node *neigh_tmp, *router_neigh;
858 struct batadv_neigh_node *router_coding = NULL;
859 uint8_t *first_source, *first_dest, *second_source, *second_dest;
860 __be32 packet_id1, packet_id2;
861 size_t count;
862 bool res = false;
863 int coding_len;
864 int unicast_size = sizeof(*packet1);
865 int coded_size = sizeof(*coded_packet);
866 int header_add = coded_size - unicast_size;
867
868 router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
869 if (!router_neigh)
870 goto out;
871
872 neigh_tmp = nc_packet->neigh_node;
873 router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
874 if (!router_coding)
875 goto out;
876
877 tq_weighted_neigh = batadv_nc_random_weight_tq(router_neigh->tq_avg);
878 tq_weighted_coding = batadv_nc_random_weight_tq(router_coding->tq_avg);
879
880 /* Select one destination for the MAC-header dst-field based on
881 * weighted TQ-values.
882 */
883 if (tq_weighted_neigh >= tq_weighted_coding) {
884 /* Destination from nc_packet is selected for MAC-header */
885 first_dest = nc_packet->nc_path->next_hop;
886 first_source = nc_packet->nc_path->prev_hop;
887 second_dest = neigh_node->addr;
888 second_source = ethhdr->h_source;
889 packet1 = (struct batadv_unicast_packet *)nc_packet->skb->data;
890 packet2 = (struct batadv_unicast_packet *)skb->data;
891 packet_id1 = nc_packet->packet_id;
892 packet_id2 = batadv_skb_crc32(skb,
893 skb->data + sizeof(*packet2));
894 } else {
895 /* Destination for skb is selected for MAC-header */
896 first_dest = neigh_node->addr;
897 first_source = ethhdr->h_source;
898 second_dest = nc_packet->nc_path->next_hop;
899 second_source = nc_packet->nc_path->prev_hop;
900 packet1 = (struct batadv_unicast_packet *)skb->data;
901 packet2 = (struct batadv_unicast_packet *)nc_packet->skb->data;
902 packet_id1 = batadv_skb_crc32(skb,
903 skb->data + sizeof(*packet1));
904 packet_id2 = nc_packet->packet_id;
905 }
906
907 /* Instead of zero padding the smallest data buffer, we
908 * code into the largest.
909 */
910 if (skb->len <= nc_packet->skb->len) {
911 skb_dest = nc_packet->skb;
912 skb_src = skb;
913 } else {
914 skb_dest = skb;
915 skb_src = nc_packet->skb;
916 }
917
918 /* coding_len is used when decoding the packet shorter packet */
919 coding_len = skb_src->len - unicast_size;
920
921 if (skb_linearize(skb_dest) < 0 || skb_linearize(skb_src) < 0)
922 goto out;
923
924 skb_push(skb_dest, header_add);
925
926 coded_packet = (struct batadv_coded_packet *)skb_dest->data;
927 skb_reset_mac_header(skb_dest);
928
929 coded_packet->header.packet_type = BATADV_CODED;
930 coded_packet->header.version = BATADV_COMPAT_VERSION;
931 coded_packet->header.ttl = packet1->header.ttl;
932
933 /* Info about first unicast packet */
934 memcpy(coded_packet->first_source, first_source, ETH_ALEN);
935 memcpy(coded_packet->first_orig_dest, packet1->dest, ETH_ALEN);
936 coded_packet->first_crc = packet_id1;
937 coded_packet->first_ttvn = packet1->ttvn;
938
939 /* Info about second unicast packet */
940 memcpy(coded_packet->second_dest, second_dest, ETH_ALEN);
941 memcpy(coded_packet->second_source, second_source, ETH_ALEN);
942 memcpy(coded_packet->second_orig_dest, packet2->dest, ETH_ALEN);
943 coded_packet->second_crc = packet_id2;
944 coded_packet->second_ttl = packet2->header.ttl;
945 coded_packet->second_ttvn = packet2->ttvn;
946 coded_packet->coded_len = htons(coding_len);
947
948 /* This is where the magic happens: Code skb_src into skb_dest */
949 batadv_nc_memxor(skb_dest->data + coded_size,
950 skb_src->data + unicast_size, coding_len);
951
952 /* Update counters accordingly */
953 if (BATADV_SKB_CB(skb_src)->decoded &&
954 BATADV_SKB_CB(skb_dest)->decoded) {
955 /* Both packets are recoded */
956 count = skb_src->len + ETH_HLEN;
957 count += skb_dest->len + ETH_HLEN;
958 batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE, 2);
959 batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES, count);
960 } else if (!BATADV_SKB_CB(skb_src)->decoded &&
961 !BATADV_SKB_CB(skb_dest)->decoded) {
962 /* Both packets are newly coded */
963 count = skb_src->len + ETH_HLEN;
964 count += skb_dest->len + ETH_HLEN;
965 batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE, 2);
966 batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES, count);
967 } else if (BATADV_SKB_CB(skb_src)->decoded &&
968 !BATADV_SKB_CB(skb_dest)->decoded) {
969 /* skb_src recoded and skb_dest is newly coded */
970 batadv_inc_counter(bat_priv, BATADV_CNT_NC_RECODE);
971 batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES,
972 skb_src->len + ETH_HLEN);
973 batadv_inc_counter(bat_priv, BATADV_CNT_NC_CODE);
974 batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES,
975 skb_dest->len + ETH_HLEN);
976 } else if (!BATADV_SKB_CB(skb_src)->decoded &&
977 BATADV_SKB_CB(skb_dest)->decoded) {
978 /* skb_src is newly coded and skb_dest is recoded */
979 batadv_inc_counter(bat_priv, BATADV_CNT_NC_CODE);
980 batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES,
981 skb_src->len + ETH_HLEN);
982 batadv_inc_counter(bat_priv, BATADV_CNT_NC_RECODE);
983 batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES,
984 skb_dest->len + ETH_HLEN);
985 }
986
987 /* skb_src is now coded into skb_dest, so free it */
988 kfree_skb(skb_src);
989
990 /* avoid duplicate free of skb from nc_packet */
991 nc_packet->skb = NULL;
992 batadv_nc_packet_free(nc_packet);
993
994 /* Send the coded packet and return true */
995 batadv_send_skb_packet(skb_dest, neigh_node->if_incoming, first_dest);
996 res = true;
997out:
998 if (router_neigh)
999 batadv_neigh_node_free_ref(router_neigh);
1000 if (router_coding)
1001 batadv_neigh_node_free_ref(router_coding);
1002 return res;
1003}
1004
1005/**
1006 * batadv_nc_skb_coding_possible - true if a decoded skb is available at dst.
1007 * @skb: data skb to forward
1008 * @dst: destination mac address of the other skb to code with
1009 * @src: source mac address of skb
1010 *
1011 * Whenever we network code a packet we have to check whether we received it in
1012 * a network coded form. If so, we may not be able to use it for coding because
1013 * some neighbors may also have received (overheard) the packet in the network
1014 * coded form without being able to decode it. It is hard to know which of the
1015 * neighboring nodes was able to decode the packet, therefore we can only
1016 * re-code the packet if the source of the previous encoded packet is involved.
1017 * Since the source encoded the packet we can be certain it has all necessary
1018 * decode information.
1019 *
1020 * Returns true if coding of a decoded packet is allowed.
1021 */
1022static bool batadv_nc_skb_coding_possible(struct sk_buff *skb,
1023 uint8_t *dst, uint8_t *src)
1024{
1025 if (BATADV_SKB_CB(skb)->decoded && !batadv_compare_eth(dst, src))
1026 return false;
1027 else
1028 return true;
1029}
1030
1031/**
1032 * batadv_nc_path_search - Find the coding path matching in_nc_node and
1033 * out_nc_node to retrieve a buffered packet that can be used for coding.
1034 * @bat_priv: the bat priv with all the soft interface information
1035 * @in_nc_node: pointer to skb next hop's neighbor nc node
1036 * @out_nc_node: pointer to skb source's neighbor nc node
1037 * @skb: data skb to forward
1038 * @eth_dst: next hop mac address of skb
1039 *
1040 * Returns true if coding of a decoded skb is allowed.
1041 */
1042static struct batadv_nc_packet *
1043batadv_nc_path_search(struct batadv_priv *bat_priv,
1044 struct batadv_nc_node *in_nc_node,
1045 struct batadv_nc_node *out_nc_node,
1046 struct sk_buff *skb,
1047 uint8_t *eth_dst)
1048{
1049 struct batadv_nc_path *nc_path, nc_path_key;
1050 struct batadv_nc_packet *nc_packet_out = NULL;
1051 struct batadv_nc_packet *nc_packet, *nc_packet_tmp;
1052 struct batadv_hashtable *hash = bat_priv->nc.coding_hash;
1053 int idx;
1054
1055 if (!hash)
1056 return NULL;
1057
1058 /* Create almost path key */
1059 batadv_nc_hash_key_gen(&nc_path_key, in_nc_node->addr,
1060 out_nc_node->addr);
1061 idx = batadv_nc_hash_choose(&nc_path_key, hash->size);
1062
1063 /* Check for coding opportunities in this nc_path */
1064 rcu_read_lock();
1065 hlist_for_each_entry_rcu(nc_path, &hash->table[idx], hash_entry) {
1066 if (!batadv_compare_eth(nc_path->prev_hop, in_nc_node->addr))
1067 continue;
1068
1069 if (!batadv_compare_eth(nc_path->next_hop, out_nc_node->addr))
1070 continue;
1071
1072 spin_lock_bh(&nc_path->packet_list_lock);
1073 if (list_empty(&nc_path->packet_list)) {
1074 spin_unlock_bh(&nc_path->packet_list_lock);
1075 continue;
1076 }
1077
1078 list_for_each_entry_safe(nc_packet, nc_packet_tmp,
1079 &nc_path->packet_list, list) {
1080 if (!batadv_nc_skb_coding_possible(nc_packet->skb,
1081 eth_dst,
1082 in_nc_node->addr))
1083 continue;
1084
1085 /* Coding opportunity is found! */
1086 list_del(&nc_packet->list);
1087 nc_packet_out = nc_packet;
1088 break;
1089 }
1090
1091 spin_unlock_bh(&nc_path->packet_list_lock);
1092 break;
1093 }
1094 rcu_read_unlock();
1095
1096 return nc_packet_out;
1097}
1098
1099/**
1100 * batadv_nc_skb_src_search - Loops through the list of neighoring nodes of the
1101 * skb's sender (may be equal to the originator).
1102 * @bat_priv: the bat priv with all the soft interface information
1103 * @skb: data skb to forward
1104 * @eth_dst: next hop mac address of skb
1105 * @eth_src: source mac address of skb
1106 * @in_nc_node: pointer to skb next hop's neighbor nc node
1107 *
1108 * Returns an nc packet if a suitable coding packet was found, NULL otherwise.
1109 */
1110static struct batadv_nc_packet *
1111batadv_nc_skb_src_search(struct batadv_priv *bat_priv,
1112 struct sk_buff *skb,
1113 uint8_t *eth_dst,
1114 uint8_t *eth_src,
1115 struct batadv_nc_node *in_nc_node)
1116{
1117 struct batadv_orig_node *orig_node;
1118 struct batadv_nc_node *out_nc_node;
1119 struct batadv_nc_packet *nc_packet = NULL;
1120
1121 orig_node = batadv_orig_hash_find(bat_priv, eth_src);
1122 if (!orig_node)
1123 return NULL;
1124
1125 rcu_read_lock();
1126 list_for_each_entry_rcu(out_nc_node,
1127 &orig_node->out_coding_list, list) {
1128 /* Check if the skb is decoded and if recoding is possible */
1129 if (!batadv_nc_skb_coding_possible(skb,
1130 out_nc_node->addr, eth_src))
1131 continue;
1132
1133 /* Search for an opportunity in this nc_path */
1134 nc_packet = batadv_nc_path_search(bat_priv, in_nc_node,
1135 out_nc_node, skb, eth_dst);
1136 if (nc_packet)
1137 break;
1138 }
1139 rcu_read_unlock();
1140
1141 batadv_orig_node_free_ref(orig_node);
1142 return nc_packet;
1143}
1144
1145/**
1146 * batadv_nc_skb_dst_search - Loops through list of neighboring nodes to dst.
1147 * @skb: data skb to forward
1148 * @neigh_node: next hop to forward packet to
1149 * @ethhdr: pointer to the ethernet header inside the skb
1150 *
1151 * Loops through list of neighboring nodes the next hop has a good connection to
1152 * (receives OGMs with a sufficient quality). We need to find a neighbor of our
1153 * next hop that potentially sent a packet which our next hop also received
1154 * (overheard) and has stored for later decoding.
1155 *
1156 * Returns true if the skb was consumed (encoded packet sent) or false otherwise
1157 */
1158static bool batadv_nc_skb_dst_search(struct sk_buff *skb,
1159 struct batadv_neigh_node *neigh_node,
1160 struct ethhdr *ethhdr)
1161{
1162 struct net_device *netdev = neigh_node->if_incoming->soft_iface;
1163 struct batadv_priv *bat_priv = netdev_priv(netdev);
1164 struct batadv_orig_node *orig_node = neigh_node->orig_node;
1165 struct batadv_nc_node *nc_node;
1166 struct batadv_nc_packet *nc_packet = NULL;
1167
1168 rcu_read_lock();
1169 list_for_each_entry_rcu(nc_node, &orig_node->in_coding_list, list) {
1170 /* Search for coding opportunity with this in_nc_node */
1171 nc_packet = batadv_nc_skb_src_search(bat_priv, skb,
1172 neigh_node->addr,
1173 ethhdr->h_source, nc_node);
1174
1175 /* Opportunity was found, so stop searching */
1176 if (nc_packet)
1177 break;
1178 }
1179 rcu_read_unlock();
1180
1181 if (!nc_packet)
1182 return false;
1183
1184 /* Code and send packets */
1185 if (batadv_nc_code_packets(bat_priv, skb, ethhdr, nc_packet,
1186 neigh_node))
1187 return true;
1188
1189 /* out of mem ? Coding failed - we have to free the buffered packet
1190 * to avoid memleaks. The skb passed as argument will be dealt with
1191 * by the calling function.
1192 */
1193 batadv_nc_send_packet(nc_packet);
1194 return false;
1195}
1196
1197/**
801 * batadv_nc_skb_add_to_path - buffer skb for later encoding / decoding 1198 * batadv_nc_skb_add_to_path - buffer skb for later encoding / decoding
802 * @skb: skb to add to path 1199 * @skb: skb to add to path
803 * @nc_path: path to add skb to 1200 * @nc_path: path to add skb to
@@ -862,6 +1259,10 @@ bool batadv_nc_skb_forward(struct sk_buff *skb,
862 if (packet->header.packet_type != BATADV_UNICAST) 1259 if (packet->header.packet_type != BATADV_UNICAST)
863 goto out; 1260 goto out;
864 1261
1262 /* Try to find a coding opportunity and send the skb if one is found */
1263 if (batadv_nc_skb_dst_search(skb, neigh_node, ethhdr))
1264 return true;
1265
865 /* Find or create a nc_path for this src-dst pair */ 1266 /* Find or create a nc_path for this src-dst pair */
866 nc_path = batadv_nc_get_path(bat_priv, 1267 nc_path = batadv_nc_get_path(bat_priv,
867 bat_priv->nc.coding_hash, 1268 bat_priv->nc.coding_hash,