network-coding.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
  2. *
  3. * Martin Hundebøll, Jeppe Ledet-Pedersen
  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, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA
  18. */
  19. #include <linux/debugfs.h>
  20. #include "main.h"
  21. #include "network-coding.h"
  22. #include "originator.h"
  23. #include "hard-interface.h"
  24. static void batadv_nc_worker(struct work_struct *work);
  25. /**
  26. * batadv_nc_start_timer - initialise the nc periodic worker
  27. * @bat_priv: the bat priv with all the soft interface information
  28. */
  29. static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
  30. {
  31. queue_delayed_work(batadv_event_workqueue, &bat_priv->nc.work,
  32. msecs_to_jiffies(10));
  33. }
  34. /**
  35. * batadv_nc_init - initialise coding hash table and start house keeping
  36. * @bat_priv: the bat priv with all the soft interface information
  37. */
  38. int batadv_nc_init(struct batadv_priv *bat_priv)
  39. {
  40. INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
  41. batadv_nc_start_timer(bat_priv);
  42. return 0;
  43. }
  44. /**
  45. * batadv_nc_init_bat_priv - initialise the nc specific bat_priv variables
  46. * @bat_priv: the bat priv with all the soft interface information
  47. */
  48. void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
  49. {
  50. atomic_set(&bat_priv->network_coding, 1);
  51. bat_priv->nc.min_tq = 200;
  52. }
  53. /**
  54. * batadv_nc_init_orig - initialise the nc fields of an orig_node
  55. * @orig_node: the orig_node which is going to be initialised
  56. */
  57. void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
  58. {
  59. INIT_LIST_HEAD(&orig_node->in_coding_list);
  60. INIT_LIST_HEAD(&orig_node->out_coding_list);
  61. spin_lock_init(&orig_node->in_coding_list_lock);
  62. spin_lock_init(&orig_node->out_coding_list_lock);
  63. }
  64. /**
  65. * batadv_nc_node_free_rcu - rcu callback to free an nc node and remove
  66. * its refcount on the orig_node
  67. * @rcu: rcu pointer of the nc node
  68. */
  69. static void batadv_nc_node_free_rcu(struct rcu_head *rcu)
  70. {
  71. struct batadv_nc_node *nc_node;
  72. nc_node = container_of(rcu, struct batadv_nc_node, rcu);
  73. batadv_orig_node_free_ref(nc_node->orig_node);
  74. kfree(nc_node);
  75. }
  76. /**
  77. * batadv_nc_node_free_ref - decrements the nc node refcounter and possibly
  78. * frees it
  79. * @nc_node: the nc node to free
  80. */
  81. static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node)
  82. {
  83. if (atomic_dec_and_test(&nc_node->refcount))
  84. call_rcu(&nc_node->rcu, batadv_nc_node_free_rcu);
  85. }
  86. /**
  87. * batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged
  88. * @bat_priv: the bat priv with all the soft interface information
  89. * @nc_node: the nc node to check
  90. *
  91. * Returns true if the entry has to be purged now, false otherwise
  92. */
  93. static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv,
  94. struct batadv_nc_node *nc_node)
  95. {
  96. if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
  97. return true;
  98. return batadv_has_timed_out(nc_node->last_seen, BATADV_NC_NODE_TIMEOUT);
  99. }
  100. /**
  101. * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale
  102. * entries
  103. * @bat_priv: the bat priv with all the soft interface information
  104. * @list: list of nc nodes
  105. * @lock: nc node list lock
  106. * @to_purge: function in charge to decide whether an entry has to be purged or
  107. * not. This function takes the nc node as argument and has to return
  108. * a boolean value: true if the entry has to be deleted, false
  109. * otherwise
  110. */
  111. static void
  112. batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv,
  113. struct list_head *list,
  114. spinlock_t *lock,
  115. bool (*to_purge)(struct batadv_priv *,
  116. struct batadv_nc_node *))
  117. {
  118. struct batadv_nc_node *nc_node, *nc_node_tmp;
  119. /* For each nc_node in list */
  120. spin_lock_bh(lock);
  121. list_for_each_entry_safe(nc_node, nc_node_tmp, list, list) {
  122. /* if an helper function has been passed as parameter,
  123. * ask it if the entry has to be purged or not
  124. */
  125. if (to_purge && !to_purge(bat_priv, nc_node))
  126. continue;
  127. batadv_dbg(BATADV_DBG_NC, bat_priv,
  128. "Removing nc_node %pM -> %pM\n",
  129. nc_node->addr, nc_node->orig_node->orig);
  130. list_del_rcu(&nc_node->list);
  131. batadv_nc_node_free_ref(nc_node);
  132. }
  133. spin_unlock_bh(lock);
  134. }
  135. /**
  136. * batadv_nc_purge_orig - purges all nc node data attached of the given
  137. * originator
  138. * @bat_priv: the bat priv with all the soft interface information
  139. * @orig_node: orig_node with the nc node entries to be purged
  140. * @to_purge: function in charge to decide whether an entry has to be purged or
  141. * not. This function takes the nc node as argument and has to return
  142. * a boolean value: true is the entry has to be deleted, false
  143. * otherwise
  144. */
  145. void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
  146. struct batadv_orig_node *orig_node,
  147. bool (*to_purge)(struct batadv_priv *,
  148. struct batadv_nc_node *))
  149. {
  150. /* Check ingoing nc_node's of this orig_node */
  151. batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->in_coding_list,
  152. &orig_node->in_coding_list_lock,
  153. to_purge);
  154. /* Check outgoing nc_node's of this orig_node */
  155. batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->out_coding_list,
  156. &orig_node->out_coding_list_lock,
  157. to_purge);
  158. }
  159. /**
  160. * batadv_nc_purge_orig_hash - traverse entire originator hash to check if they
  161. * have timed out nc nodes
  162. * @bat_priv: the bat priv with all the soft interface information
  163. */
  164. static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv)
  165. {
  166. struct batadv_hashtable *hash = bat_priv->orig_hash;
  167. struct hlist_head *head;
  168. struct batadv_orig_node *orig_node;
  169. uint32_t i;
  170. if (!hash)
  171. return;
  172. /* For each orig_node */
  173. for (i = 0; i < hash->size; i++) {
  174. head = &hash->table[i];
  175. rcu_read_lock();
  176. hlist_for_each_entry_rcu(orig_node, head, hash_entry)
  177. batadv_nc_purge_orig(bat_priv, orig_node,
  178. batadv_nc_to_purge_nc_node);
  179. rcu_read_unlock();
  180. }
  181. }
  182. /**
  183. * batadv_nc_worker - periodic task for house keeping related to network coding
  184. * @work: kernel work struct
  185. */
  186. static void batadv_nc_worker(struct work_struct *work)
  187. {
  188. struct delayed_work *delayed_work;
  189. struct batadv_priv_nc *priv_nc;
  190. struct batadv_priv *bat_priv;
  191. delayed_work = container_of(work, struct delayed_work, work);
  192. priv_nc = container_of(delayed_work, struct batadv_priv_nc, work);
  193. bat_priv = container_of(priv_nc, struct batadv_priv, nc);
  194. batadv_nc_purge_orig_hash(bat_priv);
  195. /* Schedule a new check */
  196. batadv_nc_start_timer(bat_priv);
  197. }
  198. /**
  199. * batadv_can_nc_with_orig - checks whether the given orig node is suitable for
  200. * coding or not
  201. * @bat_priv: the bat priv with all the soft interface information
  202. * @orig_node: neighboring orig node which may be used as nc candidate
  203. * @ogm_packet: incoming ogm packet also used for the checks
  204. *
  205. * Returns true if:
  206. * 1) The OGM must have the most recent sequence number.
  207. * 2) The TTL must be decremented by one and only one.
  208. * 3) The OGM must be received from the first hop from orig_node.
  209. * 4) The TQ value of the OGM must be above bat_priv->nc.min_tq.
  210. */
  211. static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
  212. struct batadv_orig_node *orig_node,
  213. struct batadv_ogm_packet *ogm_packet)
  214. {
  215. if (orig_node->last_real_seqno != ogm_packet->seqno)
  216. return false;
  217. if (orig_node->last_ttl != ogm_packet->header.ttl + 1)
  218. return false;
  219. if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
  220. return false;
  221. if (ogm_packet->tq < bat_priv->nc.min_tq)
  222. return false;
  223. return true;
  224. }
  225. /**
  226. * batadv_nc_find_nc_node - search for an existing nc node and return it
  227. * @orig_node: orig node originating the ogm packet
  228. * @orig_neigh_node: neighboring orig node from which we received the ogm packet
  229. * (can be equal to orig_node)
  230. * @in_coding: traverse incoming or outgoing network coding list
  231. *
  232. * Returns the nc_node if found, NULL otherwise.
  233. */
  234. static struct batadv_nc_node
  235. *batadv_nc_find_nc_node(struct batadv_orig_node *orig_node,
  236. struct batadv_orig_node *orig_neigh_node,
  237. bool in_coding)
  238. {
  239. struct batadv_nc_node *nc_node, *nc_node_out = NULL;
  240. struct list_head *list;
  241. if (in_coding)
  242. list = &orig_neigh_node->in_coding_list;
  243. else
  244. list = &orig_neigh_node->out_coding_list;
  245. /* Traverse list of nc_nodes to orig_node */
  246. rcu_read_lock();
  247. list_for_each_entry_rcu(nc_node, list, list) {
  248. if (!batadv_compare_eth(nc_node->addr, orig_node->orig))
  249. continue;
  250. if (!atomic_inc_not_zero(&nc_node->refcount))
  251. continue;
  252. /* Found a match */
  253. nc_node_out = nc_node;
  254. break;
  255. }
  256. rcu_read_unlock();
  257. return nc_node_out;
  258. }
  259. /**
  260. * batadv_nc_get_nc_node - retrieves an nc node or creates the entry if it was
  261. * not found
  262. * @bat_priv: the bat priv with all the soft interface information
  263. * @orig_node: orig node originating the ogm packet
  264. * @orig_neigh_node: neighboring orig node from which we received the ogm packet
  265. * (can be equal to orig_node)
  266. * @in_coding: traverse incoming or outgoing network coding list
  267. *
  268. * Returns the nc_node if found or created, NULL in case of an error.
  269. */
  270. static struct batadv_nc_node
  271. *batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
  272. struct batadv_orig_node *orig_node,
  273. struct batadv_orig_node *orig_neigh_node,
  274. bool in_coding)
  275. {
  276. struct batadv_nc_node *nc_node;
  277. spinlock_t *lock; /* Used to lock list selected by "int in_coding" */
  278. struct list_head *list;
  279. /* Check if nc_node is already added */
  280. nc_node = batadv_nc_find_nc_node(orig_node, orig_neigh_node, in_coding);
  281. /* Node found */
  282. if (nc_node)
  283. return nc_node;
  284. nc_node = kzalloc(sizeof(*nc_node), GFP_ATOMIC);
  285. if (!nc_node)
  286. return NULL;
  287. if (!atomic_inc_not_zero(&orig_neigh_node->refcount))
  288. goto free;
  289. /* Initialize nc_node */
  290. INIT_LIST_HEAD(&nc_node->list);
  291. memcpy(nc_node->addr, orig_node->orig, ETH_ALEN);
  292. nc_node->orig_node = orig_neigh_node;
  293. atomic_set(&nc_node->refcount, 2);
  294. /* Select ingoing or outgoing coding node */
  295. if (in_coding) {
  296. lock = &orig_neigh_node->in_coding_list_lock;
  297. list = &orig_neigh_node->in_coding_list;
  298. } else {
  299. lock = &orig_neigh_node->out_coding_list_lock;
  300. list = &orig_neigh_node->out_coding_list;
  301. }
  302. batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_node %pM -> %pM\n",
  303. nc_node->addr, nc_node->orig_node->orig);
  304. /* Add nc_node to orig_node */
  305. spin_lock_bh(lock);
  306. list_add_tail_rcu(&nc_node->list, list);
  307. spin_unlock_bh(lock);
  308. return nc_node;
  309. free:
  310. kfree(nc_node);
  311. return NULL;
  312. }
  313. /**
  314. * batadv_nc_update_nc_node - updates stored incoming and outgoing nc node structs
  315. * (best called on incoming OGMs)
  316. * @bat_priv: the bat priv with all the soft interface information
  317. * @orig_node: orig node originating the ogm packet
  318. * @orig_neigh_node: neighboring orig node from which we received the ogm packet
  319. * (can be equal to orig_node)
  320. * @ogm_packet: incoming ogm packet
  321. * @is_single_hop_neigh: orig_node is a single hop neighbor
  322. */
  323. void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
  324. struct batadv_orig_node *orig_node,
  325. struct batadv_orig_node *orig_neigh_node,
  326. struct batadv_ogm_packet *ogm_packet,
  327. int is_single_hop_neigh)
  328. {
  329. struct batadv_nc_node *in_nc_node = NULL, *out_nc_node = NULL;
  330. /* Check if network coding is enabled */
  331. if (!atomic_read(&bat_priv->network_coding))
  332. goto out;
  333. /* accept ogms from 'good' neighbors and single hop neighbors */
  334. if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) &&
  335. !is_single_hop_neigh)
  336. goto out;
  337. /* Add orig_node as in_nc_node on hop */
  338. in_nc_node = batadv_nc_get_nc_node(bat_priv, orig_node,
  339. orig_neigh_node, true);
  340. if (!in_nc_node)
  341. goto out;
  342. in_nc_node->last_seen = jiffies;
  343. /* Add hop as out_nc_node on orig_node */
  344. out_nc_node = batadv_nc_get_nc_node(bat_priv, orig_neigh_node,
  345. orig_node, false);
  346. if (!out_nc_node)
  347. goto out;
  348. out_nc_node->last_seen = jiffies;
  349. out:
  350. if (in_nc_node)
  351. batadv_nc_node_free_ref(in_nc_node);
  352. if (out_nc_node)
  353. batadv_nc_node_free_ref(out_nc_node);
  354. }
  355. /**
  356. * batadv_nc_free - clean up network coding memory
  357. * @bat_priv: the bat priv with all the soft interface information
  358. */
  359. void batadv_nc_free(struct batadv_priv *bat_priv)
  360. {
  361. cancel_delayed_work_sync(&bat_priv->nc.work);
  362. }
  363. /**
  364. * batadv_nc_nodes_seq_print_text - print the nc node information
  365. * @seq: seq file to print on
  366. * @offset: not used
  367. */
  368. int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
  369. {
  370. struct net_device *net_dev = (struct net_device *)seq->private;
  371. struct batadv_priv *bat_priv = netdev_priv(net_dev);
  372. struct batadv_hashtable *hash = bat_priv->orig_hash;
  373. struct batadv_hard_iface *primary_if;
  374. struct hlist_head *head;
  375. struct batadv_orig_node *orig_node;
  376. struct batadv_nc_node *nc_node;
  377. int i;
  378. primary_if = batadv_seq_print_text_primary_if_get(seq);
  379. if (!primary_if)
  380. goto out;
  381. /* Traverse list of originators */
  382. for (i = 0; i < hash->size; i++) {
  383. head = &hash->table[i];
  384. /* For each orig_node in this bin */
  385. rcu_read_lock();
  386. hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
  387. seq_printf(seq, "Node: %pM\n", orig_node->orig);
  388. seq_printf(seq, " Ingoing: ");
  389. /* For each in_nc_node to this orig_node */
  390. list_for_each_entry_rcu(nc_node,
  391. &orig_node->in_coding_list,
  392. list)
  393. seq_printf(seq, "%pM ",
  394. nc_node->addr);
  395. seq_printf(seq, "\n");
  396. seq_printf(seq, " Outgoing: ");
  397. /* For out_nc_node to this orig_node */
  398. list_for_each_entry_rcu(nc_node,
  399. &orig_node->out_coding_list,
  400. list)
  401. seq_printf(seq, "%pM ",
  402. nc_node->addr);
  403. seq_printf(seq, "\n\n");
  404. }
  405. rcu_read_unlock();
  406. }
  407. out:
  408. if (primary_if)
  409. batadv_hardif_free_ref(primary_if);
  410. return 0;
  411. }
  412. /**
  413. * batadv_nc_init_debugfs - create nc folder and related files in debugfs
  414. * @bat_priv: the bat priv with all the soft interface information
  415. */
  416. int batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
  417. {
  418. struct dentry *nc_dir, *file;
  419. nc_dir = debugfs_create_dir("nc", bat_priv->debug_dir);
  420. if (!nc_dir)
  421. goto out;
  422. file = debugfs_create_u8("min_tq", S_IRUGO | S_IWUSR, nc_dir,
  423. &bat_priv->nc.min_tq);
  424. if (!file)
  425. goto out;
  426. return 0;
  427. out:
  428. return -ENOMEM;
  429. }