1 /* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors: 2 * 3 * Linus Lüssing, Marek Lindner 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of version 2 of the GNU General Public 7 * License as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "bat_algo.h" 19 #include "main.h" 20 21 #include <linux/atomic.h> 22 #include <linux/bug.h> 23 #include <linux/cache.h> 24 #include <linux/init.h> 25 #include <linux/jiffies.h> 26 #include <linux/netdevice.h> 27 #include <linux/rculist.h> 28 #include <linux/rcupdate.h> 29 #include <linux/seq_file.h> 30 #include <linux/types.h> 31 #include <linux/workqueue.h> 32 33 #include "bat_v_elp.h" 34 #include "bat_v_ogm.h" 35 #include "hash.h" 36 #include "originator.h" 37 #include "packet.h" 38 39 static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface) 40 { 41 int ret; 42 43 ret = batadv_v_elp_iface_enable(hard_iface); 44 if (ret < 0) 45 return ret; 46 47 ret = batadv_v_ogm_iface_enable(hard_iface); 48 if (ret < 0) 49 batadv_v_elp_iface_disable(hard_iface); 50 51 /* enable link throughput auto-detection by setting the throughput 52 * override to zero 53 */ 54 atomic_set(&hard_iface->bat_v.throughput_override, 0); 55 56 return ret; 57 } 58 59 static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface) 60 { 61 batadv_v_elp_iface_disable(hard_iface); 62 } 63 64 static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface) 65 { 66 } 67 68 static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface) 69 { 70 batadv_v_elp_primary_iface_set(hard_iface); 71 batadv_v_ogm_primary_iface_set(hard_iface); 72 } 73 74 static void 75 batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) 76 { 77 ewma_throughput_init(&hardif_neigh->bat_v.throughput); 78 INIT_WORK(&hardif_neigh->bat_v.metric_work, 79 batadv_v_elp_throughput_metric_update); 80 } 81 82 static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface) 83 { 84 } 85 86 static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet) 87 { 88 } 89 90 /** 91 * batadv_v_orig_print_neigh - print neighbors for the originator table 92 * @orig_node: the orig_node for which the neighbors are printed 93 * @if_outgoing: outgoing interface for these entries 94 * @seq: debugfs table seq_file struct 95 * 96 * Must be called while holding an rcu lock. 97 */ 98 static void 99 batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node, 100 struct batadv_hard_iface *if_outgoing, 101 struct seq_file *seq) 102 { 103 struct batadv_neigh_node *neigh_node; 104 struct batadv_neigh_ifinfo *n_ifinfo; 105 106 hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { 107 n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); 108 if (!n_ifinfo) 109 continue; 110 111 seq_printf(seq, " %pM (%9u.%1u)", 112 neigh_node->addr, 113 n_ifinfo->bat_v.throughput / 10, 114 n_ifinfo->bat_v.throughput % 10); 115 116 batadv_neigh_ifinfo_put(n_ifinfo); 117 } 118 } 119 120 /** 121 * batadv_v_hardif_neigh_print - print a single ELP neighbour node 122 * @seq: neighbour table seq_file struct 123 * @hardif_neigh: hardif neighbour information 124 */ 125 static void 126 batadv_v_hardif_neigh_print(struct seq_file *seq, 127 struct batadv_hardif_neigh_node *hardif_neigh) 128 { 129 int last_secs, last_msecs; 130 u32 throughput; 131 132 last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000; 133 last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000; 134 throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput); 135 136 seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n", 137 hardif_neigh->addr, last_secs, last_msecs, throughput / 10, 138 throughput % 10, hardif_neigh->if_incoming->net_dev->name); 139 } 140 141 /** 142 * batadv_v_neigh_print - print the single hop neighbour list 143 * @bat_priv: the bat priv with all the soft interface information 144 * @seq: neighbour table seq_file struct 145 */ 146 static void batadv_v_neigh_print(struct batadv_priv *bat_priv, 147 struct seq_file *seq) 148 { 149 struct net_device *net_dev = (struct net_device *)seq->private; 150 struct batadv_hardif_neigh_node *hardif_neigh; 151 struct batadv_hard_iface *hard_iface; 152 int batman_count = 0; 153 154 seq_printf(seq, " %-15s %s (%11s) [%10s]\n", "Neighbor", 155 "last-seen", "throughput", "IF"); 156 157 rcu_read_lock(); 158 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 159 if (hard_iface->soft_iface != net_dev) 160 continue; 161 162 hlist_for_each_entry_rcu(hardif_neigh, 163 &hard_iface->neigh_list, list) { 164 batadv_v_hardif_neigh_print(seq, hardif_neigh); 165 batman_count++; 166 } 167 } 168 rcu_read_unlock(); 169 170 if (batman_count == 0) 171 seq_puts(seq, "No batman nodes in range ...\n"); 172 } 173 174 /** 175 * batadv_v_orig_print - print the originator table 176 * @bat_priv: the bat priv with all the soft interface information 177 * @seq: debugfs table seq_file struct 178 * @if_outgoing: the outgoing interface for which this should be printed 179 */ 180 static void batadv_v_orig_print(struct batadv_priv *bat_priv, 181 struct seq_file *seq, 182 struct batadv_hard_iface *if_outgoing) 183 { 184 struct batadv_neigh_node *neigh_node; 185 struct batadv_hashtable *hash = bat_priv->orig_hash; 186 int last_seen_msecs, last_seen_secs; 187 struct batadv_orig_node *orig_node; 188 struct batadv_neigh_ifinfo *n_ifinfo; 189 unsigned long last_seen_jiffies; 190 struct hlist_head *head; 191 int batman_count = 0; 192 u32 i; 193 194 seq_printf(seq, " %-15s %s (%11s) %17s [%10s]: %20s ...\n", 195 "Originator", "last-seen", "throughput", "Nexthop", 196 "outgoingIF", "Potential nexthops"); 197 198 for (i = 0; i < hash->size; i++) { 199 head = &hash->table[i]; 200 201 rcu_read_lock(); 202 hlist_for_each_entry_rcu(orig_node, head, hash_entry) { 203 neigh_node = batadv_orig_router_get(orig_node, 204 if_outgoing); 205 if (!neigh_node) 206 continue; 207 208 n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, 209 if_outgoing); 210 if (!n_ifinfo) 211 goto next; 212 213 last_seen_jiffies = jiffies - orig_node->last_seen; 214 last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); 215 last_seen_secs = last_seen_msecs / 1000; 216 last_seen_msecs = last_seen_msecs % 1000; 217 218 seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:", 219 orig_node->orig, last_seen_secs, 220 last_seen_msecs, 221 n_ifinfo->bat_v.throughput / 10, 222 n_ifinfo->bat_v.throughput % 10, 223 neigh_node->addr, 224 neigh_node->if_incoming->net_dev->name); 225 226 batadv_v_orig_print_neigh(orig_node, if_outgoing, seq); 227 seq_puts(seq, "\n"); 228 batman_count++; 229 230 next: 231 batadv_neigh_node_put(neigh_node); 232 if (n_ifinfo) 233 batadv_neigh_ifinfo_put(n_ifinfo); 234 } 235 rcu_read_unlock(); 236 } 237 238 if (batman_count == 0) 239 seq_puts(seq, "No batman nodes in range ...\n"); 240 } 241 242 static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1, 243 struct batadv_hard_iface *if_outgoing1, 244 struct batadv_neigh_node *neigh2, 245 struct batadv_hard_iface *if_outgoing2) 246 { 247 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; 248 249 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); 250 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); 251 252 if (WARN_ON(!ifinfo1 || !ifinfo2)) 253 return 0; 254 255 return ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput; 256 } 257 258 static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, 259 struct batadv_hard_iface *if_outgoing1, 260 struct batadv_neigh_node *neigh2, 261 struct batadv_hard_iface *if_outgoing2) 262 { 263 struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2; 264 u32 threshold; 265 266 ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); 267 ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); 268 269 threshold = ifinfo1->bat_v.throughput / 4; 270 threshold = ifinfo1->bat_v.throughput - threshold; 271 272 return ifinfo2->bat_v.throughput > threshold; 273 } 274 275 static struct batadv_algo_ops batadv_batman_v __read_mostly = { 276 .name = "BATMAN_V", 277 .bat_iface_enable = batadv_v_iface_enable, 278 .bat_iface_disable = batadv_v_iface_disable, 279 .bat_iface_update_mac = batadv_v_iface_update_mac, 280 .bat_primary_iface_set = batadv_v_primary_iface_set, 281 .bat_hardif_neigh_init = batadv_v_hardif_neigh_init, 282 .bat_ogm_emit = batadv_v_ogm_emit, 283 .bat_ogm_schedule = batadv_v_ogm_schedule, 284 .bat_orig_print = batadv_v_orig_print, 285 .bat_neigh_cmp = batadv_v_neigh_cmp, 286 .bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob, 287 .bat_neigh_print = batadv_v_neigh_print, 288 }; 289 290 /** 291 * batadv_v_mesh_init - initialize the B.A.T.M.A.N. V private resources for a 292 * mesh 293 * @bat_priv: the object representing the mesh interface to initialise 294 * 295 * Return: 0 on success or a negative error code otherwise 296 */ 297 int batadv_v_mesh_init(struct batadv_priv *bat_priv) 298 { 299 return batadv_v_ogm_init(bat_priv); 300 } 301 302 /** 303 * batadv_v_mesh_free - free the B.A.T.M.A.N. V private resources for a mesh 304 * @bat_priv: the object representing the mesh interface to free 305 */ 306 void batadv_v_mesh_free(struct batadv_priv *bat_priv) 307 { 308 batadv_v_ogm_free(bat_priv); 309 } 310 311 /** 312 * batadv_v_init - B.A.T.M.A.N. V initialization function 313 * 314 * Description: Takes care of initializing all the subcomponents. 315 * It is invoked upon module load only. 316 * 317 * Return: 0 on success or a negative error code otherwise 318 */ 319 int __init batadv_v_init(void) 320 { 321 int ret; 322 323 /* B.A.T.M.A.N. V echo location protocol packet */ 324 ret = batadv_recv_handler_register(BATADV_ELP, 325 batadv_v_elp_packet_recv); 326 if (ret < 0) 327 return ret; 328 329 ret = batadv_recv_handler_register(BATADV_OGM2, 330 batadv_v_ogm_packet_recv); 331 if (ret < 0) 332 goto elp_unregister; 333 334 ret = batadv_algo_register(&batadv_batman_v); 335 if (ret < 0) 336 goto ogm_unregister; 337 338 return ret; 339 340 ogm_unregister: 341 batadv_recv_handler_unregister(BATADV_OGM2); 342 343 elp_unregister: 344 batadv_recv_handler_unregister(BATADV_ELP); 345 346 return ret; 347 } 348