xref: /openbmc/linux/net/batman-adv/bat_v.c (revision 0edbfea5)
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/stddef.h>
31 #include <linux/types.h>
32 #include <linux/workqueue.h>
33 
34 #include "bat_v_elp.h"
35 #include "bat_v_ogm.h"
36 #include "hard-interface.h"
37 #include "hash.h"
38 #include "originator.h"
39 #include "packet.h"
40 
41 static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
42 {
43 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
44 	struct batadv_hard_iface *primary_if;
45 
46 	primary_if = batadv_primary_if_get_selected(bat_priv);
47 
48 	if (primary_if) {
49 		batadv_v_elp_iface_activate(primary_if, hard_iface);
50 		batadv_hardif_put(primary_if);
51 	}
52 
53 	/* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can
54 	 * set the interface as ACTIVE right away, without any risk of race
55 	 * condition
56 	 */
57 	if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
58 		hard_iface->if_status = BATADV_IF_ACTIVE;
59 }
60 
61 static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
62 {
63 	int ret;
64 
65 	ret = batadv_v_elp_iface_enable(hard_iface);
66 	if (ret < 0)
67 		return ret;
68 
69 	ret = batadv_v_ogm_iface_enable(hard_iface);
70 	if (ret < 0)
71 		batadv_v_elp_iface_disable(hard_iface);
72 
73 	/* enable link throughput auto-detection by setting the throughput
74 	 * override to zero
75 	 */
76 	atomic_set(&hard_iface->bat_v.throughput_override, 0);
77 
78 	return ret;
79 }
80 
81 static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
82 {
83 	batadv_v_elp_iface_disable(hard_iface);
84 }
85 
86 static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
87 {
88 	batadv_v_elp_primary_iface_set(hard_iface);
89 	batadv_v_ogm_primary_iface_set(hard_iface);
90 }
91 
92 /**
93  * batadv_v_iface_update_mac - react to hard-interface MAC address change
94  * @hard_iface: the modified interface
95  *
96  * If the modified interface is the primary one, update the originator
97  * address in the ELP and OGM messages to reflect the new MAC address.
98  */
99 static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
100 {
101 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
102 	struct batadv_hard_iface *primary_if;
103 
104 	primary_if = batadv_primary_if_get_selected(bat_priv);
105 	if (primary_if != hard_iface)
106 		goto out;
107 
108 	batadv_v_primary_iface_set(hard_iface);
109 out:
110 	if (primary_if)
111 		batadv_hardif_put(primary_if);
112 }
113 
114 static void
115 batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
116 {
117 	ewma_throughput_init(&hardif_neigh->bat_v.throughput);
118 	INIT_WORK(&hardif_neigh->bat_v.metric_work,
119 		  batadv_v_elp_throughput_metric_update);
120 }
121 
122 static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface)
123 {
124 }
125 
126 static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
127 {
128 }
129 
130 /**
131  * batadv_v_orig_print_neigh - print neighbors for the originator table
132  * @orig_node: the orig_node for which the neighbors are printed
133  * @if_outgoing: outgoing interface for these entries
134  * @seq: debugfs table seq_file struct
135  *
136  * Must be called while holding an rcu lock.
137  */
138 static void
139 batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node,
140 			  struct batadv_hard_iface *if_outgoing,
141 			  struct seq_file *seq)
142 {
143 	struct batadv_neigh_node *neigh_node;
144 	struct batadv_neigh_ifinfo *n_ifinfo;
145 
146 	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
147 		n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
148 		if (!n_ifinfo)
149 			continue;
150 
151 		seq_printf(seq, " %pM (%9u.%1u)",
152 			   neigh_node->addr,
153 			   n_ifinfo->bat_v.throughput / 10,
154 			   n_ifinfo->bat_v.throughput % 10);
155 
156 		batadv_neigh_ifinfo_put(n_ifinfo);
157 	}
158 }
159 
160 /**
161  * batadv_v_hardif_neigh_print - print a single ELP neighbour node
162  * @seq: neighbour table seq_file struct
163  * @hardif_neigh: hardif neighbour information
164  */
165 static void
166 batadv_v_hardif_neigh_print(struct seq_file *seq,
167 			    struct batadv_hardif_neigh_node *hardif_neigh)
168 {
169 	int last_secs, last_msecs;
170 	u32 throughput;
171 
172 	last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
173 	last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
174 	throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
175 
176 	seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n",
177 		   hardif_neigh->addr, last_secs, last_msecs, throughput / 10,
178 		   throughput % 10, hardif_neigh->if_incoming->net_dev->name);
179 }
180 
181 /**
182  * batadv_v_neigh_print - print the single hop neighbour list
183  * @bat_priv: the bat priv with all the soft interface information
184  * @seq: neighbour table seq_file struct
185  */
186 static void batadv_v_neigh_print(struct batadv_priv *bat_priv,
187 				 struct seq_file *seq)
188 {
189 	struct net_device *net_dev = (struct net_device *)seq->private;
190 	struct batadv_hardif_neigh_node *hardif_neigh;
191 	struct batadv_hard_iface *hard_iface;
192 	int batman_count = 0;
193 
194 	seq_puts(seq,
195 		 "  Neighbor        last-seen ( throughput) [        IF]\n");
196 
197 	rcu_read_lock();
198 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
199 		if (hard_iface->soft_iface != net_dev)
200 			continue;
201 
202 		hlist_for_each_entry_rcu(hardif_neigh,
203 					 &hard_iface->neigh_list, list) {
204 			batadv_v_hardif_neigh_print(seq, hardif_neigh);
205 			batman_count++;
206 		}
207 	}
208 	rcu_read_unlock();
209 
210 	if (batman_count == 0)
211 		seq_puts(seq, "No batman nodes in range ...\n");
212 }
213 
214 /**
215  * batadv_v_orig_print - print the originator table
216  * @bat_priv: the bat priv with all the soft interface information
217  * @seq: debugfs table seq_file struct
218  * @if_outgoing: the outgoing interface for which this should be printed
219  */
220 static void batadv_v_orig_print(struct batadv_priv *bat_priv,
221 				struct seq_file *seq,
222 				struct batadv_hard_iface *if_outgoing)
223 {
224 	struct batadv_neigh_node *neigh_node;
225 	struct batadv_hashtable *hash = bat_priv->orig_hash;
226 	int last_seen_msecs, last_seen_secs;
227 	struct batadv_orig_node *orig_node;
228 	struct batadv_neigh_ifinfo *n_ifinfo;
229 	unsigned long last_seen_jiffies;
230 	struct hlist_head *head;
231 	int batman_count = 0;
232 	u32 i;
233 
234 	seq_puts(seq,
235 		 "  Originator      last-seen ( throughput)           Nexthop [outgoingIF]:   Potential nexthops ...\n");
236 
237 	for (i = 0; i < hash->size; i++) {
238 		head = &hash->table[i];
239 
240 		rcu_read_lock();
241 		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
242 			neigh_node = batadv_orig_router_get(orig_node,
243 							    if_outgoing);
244 			if (!neigh_node)
245 				continue;
246 
247 			n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
248 							   if_outgoing);
249 			if (!n_ifinfo)
250 				goto next;
251 
252 			last_seen_jiffies = jiffies - orig_node->last_seen;
253 			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
254 			last_seen_secs = last_seen_msecs / 1000;
255 			last_seen_msecs = last_seen_msecs % 1000;
256 
257 			seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:",
258 				   orig_node->orig, last_seen_secs,
259 				   last_seen_msecs,
260 				   n_ifinfo->bat_v.throughput / 10,
261 				   n_ifinfo->bat_v.throughput % 10,
262 				   neigh_node->addr,
263 				   neigh_node->if_incoming->net_dev->name);
264 
265 			batadv_v_orig_print_neigh(orig_node, if_outgoing, seq);
266 			seq_puts(seq, "\n");
267 			batman_count++;
268 
269 next:
270 			batadv_neigh_node_put(neigh_node);
271 			if (n_ifinfo)
272 				batadv_neigh_ifinfo_put(n_ifinfo);
273 		}
274 		rcu_read_unlock();
275 	}
276 
277 	if (batman_count == 0)
278 		seq_puts(seq, "No batman nodes in range ...\n");
279 }
280 
281 static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
282 			      struct batadv_hard_iface *if_outgoing1,
283 			      struct batadv_neigh_node *neigh2,
284 			      struct batadv_hard_iface *if_outgoing2)
285 {
286 	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
287 	int ret = 0;
288 
289 	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
290 	if (WARN_ON(!ifinfo1))
291 		goto err_ifinfo1;
292 
293 	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
294 	if (WARN_ON(!ifinfo2))
295 		goto err_ifinfo2;
296 
297 	ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
298 
299 	batadv_neigh_ifinfo_put(ifinfo2);
300 err_ifinfo2:
301 	batadv_neigh_ifinfo_put(ifinfo1);
302 err_ifinfo1:
303 	return ret;
304 }
305 
306 static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
307 				  struct batadv_hard_iface *if_outgoing1,
308 				  struct batadv_neigh_node *neigh2,
309 				  struct batadv_hard_iface *if_outgoing2)
310 {
311 	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
312 	u32 threshold;
313 	bool ret = false;
314 
315 	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
316 	if (WARN_ON(!ifinfo1))
317 		goto err_ifinfo1;
318 
319 	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
320 	if (WARN_ON(!ifinfo2))
321 		goto err_ifinfo2;
322 
323 	threshold = ifinfo1->bat_v.throughput / 4;
324 	threshold = ifinfo1->bat_v.throughput - threshold;
325 
326 	ret = ifinfo2->bat_v.throughput > threshold;
327 
328 	batadv_neigh_ifinfo_put(ifinfo2);
329 err_ifinfo2:
330 	batadv_neigh_ifinfo_put(ifinfo1);
331 err_ifinfo1:
332 	return ret;
333 }
334 
335 static struct batadv_algo_ops batadv_batman_v __read_mostly = {
336 	.name = "BATMAN_V",
337 	.bat_iface_activate = batadv_v_iface_activate,
338 	.bat_iface_enable = batadv_v_iface_enable,
339 	.bat_iface_disable = batadv_v_iface_disable,
340 	.bat_iface_update_mac = batadv_v_iface_update_mac,
341 	.bat_primary_iface_set = batadv_v_primary_iface_set,
342 	.bat_hardif_neigh_init = batadv_v_hardif_neigh_init,
343 	.bat_ogm_emit = batadv_v_ogm_emit,
344 	.bat_ogm_schedule = batadv_v_ogm_schedule,
345 	.bat_orig_print = batadv_v_orig_print,
346 	.bat_neigh_cmp = batadv_v_neigh_cmp,
347 	.bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob,
348 	.bat_neigh_print = batadv_v_neigh_print,
349 };
350 
351 /**
352  * batadv_v_mesh_init - initialize the B.A.T.M.A.N. V private resources for a
353  *  mesh
354  * @bat_priv: the object representing the mesh interface to initialise
355  *
356  * Return: 0 on success or a negative error code otherwise
357  */
358 int batadv_v_mesh_init(struct batadv_priv *bat_priv)
359 {
360 	return batadv_v_ogm_init(bat_priv);
361 }
362 
363 /**
364  * batadv_v_mesh_free - free the B.A.T.M.A.N. V private resources for a mesh
365  * @bat_priv: the object representing the mesh interface to free
366  */
367 void batadv_v_mesh_free(struct batadv_priv *bat_priv)
368 {
369 	batadv_v_ogm_free(bat_priv);
370 }
371 
372 /**
373  * batadv_v_init - B.A.T.M.A.N. V initialization function
374  *
375  * Description: Takes care of initializing all the subcomponents.
376  * It is invoked upon module load only.
377  *
378  * Return: 0 on success or a negative error code otherwise
379  */
380 int __init batadv_v_init(void)
381 {
382 	int ret;
383 
384 	/* B.A.T.M.A.N. V echo location protocol packet  */
385 	ret = batadv_recv_handler_register(BATADV_ELP,
386 					   batadv_v_elp_packet_recv);
387 	if (ret < 0)
388 		return ret;
389 
390 	ret = batadv_recv_handler_register(BATADV_OGM2,
391 					   batadv_v_ogm_packet_recv);
392 	if (ret < 0)
393 		goto elp_unregister;
394 
395 	ret = batadv_algo_register(&batadv_batman_v);
396 	if (ret < 0)
397 		goto ogm_unregister;
398 
399 	return ret;
400 
401 ogm_unregister:
402 	batadv_recv_handler_unregister(BATADV_OGM2);
403 
404 elp_unregister:
405 	batadv_recv_handler_unregister(BATADV_ELP);
406 
407 	return ret;
408 }
409