alias.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * netifd - network interface daemon
  3. * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2
  7. * as published by the Free Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include "netifd.h"
  18. #include "device.h"
  19. #include "interface.h"
  20. static struct avl_tree aliases;
  21. struct alias_device {
  22. struct avl_node avl;
  23. struct device dev;
  24. struct device_user dep;
  25. struct device_user new_dep;
  26. bool update;
  27. char name[];
  28. };
  29. static void alias_set_device(struct alias_device *alias, struct device *dev)
  30. {
  31. if (dev == alias->dep.dev) {
  32. if (alias->update) {
  33. device_remove_user(&alias->new_dep);
  34. alias->update = false;
  35. if (dev)
  36. device_set_present(&alias->dev, true);
  37. }
  38. return;
  39. }
  40. device_set_present(&alias->dev, false);
  41. device_remove_user(&alias->new_dep);
  42. if (alias->dev.active) {
  43. if (dev)
  44. device_add_user(&alias->new_dep, dev);
  45. alias->update = true;
  46. return;
  47. }
  48. alias->update = false;
  49. device_remove_user(&alias->dep);
  50. alias->dev.hidden = !dev;
  51. if (dev) {
  52. device_set_ifindex(&alias->dev, dev->ifindex);
  53. device_set_ifname(&alias->dev, dev->ifname);
  54. device_add_user(&alias->dep, dev);
  55. } else {
  56. device_set_ifname(&alias->dev, "");
  57. device_set_link(&alias->dev, false);
  58. }
  59. }
  60. static int
  61. alias_device_set_state(struct device *dev, bool state)
  62. {
  63. struct alias_device *alias;
  64. alias = container_of(dev, struct alias_device, dev);
  65. if (!alias->dep.dev)
  66. return -1;
  67. if (state)
  68. return device_claim(&alias->dep);
  69. device_release(&alias->dep);
  70. if (alias->update)
  71. alias_set_device(alias, alias->new_dep.dev);
  72. return 0;
  73. }
  74. static void alias_device_cb(struct device_user *dep, enum device_event ev)
  75. {
  76. struct alias_device *alias;
  77. alias = container_of(dep, struct alias_device, dep);
  78. switch (ev) {
  79. case DEV_EVENT_ADD:
  80. device_set_present(&alias->dev, true);
  81. break;
  82. case DEV_EVENT_REMOVE:
  83. device_set_present(&alias->dev, false);
  84. break;
  85. case DEV_EVENT_LINK_UP:
  86. device_set_link(&alias->dev, true);
  87. break;
  88. case DEV_EVENT_LINK_DOWN:
  89. device_set_link(&alias->dev, false);
  90. break;
  91. case DEV_EVENT_UPDATE_IFINDEX:
  92. device_set_ifindex(&alias->dev, dep->dev->ifindex);
  93. break;
  94. default:
  95. device_broadcast_event(&alias->dev, ev);
  96. break;
  97. }
  98. }
  99. static struct device *
  100. alias_device_create(const char *name, struct device_type *devtype,
  101. struct blob_attr *attr)
  102. {
  103. struct alias_device *alias;
  104. alias = calloc(1, sizeof(*alias) + strlen(name) + 1);
  105. if (!alias)
  106. return NULL;
  107. strcpy(alias->name, name);
  108. alias->dev.set_state = alias_device_set_state;
  109. alias->dev.hidden = true;
  110. if (device_init_virtual(&alias->dev, devtype, NULL) < 0) {
  111. free(alias);
  112. return NULL;
  113. }
  114. alias->avl.key = alias->name;
  115. avl_insert(&aliases, &alias->avl);
  116. alias->dep.alias = true;
  117. alias->dep.cb = alias_device_cb;
  118. device_check_state(&alias->dev);
  119. return &alias->dev;
  120. }
  121. static void alias_device_free(struct device *dev)
  122. {
  123. struct alias_device *alias;
  124. alias = container_of(dev, struct alias_device, dev);
  125. device_remove_user(&alias->new_dep);
  126. device_remove_user(&alias->dep);
  127. avl_delete(&aliases, &alias->avl);
  128. free(alias);
  129. }
  130. static int alias_check_state(struct device *dev)
  131. {
  132. struct alias_device *alias;
  133. struct interface *iface;
  134. struct device *ndev = NULL;
  135. alias = container_of(dev, struct alias_device, dev);
  136. iface = vlist_find(&interfaces, alias->name, iface, node);
  137. if (iface && iface->state == IFS_UP)
  138. ndev = iface->l3_dev.dev;
  139. alias_set_device(alias, ndev);
  140. return 0;
  141. }
  142. static struct device_type alias_device_type = {
  143. .name = "Network alias",
  144. .create = alias_device_create,
  145. .free = alias_device_free,
  146. .check_state = alias_check_state,
  147. };
  148. void
  149. alias_notify_device(const char *name, struct device *dev)
  150. {
  151. struct alias_device *alias;
  152. device_lock();
  153. alias = avl_find_element(&aliases, name, alias, avl);
  154. if (alias)
  155. alias_set_device(alias, dev);
  156. device_unlock();
  157. }
  158. struct device *
  159. device_alias_get(const char *name)
  160. {
  161. struct alias_device *alias;
  162. alias = avl_find_element(&aliases, name, alias, avl);
  163. if (alias)
  164. return &alias->dev;
  165. return alias_device_create(name, &alias_device_type, NULL);
  166. }
  167. static void __init alias_init(void)
  168. {
  169. avl_init(&aliases, avl_strcmp, false, NULL);
  170. }