nhrp_interface.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /* NHRP interface
  2. * Copyright (c) 2014-2015 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <net/if_arp.h>
  10. #include "zebra.h"
  11. #include "linklist.h"
  12. #include "memory.h"
  13. #include "thread.h"
  14. #include "nhrpd.h"
  15. #include "os.h"
  16. #include "netlink.h"
  17. static int nhrp_if_new_hook(struct interface *ifp)
  18. {
  19. struct nhrp_interface *nifp;
  20. afi_t afi;
  21. nifp = XCALLOC(MTYPE_NHRP_IF, sizeof(struct nhrp_interface));
  22. if (!nifp) return 0;
  23. ifp->info = nifp;
  24. nifp->ifp = ifp;
  25. notifier_init(&nifp->notifier_list);
  26. for (afi = 0; afi < AFI_MAX; afi++) {
  27. struct nhrp_afi_data *ad = &nifp->afi[afi];
  28. ad->holdtime = NHRPD_DEFAULT_HOLDTIME;
  29. list_init(&ad->nhslist_head);
  30. }
  31. return 0;
  32. }
  33. static int nhrp_if_delete_hook(struct interface *ifp)
  34. {
  35. XFREE(MTYPE_NHRP_IF, ifp->info);
  36. return 0;
  37. }
  38. void nhrp_interface_init(void)
  39. {
  40. if_add_hook(IF_NEW_HOOK, nhrp_if_new_hook);
  41. if_add_hook(IF_DELETE_HOOK, nhrp_if_delete_hook);
  42. }
  43. void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
  44. {
  45. struct nhrp_interface *nifp = ifp->info;
  46. struct nhrp_afi_data *if_ad = &nifp->afi[afi];
  47. unsigned short new_mtu;
  48. if (if_ad->configured_mtu < 0)
  49. new_mtu = nifp->nbmaifp ? nifp->nbmaifp->mtu : 0;
  50. else
  51. new_mtu = if_ad->configured_mtu;
  52. if (new_mtu >= 1500)
  53. new_mtu = 0;
  54. if (new_mtu != if_ad->mtu) {
  55. debugf(NHRP_DEBUG_IF, "%s: MTU changed to %d", ifp->name, new_mtu);
  56. if_ad->mtu = new_mtu;
  57. notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_MTU_CHANGED);
  58. }
  59. }
  60. static void nhrp_interface_update_source(struct interface *ifp)
  61. {
  62. struct nhrp_interface *nifp = ifp->info;
  63. if (!nifp->source || !nifp->nbmaifp ||
  64. nifp->linkidx == nifp->nbmaifp->ifindex)
  65. return;
  66. nifp->linkidx = nifp->nbmaifp->ifindex;
  67. debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name, nifp->linkidx);
  68. netlink_gre_set_link(ifp->ifindex, nifp->linkidx);
  69. }
  70. static void nhrp_interface_interface_notifier(struct notifier_block *n, unsigned long cmd)
  71. {
  72. struct nhrp_interface *nifp = container_of(n, struct nhrp_interface, nbmanifp_notifier);
  73. struct interface *nbmaifp = nifp->nbmaifp;
  74. struct nhrp_interface *nbmanifp = nbmaifp->info;
  75. char buf[SU_ADDRSTRLEN];
  76. switch (cmd) {
  77. case NOTIFY_INTERFACE_CHANGED:
  78. nhrp_interface_update_mtu(nifp->ifp, AFI_IP);
  79. nhrp_interface_update_source(nifp->ifp);
  80. break;
  81. case NOTIFY_INTERFACE_ADDRESS_CHANGED:
  82. nifp->nbma = nbmanifp->afi[AFI_IP].addr;
  83. nhrp_interface_update(nifp->ifp);
  84. notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED);
  85. debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %s",
  86. nifp->ifp->name,
  87. sockunion2str(&nifp->nbma, buf, sizeof buf));
  88. break;
  89. }
  90. }
  91. static void nhrp_interface_update_nbma(struct interface *ifp)
  92. {
  93. struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL;
  94. struct interface *nbmaifp = NULL;
  95. union sockunion nbma;
  96. sockunion_family(&nbma) = AF_UNSPEC;
  97. if (nifp->source)
  98. nbmaifp = if_lookup_by_name(nifp->source);
  99. switch (ifp->ll_type) {
  100. case ZEBRA_LLT_IPGRE: {
  101. struct in_addr saddr = {0};
  102. netlink_gre_get_info(ifp->ifindex, &nifp->grekey, &nifp->linkidx, &saddr);
  103. debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name, nifp->grekey, nifp->linkidx, saddr.s_addr);
  104. if (saddr.s_addr)
  105. sockunion_set(&nbma, AF_INET, (u_char *) &saddr.s_addr, sizeof(saddr.s_addr));
  106. else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
  107. nbmaifp = if_lookup_by_index(nifp->linkidx);
  108. }
  109. break;
  110. default:
  111. break;
  112. }
  113. if (nbmaifp)
  114. nbmanifp = nbmaifp->info;
  115. if (nbmaifp != nifp->nbmaifp) {
  116. if (nifp->nbmaifp)
  117. notifier_del(&nifp->nbmanifp_notifier);
  118. nifp->nbmaifp = nbmaifp;
  119. if (nbmaifp) {
  120. notifier_add(&nifp->nbmanifp_notifier, &nbmanifp->notifier_list, nhrp_interface_interface_notifier);
  121. debugf(NHRP_DEBUG_IF, "%s: bound to %s", ifp->name, nbmaifp->name);
  122. }
  123. }
  124. if (nbmaifp) {
  125. if (sockunion_family(&nbma) == AF_UNSPEC)
  126. nbma = nbmanifp->afi[AFI_IP].addr;
  127. nhrp_interface_update_mtu(ifp, AFI_IP);
  128. nhrp_interface_update_source(ifp);
  129. }
  130. if (!sockunion_same(&nbma, &nifp->nbma)) {
  131. nifp->nbma = nbma;
  132. nhrp_interface_update(nifp->ifp);
  133. debugf(NHRP_DEBUG_IF, "%s: NBMA address changed", ifp->name);
  134. notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED);
  135. }
  136. nhrp_interface_update(ifp);
  137. }
  138. static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, int force)
  139. {
  140. const int family = afi2family(afi);
  141. struct nhrp_interface *nifp = ifp->info;
  142. struct nhrp_afi_data *if_ad = &nifp->afi[afi];
  143. struct nhrp_cache *nc;
  144. struct connected *c, *best;
  145. struct listnode *cnode;
  146. union sockunion addr;
  147. char buf[PREFIX_STRLEN];
  148. /* Select new best match preferring primary address */
  149. best = NULL;
  150. for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
  151. if (PREFIX_FAMILY(c->address) != family)
  152. continue;
  153. if (best == NULL) {
  154. best = c;
  155. continue;
  156. }
  157. if ((best->flags & ZEBRA_IFA_SECONDARY) && !(c->flags & ZEBRA_IFA_SECONDARY)) {
  158. best = c;
  159. continue;
  160. }
  161. if (!(best->flags & ZEBRA_IFA_SECONDARY) && (c->flags & ZEBRA_IFA_SECONDARY))
  162. continue;
  163. if (best->address->prefixlen > c->address->prefixlen) {
  164. best = c;
  165. continue;
  166. }
  167. if (best->address->prefixlen < c->address->prefixlen)
  168. continue;
  169. }
  170. /* On NHRP interfaces a host prefix is required */
  171. if (best && if_ad->configured && best->address->prefixlen != 8 * prefix_blen(best->address)) {
  172. zlog_notice("%s: %s is not a host prefix", ifp->name,
  173. prefix2str(best->address, buf, sizeof buf));
  174. best = NULL;
  175. }
  176. /* Update address if it changed */
  177. if (best)
  178. prefix2sockunion(best->address, &addr);
  179. else
  180. memset(&addr, 0, sizeof(addr));
  181. if (!force && sockunion_same(&if_ad->addr, &addr))
  182. return;
  183. if (sockunion_family(&if_ad->addr) != AF_UNSPEC) {
  184. nc = nhrp_cache_get(ifp, &if_ad->addr, 0);
  185. if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, NULL, 0, NULL);
  186. }
  187. debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s",
  188. ifp->name, afi == AFI_IP ? 4 : 6,
  189. best ? prefix2str(best->address, buf, sizeof buf) : "(none)");
  190. if_ad->addr = addr;
  191. if (if_ad->configured && sockunion_family(&if_ad->addr) != AF_UNSPEC) {
  192. nc = nhrp_cache_get(ifp, &addr, 1);
  193. if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL);
  194. }
  195. notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
  196. }
  197. void nhrp_interface_update(struct interface *ifp)
  198. {
  199. struct nhrp_interface *nifp = ifp->info;
  200. struct nhrp_afi_data *if_ad;
  201. afi_t afi;
  202. int enabled = 0;
  203. notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_CHANGED);
  204. for (afi = 0; afi < AFI_MAX; afi++) {
  205. if_ad = &nifp->afi[afi];
  206. if (sockunion_family(&nifp->nbma) == AF_UNSPEC ||
  207. ifp->ifindex == IFINDEX_INTERNAL || !if_is_up(ifp) ||
  208. !if_ad->network_id) {
  209. if (if_ad->configured) {
  210. if_ad->configured = 0;
  211. nhrp_interface_update_address(ifp, afi, 1);
  212. }
  213. continue;
  214. }
  215. if (!if_ad->configured) {
  216. os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi));
  217. if_ad->configured = 1;
  218. nhrp_interface_update_address(ifp, afi, 1);
  219. }
  220. enabled = 1;
  221. }
  222. if (enabled != nifp->enabled) {
  223. nifp->enabled = enabled;
  224. notifier_call(&nifp->notifier_list, enabled ? NOTIFY_INTERFACE_UP : NOTIFY_INTERFACE_DOWN);
  225. }
  226. }
  227. int nhrp_interface_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id)
  228. {
  229. struct interface *ifp;
  230. /* read and add the interface in the iflist. */
  231. ifp = zebra_interface_add_read(client->ibuf, vrf_id);
  232. if (ifp == NULL)
  233. return 0;
  234. debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s",
  235. ifp->name, ifp->ifindex,
  236. ifp->ll_type, if_link_type_str(ifp->ll_type));
  237. nhrp_interface_update_nbma(ifp);
  238. return 0;
  239. }
  240. int nhrp_interface_delete(int cmd, struct zclient *client,
  241. zebra_size_t length, vrf_id_t vrf_id)
  242. {
  243. struct interface *ifp;
  244. struct stream *s;
  245. s = client->ibuf;
  246. ifp = zebra_interface_state_read(s, vrf_id);
  247. if (ifp == NULL)
  248. return 0;
  249. debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
  250. ifp->ifindex = IFINDEX_INTERNAL;
  251. nhrp_interface_update(ifp);
  252. /* if_delete(ifp); */
  253. return 0;
  254. }
  255. int nhrp_interface_up(int cmd, struct zclient *client,
  256. zebra_size_t length, vrf_id_t vrf_id)
  257. {
  258. struct interface *ifp;
  259. ifp = zebra_interface_state_read(client->ibuf, vrf_id);
  260. if (ifp == NULL)
  261. return 0;
  262. debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
  263. nhrp_interface_update_nbma(ifp);
  264. return 0;
  265. }
  266. int nhrp_interface_down(int cmd, struct zclient *client,
  267. zebra_size_t length, vrf_id_t vrf_id)
  268. {
  269. struct interface *ifp;
  270. ifp = zebra_interface_state_read(client->ibuf, vrf_id);
  271. if (ifp == NULL)
  272. return 0;
  273. debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name);
  274. nhrp_interface_update(ifp);
  275. return 0;
  276. }
  277. int nhrp_interface_address_add(int cmd, struct zclient *client,
  278. zebra_size_t length, vrf_id_t vrf_id)
  279. {
  280. struct connected *ifc;
  281. char buf[PREFIX_STRLEN];
  282. ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id);
  283. if (ifc == NULL)
  284. return 0;
  285. debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s",
  286. ifc->ifp->name,
  287. prefix2str(ifc->address, buf, sizeof buf));
  288. nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
  289. return 0;
  290. }
  291. int nhrp_interface_address_delete(int cmd, struct zclient *client,
  292. zebra_size_t length, vrf_id_t vrf_id)
  293. {
  294. struct connected *ifc;
  295. char buf[PREFIX_STRLEN];
  296. ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id);
  297. if (ifc == NULL)
  298. return 0;
  299. debugf(NHRP_DEBUG_IF, "if-addr-del: %s: %s",
  300. ifc->ifp->name,
  301. prefix2str(ifc->address, buf, sizeof buf));
  302. nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
  303. connected_free(ifc);
  304. return 0;
  305. }
  306. void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn)
  307. {
  308. struct nhrp_interface *nifp = ifp->info;
  309. notifier_add(n, &nifp->notifier_list, fn);
  310. }
  311. void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n)
  312. {
  313. notifier_del(n);
  314. }
  315. void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile)
  316. {
  317. struct nhrp_interface *nifp = ifp->info;
  318. if (nifp->ipsec_profile) free(nifp->ipsec_profile);
  319. nifp->ipsec_profile = profile ? strdup(profile) : NULL;
  320. if (nifp->ipsec_fallback_profile) free(nifp->ipsec_fallback_profile);
  321. nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL;
  322. notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
  323. }
  324. void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
  325. {
  326. struct nhrp_interface *nifp = ifp->info;
  327. if (nifp->source) free(nifp->source);
  328. nifp->source = ifname ? strdup(ifname) : NULL;
  329. nhrp_interface_update_nbma(ifp);
  330. }