diff options
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/bat_iv_ogm.c | 5 | ||||
-rw-r--r-- | net/batman-adv/debugfs.c | 18 | ||||
-rw-r--r-- | net/batman-adv/main.h | 2 | ||||
-rw-r--r-- | net/batman-adv/network-coding.c | 414 | ||||
-rw-r--r-- | net/batman-adv/network-coding.h | 47 | ||||
-rw-r--r-- | net/batman-adv/originator.c | 6 | ||||
-rw-r--r-- | net/batman-adv/types.h | 32 |
7 files changed, 524 insertions, 0 deletions
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index a5bb0a769eb9..071f288b77a8 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "hard-interface.h" | 27 | #include "hard-interface.h" |
28 | #include "send.h" | 28 | #include "send.h" |
29 | #include "bat_algo.h" | 29 | #include "bat_algo.h" |
30 | #include "network-coding.h" | ||
30 | 31 | ||
31 | static struct batadv_neigh_node * | 32 | static struct batadv_neigh_node * |
32 | batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, | 33 | batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, |
@@ -1185,6 +1186,10 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1185 | if (!orig_neigh_node) | 1186 | if (!orig_neigh_node) |
1186 | goto out; | 1187 | goto out; |
1187 | 1188 | ||
1189 | /* Update nc_nodes of the originator */ | ||
1190 | batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, | ||
1191 | batadv_ogm_packet, is_single_hop_neigh); | ||
1192 | |||
1188 | orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node); | 1193 | orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node); |
1189 | 1194 | ||
1190 | /* drop packet if sender is not a direct neighbor and if we | 1195 | /* drop packet if sender is not a direct neighbor and if we |
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index 6ae86516db4d..f186a55b23c3 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "icmp_socket.h" | 32 | #include "icmp_socket.h" |
33 | #include "bridge_loop_avoidance.h" | 33 | #include "bridge_loop_avoidance.h" |
34 | #include "distributed-arp-table.h" | 34 | #include "distributed-arp-table.h" |
35 | #include "network-coding.h" | ||
35 | 36 | ||
36 | static struct dentry *batadv_debugfs; | 37 | static struct dentry *batadv_debugfs; |
37 | 38 | ||
@@ -310,6 +311,14 @@ struct batadv_debuginfo { | |||
310 | const struct file_operations fops; | 311 | const struct file_operations fops; |
311 | }; | 312 | }; |
312 | 313 | ||
314 | #ifdef CONFIG_BATMAN_ADV_NC | ||
315 | static int batadv_nc_nodes_open(struct inode *inode, struct file *file) | ||
316 | { | ||
317 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
318 | return single_open(file, batadv_nc_nodes_seq_print_text, net_dev); | ||
319 | } | ||
320 | #endif | ||
321 | |||
313 | #define BATADV_DEBUGINFO(_name, _mode, _open) \ | 322 | #define BATADV_DEBUGINFO(_name, _mode, _open) \ |
314 | struct batadv_debuginfo batadv_debuginfo_##_name = { \ | 323 | struct batadv_debuginfo batadv_debuginfo_##_name = { \ |
315 | .attr = { .name = __stringify(_name), \ | 324 | .attr = { .name = __stringify(_name), \ |
@@ -348,6 +357,9 @@ static BATADV_DEBUGINFO(dat_cache, S_IRUGO, batadv_dat_cache_open); | |||
348 | static BATADV_DEBUGINFO(transtable_local, S_IRUGO, | 357 | static BATADV_DEBUGINFO(transtable_local, S_IRUGO, |
349 | batadv_transtable_local_open); | 358 | batadv_transtable_local_open); |
350 | static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open); | 359 | static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open); |
360 | #ifdef CONFIG_BATMAN_ADV_NC | ||
361 | static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open); | ||
362 | #endif | ||
351 | 363 | ||
352 | static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { | 364 | static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { |
353 | &batadv_debuginfo_originators, | 365 | &batadv_debuginfo_originators, |
@@ -362,6 +374,9 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { | |||
362 | #endif | 374 | #endif |
363 | &batadv_debuginfo_transtable_local, | 375 | &batadv_debuginfo_transtable_local, |
364 | &batadv_debuginfo_vis_data, | 376 | &batadv_debuginfo_vis_data, |
377 | #ifdef CONFIG_BATMAN_ADV_NC | ||
378 | &batadv_debuginfo_nc_nodes, | ||
379 | #endif | ||
365 | NULL, | 380 | NULL, |
366 | }; | 381 | }; |
367 | 382 | ||
@@ -431,6 +446,9 @@ int batadv_debugfs_add_meshif(struct net_device *dev) | |||
431 | } | 446 | } |
432 | } | 447 | } |
433 | 448 | ||
449 | if (batadv_nc_init_debugfs(bat_priv) < 0) | ||
450 | goto rem_attr; | ||
451 | |||
434 | return 0; | 452 | return 0; |
435 | rem_attr: | 453 | rem_attr: |
436 | debugfs_remove_recursive(bat_priv->debug_dir); | 454 | debugfs_remove_recursive(bat_priv->debug_dir); |
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 59ba2ff8e252..8a10619ae916 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h | |||
@@ -105,6 +105,8 @@ | |||
105 | #define BATADV_RESET_PROTECTION_MS 30000 | 105 | #define BATADV_RESET_PROTECTION_MS 30000 |
106 | #define BATADV_EXPECTED_SEQNO_RANGE 65536 | 106 | #define BATADV_EXPECTED_SEQNO_RANGE 65536 |
107 | 107 | ||
108 | #define BATADV_NC_NODE_TIMEOUT 10000 /* Milliseconds */ | ||
109 | |||
108 | enum batadv_mesh_state { | 110 | enum batadv_mesh_state { |
109 | BATADV_MESH_INACTIVE, | 111 | BATADV_MESH_INACTIVE, |
110 | BATADV_MESH_ACTIVE, | 112 | BATADV_MESH_ACTIVE, |
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 9c2d54bdd2ce..ff4985d84726 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c | |||
@@ -17,8 +17,12 @@ | |||
17 | * 02110-1301, USA | 17 | * 02110-1301, USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/debugfs.h> | ||
21 | |||
20 | #include "main.h" | 22 | #include "main.h" |
21 | #include "network-coding.h" | 23 | #include "network-coding.h" |
24 | #include "originator.h" | ||
25 | #include "hard-interface.h" | ||
22 | 26 | ||
23 | static void batadv_nc_worker(struct work_struct *work); | 27 | static void batadv_nc_worker(struct work_struct *work); |
24 | 28 | ||
@@ -51,6 +55,151 @@ int batadv_nc_init(struct batadv_priv *bat_priv) | |||
51 | void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) | 55 | void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) |
52 | { | 56 | { |
53 | atomic_set(&bat_priv->network_coding, 1); | 57 | atomic_set(&bat_priv->network_coding, 1); |
58 | bat_priv->nc.min_tq = 200; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * batadv_nc_init_orig - initialise the nc fields of an orig_node | ||
63 | * @orig_node: the orig_node which is going to be initialised | ||
64 | */ | ||
65 | void batadv_nc_init_orig(struct batadv_orig_node *orig_node) | ||
66 | { | ||
67 | INIT_LIST_HEAD(&orig_node->in_coding_list); | ||
68 | INIT_LIST_HEAD(&orig_node->out_coding_list); | ||
69 | spin_lock_init(&orig_node->in_coding_list_lock); | ||
70 | spin_lock_init(&orig_node->out_coding_list_lock); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * batadv_nc_node_free_rcu - rcu callback to free an nc node and remove | ||
75 | * its refcount on the orig_node | ||
76 | * @rcu: rcu pointer of the nc node | ||
77 | */ | ||
78 | static void batadv_nc_node_free_rcu(struct rcu_head *rcu) | ||
79 | { | ||
80 | struct batadv_nc_node *nc_node; | ||
81 | |||
82 | nc_node = container_of(rcu, struct batadv_nc_node, rcu); | ||
83 | batadv_orig_node_free_ref(nc_node->orig_node); | ||
84 | kfree(nc_node); | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * batadv_nc_node_free_ref - decrements the nc node refcounter and possibly | ||
89 | * frees it | ||
90 | * @nc_node: the nc node to free | ||
91 | */ | ||
92 | static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node) | ||
93 | { | ||
94 | if (atomic_dec_and_test(&nc_node->refcount)) | ||
95 | call_rcu(&nc_node->rcu, batadv_nc_node_free_rcu); | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged | ||
100 | * @bat_priv: the bat priv with all the soft interface information | ||
101 | * @nc_node: the nc node to check | ||
102 | * | ||
103 | * Returns true if the entry has to be purged now, false otherwise | ||
104 | */ | ||
105 | static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv, | ||
106 | struct batadv_nc_node *nc_node) | ||
107 | { | ||
108 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | ||
109 | return true; | ||
110 | |||
111 | return batadv_has_timed_out(nc_node->last_seen, BATADV_NC_NODE_TIMEOUT); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale | ||
116 | * entries | ||
117 | * @bat_priv: the bat priv with all the soft interface information | ||
118 | * @list: list of nc nodes | ||
119 | * @lock: nc node list lock | ||
120 | * @to_purge: function in charge to decide whether an entry has to be purged or | ||
121 | * not. This function takes the nc node as argument and has to return | ||
122 | * a boolean value: true if the entry has to be deleted, false | ||
123 | * otherwise | ||
124 | */ | ||
125 | static void | ||
126 | batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv, | ||
127 | struct list_head *list, | ||
128 | spinlock_t *lock, | ||
129 | bool (*to_purge)(struct batadv_priv *, | ||
130 | struct batadv_nc_node *)) | ||
131 | { | ||
132 | struct batadv_nc_node *nc_node, *nc_node_tmp; | ||
133 | |||
134 | /* For each nc_node in list */ | ||
135 | spin_lock_bh(lock); | ||
136 | list_for_each_entry_safe(nc_node, nc_node_tmp, list, list) { | ||
137 | /* if an helper function has been passed as parameter, | ||
138 | * ask it if the entry has to be purged or not | ||
139 | */ | ||
140 | if (to_purge && !to_purge(bat_priv, nc_node)) | ||
141 | continue; | ||
142 | |||
143 | batadv_dbg(BATADV_DBG_NC, bat_priv, | ||
144 | "Removing nc_node %pM -> %pM\n", | ||
145 | nc_node->addr, nc_node->orig_node->orig); | ||
146 | list_del_rcu(&nc_node->list); | ||
147 | batadv_nc_node_free_ref(nc_node); | ||
148 | } | ||
149 | spin_unlock_bh(lock); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * batadv_nc_purge_orig - purges all nc node data attached of the given | ||
154 | * originator | ||
155 | * @bat_priv: the bat priv with all the soft interface information | ||
156 | * @orig_node: orig_node with the nc node entries to be purged | ||
157 | * @to_purge: function in charge to decide whether an entry has to be purged or | ||
158 | * not. This function takes the nc node as argument and has to return | ||
159 | * a boolean value: true is the entry has to be deleted, false | ||
160 | * otherwise | ||
161 | */ | ||
162 | void batadv_nc_purge_orig(struct batadv_priv *bat_priv, | ||
163 | struct batadv_orig_node *orig_node, | ||
164 | bool (*to_purge)(struct batadv_priv *, | ||
165 | struct batadv_nc_node *)) | ||
166 | { | ||
167 | /* Check ingoing nc_node's of this orig_node */ | ||
168 | batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->in_coding_list, | ||
169 | &orig_node->in_coding_list_lock, | ||
170 | to_purge); | ||
171 | |||
172 | /* Check outgoing nc_node's of this orig_node */ | ||
173 | batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->out_coding_list, | ||
174 | &orig_node->out_coding_list_lock, | ||
175 | to_purge); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * batadv_nc_purge_orig_hash - traverse entire originator hash to check if they | ||
180 | * have timed out nc nodes | ||
181 | * @bat_priv: the bat priv with all the soft interface information | ||
182 | */ | ||
183 | static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv) | ||
184 | { | ||
185 | struct batadv_hashtable *hash = bat_priv->orig_hash; | ||
186 | struct hlist_head *head; | ||
187 | struct batadv_orig_node *orig_node; | ||
188 | uint32_t i; | ||
189 | |||
190 | if (!hash) | ||
191 | return; | ||
192 | |||
193 | /* For each orig_node */ | ||
194 | for (i = 0; i < hash->size; i++) { | ||
195 | head = &hash->table[i]; | ||
196 | |||
197 | rcu_read_lock(); | ||
198 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) | ||
199 | batadv_nc_purge_orig(bat_priv, orig_node, | ||
200 | batadv_nc_to_purge_nc_node); | ||
201 | rcu_read_unlock(); | ||
202 | } | ||
54 | } | 203 | } |
55 | 204 | ||
56 | /** | 205 | /** |
@@ -67,11 +216,197 @@ static void batadv_nc_worker(struct work_struct *work) | |||
67 | priv_nc = container_of(delayed_work, struct batadv_priv_nc, work); | 216 | priv_nc = container_of(delayed_work, struct batadv_priv_nc, work); |
68 | bat_priv = container_of(priv_nc, struct batadv_priv, nc); | 217 | bat_priv = container_of(priv_nc, struct batadv_priv, nc); |
69 | 218 | ||
219 | batadv_nc_purge_orig_hash(bat_priv); | ||
220 | |||
70 | /* Schedule a new check */ | 221 | /* Schedule a new check */ |
71 | batadv_nc_start_timer(bat_priv); | 222 | batadv_nc_start_timer(bat_priv); |
72 | } | 223 | } |
73 | 224 | ||
74 | /** | 225 | /** |
226 | * batadv_can_nc_with_orig - checks whether the given orig node is suitable for | ||
227 | * coding or not | ||
228 | * @bat_priv: the bat priv with all the soft interface information | ||
229 | * @orig_node: neighboring orig node which may be used as nc candidate | ||
230 | * @ogm_packet: incoming ogm packet also used for the checks | ||
231 | * | ||
232 | * Returns true if: | ||
233 | * 1) The OGM must have the most recent sequence number. | ||
234 | * 2) The TTL must be decremented by one and only one. | ||
235 | * 3) The OGM must be received from the first hop from orig_node. | ||
236 | * 4) The TQ value of the OGM must be above bat_priv->nc.min_tq. | ||
237 | */ | ||
238 | static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv, | ||
239 | struct batadv_orig_node *orig_node, | ||
240 | struct batadv_ogm_packet *ogm_packet) | ||
241 | { | ||
242 | if (orig_node->last_real_seqno != ogm_packet->seqno) | ||
243 | return false; | ||
244 | if (orig_node->last_ttl != ogm_packet->header.ttl + 1) | ||
245 | return false; | ||
246 | if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender)) | ||
247 | return false; | ||
248 | if (ogm_packet->tq < bat_priv->nc.min_tq) | ||
249 | return false; | ||
250 | |||
251 | return true; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * batadv_nc_find_nc_node - search for an existing nc node and return it | ||
256 | * @orig_node: orig node originating the ogm packet | ||
257 | * @orig_neigh_node: neighboring orig node from which we received the ogm packet | ||
258 | * (can be equal to orig_node) | ||
259 | * @in_coding: traverse incoming or outgoing network coding list | ||
260 | * | ||
261 | * Returns the nc_node if found, NULL otherwise. | ||
262 | */ | ||
263 | static struct batadv_nc_node | ||
264 | *batadv_nc_find_nc_node(struct batadv_orig_node *orig_node, | ||
265 | struct batadv_orig_node *orig_neigh_node, | ||
266 | bool in_coding) | ||
267 | { | ||
268 | struct batadv_nc_node *nc_node, *nc_node_out = NULL; | ||
269 | struct list_head *list; | ||
270 | |||
271 | if (in_coding) | ||
272 | list = &orig_neigh_node->in_coding_list; | ||
273 | else | ||
274 | list = &orig_neigh_node->out_coding_list; | ||
275 | |||
276 | /* Traverse list of nc_nodes to orig_node */ | ||
277 | rcu_read_lock(); | ||
278 | list_for_each_entry_rcu(nc_node, list, list) { | ||
279 | if (!batadv_compare_eth(nc_node->addr, orig_node->orig)) | ||
280 | continue; | ||
281 | |||
282 | if (!atomic_inc_not_zero(&nc_node->refcount)) | ||
283 | continue; | ||
284 | |||
285 | /* Found a match */ | ||
286 | nc_node_out = nc_node; | ||
287 | break; | ||
288 | } | ||
289 | rcu_read_unlock(); | ||
290 | |||
291 | return nc_node_out; | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * batadv_nc_get_nc_node - retrieves an nc node or creates the entry if it was | ||
296 | * not found | ||
297 | * @bat_priv: the bat priv with all the soft interface information | ||
298 | * @orig_node: orig node originating the ogm packet | ||
299 | * @orig_neigh_node: neighboring orig node from which we received the ogm packet | ||
300 | * (can be equal to orig_node) | ||
301 | * @in_coding: traverse incoming or outgoing network coding list | ||
302 | * | ||
303 | * Returns the nc_node if found or created, NULL in case of an error. | ||
304 | */ | ||
305 | static struct batadv_nc_node | ||
306 | *batadv_nc_get_nc_node(struct batadv_priv *bat_priv, | ||
307 | struct batadv_orig_node *orig_node, | ||
308 | struct batadv_orig_node *orig_neigh_node, | ||
309 | bool in_coding) | ||
310 | { | ||
311 | struct batadv_nc_node *nc_node; | ||
312 | spinlock_t *lock; /* Used to lock list selected by "int in_coding" */ | ||
313 | struct list_head *list; | ||
314 | |||
315 | /* Check if nc_node is already added */ | ||
316 | nc_node = batadv_nc_find_nc_node(orig_node, orig_neigh_node, in_coding); | ||
317 | |||
318 | /* Node found */ | ||
319 | if (nc_node) | ||
320 | return nc_node; | ||
321 | |||
322 | nc_node = kzalloc(sizeof(*nc_node), GFP_ATOMIC); | ||
323 | if (!nc_node) | ||
324 | return NULL; | ||
325 | |||
326 | if (!atomic_inc_not_zero(&orig_neigh_node->refcount)) | ||
327 | goto free; | ||
328 | |||
329 | /* Initialize nc_node */ | ||
330 | INIT_LIST_HEAD(&nc_node->list); | ||
331 | memcpy(nc_node->addr, orig_node->orig, ETH_ALEN); | ||
332 | nc_node->orig_node = orig_neigh_node; | ||
333 | atomic_set(&nc_node->refcount, 2); | ||
334 | |||
335 | /* Select ingoing or outgoing coding node */ | ||
336 | if (in_coding) { | ||
337 | lock = &orig_neigh_node->in_coding_list_lock; | ||
338 | list = &orig_neigh_node->in_coding_list; | ||
339 | } else { | ||
340 | lock = &orig_neigh_node->out_coding_list_lock; | ||
341 | list = &orig_neigh_node->out_coding_list; | ||
342 | } | ||
343 | |||
344 | batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_node %pM -> %pM\n", | ||
345 | nc_node->addr, nc_node->orig_node->orig); | ||
346 | |||
347 | /* Add nc_node to orig_node */ | ||
348 | spin_lock_bh(lock); | ||
349 | list_add_tail_rcu(&nc_node->list, list); | ||
350 | spin_unlock_bh(lock); | ||
351 | |||
352 | return nc_node; | ||
353 | |||
354 | free: | ||
355 | kfree(nc_node); | ||
356 | return NULL; | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * batadv_nc_update_nc_node - updates stored incoming and outgoing nc node structs | ||
361 | * (best called on incoming OGMs) | ||
362 | * @bat_priv: the bat priv with all the soft interface information | ||
363 | * @orig_node: orig node originating the ogm packet | ||
364 | * @orig_neigh_node: neighboring orig node from which we received the ogm packet | ||
365 | * (can be equal to orig_node) | ||
366 | * @ogm_packet: incoming ogm packet | ||
367 | * @is_single_hop_neigh: orig_node is a single hop neighbor | ||
368 | */ | ||
369 | void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, | ||
370 | struct batadv_orig_node *orig_node, | ||
371 | struct batadv_orig_node *orig_neigh_node, | ||
372 | struct batadv_ogm_packet *ogm_packet, | ||
373 | int is_single_hop_neigh) | ||
374 | { | ||
375 | struct batadv_nc_node *in_nc_node = NULL, *out_nc_node = NULL; | ||
376 | |||
377 | /* Check if network coding is enabled */ | ||
378 | if (!atomic_read(&bat_priv->network_coding)) | ||
379 | goto out; | ||
380 | |||
381 | /* accept ogms from 'good' neighbors and single hop neighbors */ | ||
382 | if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) && | ||
383 | !is_single_hop_neigh) | ||
384 | goto out; | ||
385 | |||
386 | /* Add orig_node as in_nc_node on hop */ | ||
387 | in_nc_node = batadv_nc_get_nc_node(bat_priv, orig_node, | ||
388 | orig_neigh_node, true); | ||
389 | if (!in_nc_node) | ||
390 | goto out; | ||
391 | |||
392 | in_nc_node->last_seen = jiffies; | ||
393 | |||
394 | /* Add hop as out_nc_node on orig_node */ | ||
395 | out_nc_node = batadv_nc_get_nc_node(bat_priv, orig_neigh_node, | ||
396 | orig_node, false); | ||
397 | if (!out_nc_node) | ||
398 | goto out; | ||
399 | |||
400 | out_nc_node->last_seen = jiffies; | ||
401 | |||
402 | out: | ||
403 | if (in_nc_node) | ||
404 | batadv_nc_node_free_ref(in_nc_node); | ||
405 | if (out_nc_node) | ||
406 | batadv_nc_node_free_ref(out_nc_node); | ||
407 | } | ||
408 | |||
409 | /** | ||
75 | * batadv_nc_free - clean up network coding memory | 410 | * batadv_nc_free - clean up network coding memory |
76 | * @bat_priv: the bat priv with all the soft interface information | 411 | * @bat_priv: the bat priv with all the soft interface information |
77 | */ | 412 | */ |
@@ -79,3 +414,82 @@ void batadv_nc_free(struct batadv_priv *bat_priv) | |||
79 | { | 414 | { |
80 | cancel_delayed_work_sync(&bat_priv->nc.work); | 415 | cancel_delayed_work_sync(&bat_priv->nc.work); |
81 | } | 416 | } |
417 | |||
418 | /** | ||
419 | * batadv_nc_nodes_seq_print_text - print the nc node information | ||
420 | * @seq: seq file to print on | ||
421 | * @offset: not used | ||
422 | */ | ||
423 | int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset) | ||
424 | { | ||
425 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
426 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
427 | struct batadv_hashtable *hash = bat_priv->orig_hash; | ||
428 | struct batadv_hard_iface *primary_if; | ||
429 | struct hlist_head *head; | ||
430 | struct batadv_orig_node *orig_node; | ||
431 | struct batadv_nc_node *nc_node; | ||
432 | int i; | ||
433 | |||
434 | primary_if = batadv_seq_print_text_primary_if_get(seq); | ||
435 | if (!primary_if) | ||
436 | goto out; | ||
437 | |||
438 | /* Traverse list of originators */ | ||
439 | for (i = 0; i < hash->size; i++) { | ||
440 | head = &hash->table[i]; | ||
441 | |||
442 | /* For each orig_node in this bin */ | ||
443 | rcu_read_lock(); | ||
444 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { | ||
445 | seq_printf(seq, "Node: %pM\n", orig_node->orig); | ||
446 | |||
447 | seq_printf(seq, " Ingoing: "); | ||
448 | /* For each in_nc_node to this orig_node */ | ||
449 | list_for_each_entry_rcu(nc_node, | ||
450 | &orig_node->in_coding_list, | ||
451 | list) | ||
452 | seq_printf(seq, "%pM ", | ||
453 | nc_node->addr); | ||
454 | seq_printf(seq, "\n"); | ||
455 | |||
456 | seq_printf(seq, " Outgoing: "); | ||
457 | /* For out_nc_node to this orig_node */ | ||
458 | list_for_each_entry_rcu(nc_node, | ||
459 | &orig_node->out_coding_list, | ||
460 | list) | ||
461 | seq_printf(seq, "%pM ", | ||
462 | nc_node->addr); | ||
463 | seq_printf(seq, "\n\n"); | ||
464 | } | ||
465 | rcu_read_unlock(); | ||
466 | } | ||
467 | |||
468 | out: | ||
469 | if (primary_if) | ||
470 | batadv_hardif_free_ref(primary_if); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | /** | ||
475 | * batadv_nc_init_debugfs - create nc folder and related files in debugfs | ||
476 | * @bat_priv: the bat priv with all the soft interface information | ||
477 | */ | ||
478 | int batadv_nc_init_debugfs(struct batadv_priv *bat_priv) | ||
479 | { | ||
480 | struct dentry *nc_dir, *file; | ||
481 | |||
482 | nc_dir = debugfs_create_dir("nc", bat_priv->debug_dir); | ||
483 | if (!nc_dir) | ||
484 | goto out; | ||
485 | |||
486 | file = debugfs_create_u8("min_tq", S_IRUGO | S_IWUSR, nc_dir, | ||
487 | &bat_priv->nc.min_tq); | ||
488 | if (!file) | ||
489 | goto out; | ||
490 | |||
491 | return 0; | ||
492 | |||
493 | out: | ||
494 | return -ENOMEM; | ||
495 | } | ||
diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h index 7483cba4b5d4..4c56cd98d9de 100644 --- a/net/batman-adv/network-coding.h +++ b/net/batman-adv/network-coding.h | |||
@@ -24,7 +24,19 @@ | |||
24 | 24 | ||
25 | int batadv_nc_init(struct batadv_priv *bat_priv); | 25 | int batadv_nc_init(struct batadv_priv *bat_priv); |
26 | void batadv_nc_free(struct batadv_priv *bat_priv); | 26 | void batadv_nc_free(struct batadv_priv *bat_priv); |
27 | void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, | ||
28 | struct batadv_orig_node *orig_node, | ||
29 | struct batadv_orig_node *orig_neigh_node, | ||
30 | struct batadv_ogm_packet *ogm_packet, | ||
31 | int is_single_hop_neigh); | ||
32 | void batadv_nc_purge_orig(struct batadv_priv *bat_priv, | ||
33 | struct batadv_orig_node *orig_node, | ||
34 | bool (*to_purge)(struct batadv_priv *, | ||
35 | struct batadv_nc_node *)); | ||
27 | void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv); | 36 | void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv); |
37 | void batadv_nc_init_orig(struct batadv_orig_node *orig_node); | ||
38 | int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset); | ||
39 | int batadv_nc_init_debugfs(struct batadv_priv *bat_priv); | ||
28 | 40 | ||
29 | #else /* ifdef CONFIG_BATMAN_ADV_NC */ | 41 | #else /* ifdef CONFIG_BATMAN_ADV_NC */ |
30 | 42 | ||
@@ -38,11 +50,46 @@ static inline void batadv_nc_free(struct batadv_priv *bat_priv) | |||
38 | return; | 50 | return; |
39 | } | 51 | } |
40 | 52 | ||
53 | static inline void | ||
54 | batadv_nc_update_nc_node(struct batadv_priv *bat_priv, | ||
55 | struct batadv_orig_node *orig_node, | ||
56 | struct batadv_orig_node *orig_neigh_node, | ||
57 | struct batadv_ogm_packet *ogm_packet, | ||
58 | int is_single_hop_neigh) | ||
59 | { | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | static inline void | ||
64 | batadv_nc_purge_orig(struct batadv_priv *bat_priv, | ||
65 | struct batadv_orig_node *orig_node, | ||
66 | bool (*to_purge)(struct batadv_priv *, | ||
67 | struct batadv_nc_node *)) | ||
68 | { | ||
69 | return; | ||
70 | } | ||
71 | |||
41 | static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) | 72 | static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) |
42 | { | 73 | { |
43 | return; | 74 | return; |
44 | } | 75 | } |
45 | 76 | ||
77 | static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node) | ||
78 | { | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq, | ||
83 | void *offset) | ||
84 | { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static inline int batadv_nc_init_debugfs(struct batadv_priv *bat_priv) | ||
89 | { | ||
90 | return 0; | ||
91 | } | ||
92 | |||
46 | #endif /* ifdef CONFIG_BATMAN_ADV_NC */ | 93 | #endif /* ifdef CONFIG_BATMAN_ADV_NC */ |
47 | 94 | ||
48 | #endif /* _NET_BATMAN_ADV_NETWORK_CODING_H_ */ | 95 | #endif /* _NET_BATMAN_ADV_NETWORK_CODING_H_ */ |
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 96fb80b724dc..585e684a380b 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "unicast.h" | 28 | #include "unicast.h" |
29 | #include "soft-interface.h" | 29 | #include "soft-interface.h" |
30 | #include "bridge_loop_avoidance.h" | 30 | #include "bridge_loop_avoidance.h" |
31 | #include "network-coding.h" | ||
31 | 32 | ||
32 | /* hash class keys */ | 33 | /* hash class keys */ |
33 | static struct lock_class_key batadv_orig_hash_lock_class_key; | 34 | static struct lock_class_key batadv_orig_hash_lock_class_key; |
@@ -142,6 +143,9 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) | |||
142 | 143 | ||
143 | spin_unlock_bh(&orig_node->neigh_list_lock); | 144 | spin_unlock_bh(&orig_node->neigh_list_lock); |
144 | 145 | ||
146 | /* Free nc_nodes */ | ||
147 | batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL); | ||
148 | |||
145 | batadv_frag_list_free(&orig_node->frag_list); | 149 | batadv_frag_list_free(&orig_node->frag_list); |
146 | batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, | 150 | batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, |
147 | "originator timed out"); | 151 | "originator timed out"); |
@@ -219,6 +223,8 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
219 | spin_lock_init(&orig_node->neigh_list_lock); | 223 | spin_lock_init(&orig_node->neigh_list_lock); |
220 | spin_lock_init(&orig_node->tt_buff_lock); | 224 | spin_lock_init(&orig_node->tt_buff_lock); |
221 | 225 | ||
226 | batadv_nc_init_orig(orig_node); | ||
227 | |||
222 | /* extra reference for return */ | 228 | /* extra reference for return */ |
223 | atomic_set(&orig_node->refcount, 2); | 229 | atomic_set(&orig_node->refcount, 2); |
224 | 230 | ||
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 83bfe7c38f81..1544ab40bedd 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -128,6 +128,10 @@ struct batadv_hard_iface { | |||
128 | * @bond_list: list of bonding candidates | 128 | * @bond_list: list of bonding candidates |
129 | * @refcount: number of contexts the object is used | 129 | * @refcount: number of contexts the object is used |
130 | * @rcu: struct used for freeing in an RCU-safe manner | 130 | * @rcu: struct used for freeing in an RCU-safe manner |
131 | * @in_coding_list: list of nodes this orig can hear | ||
132 | * @out_coding_list: list of nodes that can hear this orig | ||
133 | * @in_coding_list_lock: protects in_coding_list | ||
134 | * @out_coding_list_lock: protects out_coding_list | ||
131 | */ | 135 | */ |
132 | struct batadv_orig_node { | 136 | struct batadv_orig_node { |
133 | uint8_t orig[ETH_ALEN]; | 137 | uint8_t orig[ETH_ALEN]; |
@@ -171,6 +175,12 @@ struct batadv_orig_node { | |||
171 | struct list_head bond_list; | 175 | struct list_head bond_list; |
172 | atomic_t refcount; | 176 | atomic_t refcount; |
173 | struct rcu_head rcu; | 177 | struct rcu_head rcu; |
178 | #ifdef CONFIG_BATMAN_ADV_NC | ||
179 | struct list_head in_coding_list; | ||
180 | struct list_head out_coding_list; | ||
181 | spinlock_t in_coding_list_lock; /* Protects in_coding_list */ | ||
182 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ | ||
183 | #endif | ||
174 | }; | 184 | }; |
175 | 185 | ||
176 | /** | 186 | /** |
@@ -430,9 +440,13 @@ struct batadv_priv_dat { | |||
430 | /** | 440 | /** |
431 | * struct batadv_priv_nc - per mesh interface network coding private data | 441 | * struct batadv_priv_nc - per mesh interface network coding private data |
432 | * @work: work queue callback item for cleanup | 442 | * @work: work queue callback item for cleanup |
443 | * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs | ||
444 | * @min_tq: only consider neighbors for encoding if neigh_tq > min_tq | ||
433 | */ | 445 | */ |
434 | struct batadv_priv_nc { | 446 | struct batadv_priv_nc { |
435 | struct delayed_work work; | 447 | struct delayed_work work; |
448 | struct dentry *debug_dir; | ||
449 | u8 min_tq; | ||
436 | }; | 450 | }; |
437 | 451 | ||
438 | /** | 452 | /** |
@@ -716,6 +730,24 @@ struct batadv_tt_roam_node { | |||
716 | }; | 730 | }; |
717 | 731 | ||
718 | /** | 732 | /** |
733 | * struct batadv_nc_node - network coding node | ||
734 | * @list: next and prev pointer for the list handling | ||
735 | * @addr: the node's mac address | ||
736 | * @refcount: number of contexts the object is used by | ||
737 | * @rcu: struct used for freeing in an RCU-safe manner | ||
738 | * @orig_node: pointer to corresponding orig node struct | ||
739 | * @last_seen: timestamp of last ogm received from this node | ||
740 | */ | ||
741 | struct batadv_nc_node { | ||
742 | struct list_head list; | ||
743 | uint8_t addr[ETH_ALEN]; | ||
744 | atomic_t refcount; | ||
745 | struct rcu_head rcu; | ||
746 | struct batadv_orig_node *orig_node; | ||
747 | unsigned long last_seen; | ||
748 | }; | ||
749 | |||
750 | /** | ||
719 | * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded | 751 | * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded |
720 | * @list: list node for batadv_socket_client::queue_list | 752 | * @list: list node for batadv_socket_client::queue_list |
721 | * @send_time: execution time for delayed_work (packet sending) | 753 | * @send_time: execution time for delayed_work (packet sending) |