disambiguation.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /*
  2. Copyright (c) 2014 by Matthieu Boutier and Juliusz Chroboczek.
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include <assert.h>
  24. #include <sys/time.h>
  25. #include "babeld.h"
  26. #include "util.h"
  27. #include "interface.h"
  28. #include "kernel.h"
  29. #include "route.h"
  30. #include "source.h"
  31. #include "neighbour.h"
  32. #include "rule.h"
  33. #include "disambiguation.h"
  34. struct zone {
  35. const unsigned char *dst_prefix;
  36. unsigned char dst_plen;
  37. const unsigned char *src_prefix;
  38. unsigned char src_plen;
  39. };
  40. /* This function assumes rt1 and rt2 non disjoint. */
  41. static int
  42. rt_cmp(const struct babel_route *rt1, const struct babel_route *rt2)
  43. {
  44. enum prefix_status dst_st, src_st;
  45. const struct source *r1 = rt1->src, *r2 = rt2->src;
  46. dst_st = prefix_cmp(r1->prefix, r1->plen, r2->prefix, r2->plen);
  47. if(dst_st == PST_MORE_SPECIFIC)
  48. return -1;
  49. else if(dst_st == PST_LESS_SPECIFIC)
  50. return 1;
  51. src_st = prefix_cmp(r1->src_prefix, r1->src_plen,
  52. r2->src_prefix, r2->src_plen);
  53. if(src_st == PST_MORE_SPECIFIC)
  54. return -1;
  55. else if(src_st == PST_LESS_SPECIFIC)
  56. return 1;
  57. return 0;
  58. }
  59. static const struct babel_route *
  60. min_route(const struct babel_route *r1, const struct babel_route *r2)
  61. {
  62. int rc;
  63. if(!r1) return r2;
  64. if(!r2) return r1;
  65. rc = rt_cmp(r1, r2);
  66. return rc <= 0 ? r1 : r2;
  67. }
  68. static int
  69. conflicts(const struct babel_route *rt, const struct babel_route *rt1)
  70. {
  71. enum prefix_status dst_st, src_st;
  72. const struct source *r = rt->src, *r1 = rt1->src;
  73. dst_st = prefix_cmp(r->prefix, r->plen, r1->prefix, r1->plen);
  74. if(dst_st == PST_DISJOINT || dst_st == PST_EQUALS)
  75. return 0;
  76. src_st = prefix_cmp(r->src_prefix, r->src_plen,
  77. r1->src_prefix, r1->src_plen);
  78. return ((dst_st == PST_LESS_SPECIFIC && src_st == PST_MORE_SPECIFIC) ||
  79. (dst_st == PST_MORE_SPECIFIC && src_st == PST_LESS_SPECIFIC));
  80. }
  81. static const struct zone*
  82. to_zone(const struct babel_route *rt, struct zone *zone)
  83. {
  84. zone->dst_prefix = rt->src->prefix;
  85. zone->dst_plen = rt->src->plen;
  86. zone->src_prefix = rt->src->src_prefix;
  87. zone->src_plen = rt->src->src_plen;
  88. return zone;
  89. }
  90. /* fill zone with rt cap rt1, and returns a pointer to zone, or NULL if the
  91. intersection is empty. */
  92. static const struct zone*
  93. inter(const struct babel_route *rt, const struct babel_route *rt1,
  94. struct zone *zone)
  95. {
  96. enum prefix_status dst_st, src_st;
  97. const struct source *r = rt->src, *r1 = rt1->src;
  98. dst_st = prefix_cmp(r->prefix, r->plen, r1->prefix, r1->plen);
  99. if(dst_st == PST_DISJOINT)
  100. return NULL;
  101. src_st = prefix_cmp(r->src_prefix, r->src_plen,
  102. r1->src_prefix, r1->src_plen);
  103. if(src_st == PST_DISJOINT)
  104. return NULL;
  105. if(dst_st == PST_MORE_SPECIFIC || dst_st == PST_EQUALS) {
  106. zone->dst_prefix = r->prefix;
  107. zone->dst_plen = r->plen;
  108. } else {
  109. zone->dst_prefix = r1->prefix;
  110. zone->dst_plen = r1->plen;
  111. }
  112. if(src_st == PST_MORE_SPECIFIC || src_st == PST_EQUALS) {
  113. zone->src_prefix = r->src_prefix;
  114. zone->src_plen = r->src_plen;
  115. } else {
  116. zone->src_prefix = r1->src_prefix;
  117. zone->src_plen = r1->src_plen;
  118. }
  119. return zone;
  120. }
  121. static int
  122. zone_equal(const struct zone *z1, const struct zone *z2)
  123. {
  124. return z1 && z2 && z1->dst_plen == z2->dst_plen &&
  125. memcmp(z1->dst_prefix, z2->dst_prefix, 16) == 0 &&
  126. z1->src_plen == z2->src_plen &&
  127. memcmp(z1->src_prefix, z2->src_prefix, 16) == 0;
  128. }
  129. static const struct babel_route *
  130. min_conflict(const struct zone *zone, const struct babel_route *rt)
  131. {
  132. struct babel_route *rt1 = NULL;
  133. const struct babel_route *min = NULL;
  134. struct route_stream *stream = NULL;
  135. struct zone curr_zone;
  136. stream = route_stream(ROUTE_INSTALLED);
  137. if(!stream) {
  138. fprintf(stderr, "Couldn't allocate route stream.\n");
  139. return NULL;
  140. }
  141. while(1) {
  142. rt1 = route_stream_next(stream);
  143. if(rt1 == NULL) break;
  144. if(!(conflicts(rt, rt1) &&
  145. zone_equal(inter(rt, rt1, &curr_zone), zone)))
  146. continue;
  147. min = min_route(rt1, min);
  148. }
  149. route_stream_done(stream);
  150. return min;
  151. }
  152. static const struct babel_route *
  153. conflict_solution(const struct babel_route *rt)
  154. {
  155. const struct babel_route *rt1 = NULL, *rt2 = NULL;
  156. struct route_stream *stream1 = NULL;
  157. struct route_stream *stream2 = NULL;
  158. const struct babel_route *min = NULL; /* == solution */
  159. struct zone zone;
  160. struct zone tmp;
  161. /* Having a conflict requires at least one specific route. */
  162. stream1 = route_stream(ROUTE_SS_INSTALLED);
  163. if(!stream1) {
  164. return NULL;
  165. }
  166. while(1) {
  167. rt1 = route_stream_next(stream1);
  168. if(rt1 == NULL) break;
  169. stream2 = route_stream(ROUTE_INSTALLED);
  170. if(!stream2) {
  171. route_stream_done(stream1);
  172. fprintf(stderr, "Couldn't allocate route stream.\n");
  173. return NULL;
  174. }
  175. while(1) {
  176. rt2 = route_stream_next(stream2);
  177. if(rt2 == NULL) break;
  178. if(!(conflicts(rt1, rt2) &&
  179. zone_equal(inter(rt1, rt2, &tmp), to_zone(rt, &zone)) &&
  180. rt_cmp(rt1, rt2) < 0))
  181. continue;
  182. min = min_route(rt1, min);
  183. }
  184. route_stream_done(stream2);
  185. }
  186. route_stream_done(stream1);
  187. return min;
  188. }
  189. static int
  190. is_installed(struct zone *zone)
  191. {
  192. return zone != NULL &&
  193. find_installed_route(zone->dst_prefix, zone->dst_plen,
  194. zone->src_prefix, zone->src_plen) != NULL;
  195. }
  196. static int
  197. add_route(const struct zone *zone, const struct babel_route *route)
  198. {
  199. int table = find_table(zone->dst_prefix, zone->dst_plen,
  200. zone->src_prefix, zone->src_plen);
  201. return kernel_route(ROUTE_ADD, table, zone->dst_prefix, zone->dst_plen,
  202. zone->src_prefix, zone->src_plen,
  203. route->nexthop,
  204. route->neigh->ifp->ifindex,
  205. metric_to_kernel(route_metric(route)), NULL, 0, 0, 0);
  206. }
  207. static int
  208. del_route(const struct zone *zone, const struct babel_route *route)
  209. {
  210. int table = find_table(zone->dst_prefix, zone->dst_plen,
  211. zone->src_prefix, zone->src_plen);
  212. return kernel_route(ROUTE_FLUSH, table, zone->dst_prefix, zone->dst_plen,
  213. zone->src_prefix, zone->src_plen,
  214. route->nexthop,
  215. route->neigh->ifp->ifindex,
  216. metric_to_kernel(route_metric(route)), NULL, 0, 0, 0);
  217. }
  218. static int
  219. chg_route(const struct zone *zone, const struct babel_route *old,
  220. const struct babel_route *new)
  221. {
  222. int table = find_table(zone->dst_prefix, zone->dst_plen,
  223. zone->src_prefix, zone->src_plen);
  224. return kernel_route(ROUTE_MODIFY, table, zone->dst_prefix, zone->dst_plen,
  225. zone->src_prefix, zone->src_plen,
  226. old->nexthop, old->neigh->ifp->ifindex,
  227. metric_to_kernel(route_metric(old)),
  228. new->nexthop, new->neigh->ifp->ifindex,
  229. metric_to_kernel(route_metric(new)), table);
  230. }
  231. static int
  232. chg_route_metric(const struct zone *zone, const struct babel_route *route,
  233. int old_metric, int new_metric)
  234. {
  235. int table = find_table(zone->dst_prefix, zone->dst_plen,
  236. zone->src_prefix, zone->src_plen);
  237. return kernel_route(ROUTE_MODIFY, table, zone->dst_prefix, zone->dst_plen,
  238. zone->src_prefix, zone->src_plen,
  239. route->nexthop, route->neigh->ifp->ifindex,
  240. old_metric,
  241. route->nexthop, route->neigh->ifp->ifindex,
  242. new_metric, table);
  243. }
  244. int
  245. kinstall_route(const struct babel_route *route)
  246. {
  247. int rc;
  248. struct zone zone;
  249. const struct babel_route *rt1 = NULL;
  250. const struct babel_route *rt2 = NULL;
  251. struct route_stream *stream = NULL;
  252. int v4 = v4mapped(route->nexthop);
  253. debugf("install_route(%s from %s)\n",
  254. format_prefix(route->src->prefix, route->src->plen),
  255. format_prefix(route->src->src_prefix, route->src->src_plen));
  256. // testing
  257. printf("--kinstall_route: route->src->prefix:%s\n\troute->src->cipher:%s\n",
  258. format_prefix(route->src->prefix, route->src->plen),
  259. route->src->cipher);
  260. /* Install source-specific conflicting routes */
  261. if(kernel_disambiguate(v4)) {
  262. to_zone(route, &zone);
  263. rc = add_route(&zone, route);
  264. goto end;
  265. }
  266. stream = route_stream(ROUTE_INSTALLED);
  267. if(!stream) {
  268. fprintf(stderr, "Couldn't allocate route stream.\n");
  269. return -1;
  270. }
  271. /* Install source-specific conflicting routes */
  272. while(1) {
  273. rt1 = route_stream_next(stream);
  274. if(rt1 == NULL) break;
  275. inter(route, rt1, &zone);
  276. if(!(conflicts(route, rt1) &&
  277. !is_installed(&zone) &&
  278. rt_cmp(rt1, min_conflict(&zone, route)) == 0))
  279. continue;
  280. rt2 = min_conflict(&zone, rt1);
  281. if(rt2 == NULL)
  282. add_route(&zone, min_route(route, rt1));
  283. else if(rt_cmp(route, rt2) < 0 && rt_cmp(route, rt1) < 0)
  284. chg_route(&zone, rt2, route);
  285. }
  286. route_stream_done(stream);
  287. /* Non conflicting case */
  288. to_zone(route, &zone);
  289. rt1 = conflict_solution(route);
  290. if(rt1 == NULL)
  291. rc = add_route(&zone, route);
  292. else
  293. rc = chg_route(&zone, rt1, route);
  294. end:
  295. if(rc < 0) {
  296. int save = errno;
  297. perror("kernel_route(ADD)");
  298. if(save != EEXIST)
  299. return -1;
  300. }
  301. return 0;
  302. }
  303. int
  304. kuninstall_route(const struct babel_route *route)
  305. {
  306. int rc;
  307. struct zone zone;
  308. const struct babel_route *rt1 = NULL, *rt2 = NULL;
  309. struct route_stream *stream = NULL;
  310. int v4 = v4mapped(route->nexthop);
  311. debugf("uninstall_route(%s from %s)\n",
  312. format_prefix(route->src->prefix, route->src->plen),
  313. format_prefix(route->src->src_prefix, route->src->src_plen));
  314. to_zone(route, &zone);
  315. if(kernel_disambiguate(v4)) {
  316. rc = del_route(&zone, route);
  317. if(rc < 0)
  318. perror("kernel_route(FLUSH)");
  319. return rc;
  320. }
  321. /* Remove the route, or change if the route was solving a conflict. */
  322. rt1 = conflict_solution(route);
  323. if(rt1 == NULL)
  324. rc = del_route(&zone, route);
  325. else
  326. rc = chg_route(&zone, route, rt1);
  327. if(rc < 0)
  328. perror("kernel_route(FLUSH)");
  329. /* Remove source-specific conflicting routes */
  330. stream = route_stream(ROUTE_INSTALLED);
  331. if(!stream) {
  332. fprintf(stderr, "Couldn't allocate route stream.\n");
  333. return -1;
  334. }
  335. while(1) {
  336. rt1 = route_stream_next(stream);
  337. if(rt1 == NULL) break;
  338. inter(route, rt1, &zone);
  339. if(!(conflicts(route, rt1) &&
  340. !is_installed(&zone) &&
  341. rt_cmp(rt1, min_conflict(&zone, route)) == 0))
  342. continue;
  343. rt2 = min_conflict(&zone, rt1);
  344. if(rt2 == NULL)
  345. del_route(&zone, min_route(route, rt1));
  346. else if(rt_cmp(route, rt2) < 0 && rt_cmp(route, rt1) < 0)
  347. chg_route(&zone, route, rt2);
  348. }
  349. route_stream_done(stream);
  350. return rc;
  351. }
  352. int
  353. kswitch_routes(const struct babel_route *old, const struct babel_route *new)
  354. {
  355. int rc;
  356. struct zone zone;
  357. struct babel_route *rt1 = NULL;
  358. struct route_stream *stream = NULL;
  359. debugf("switch_routes(%s from %s)\n",
  360. format_prefix(old->src->prefix, old->src->plen),
  361. format_prefix(old->src->src_prefix, old->src->src_plen));
  362. to_zone(old, &zone);
  363. rc = chg_route(&zone, old, new);
  364. if(rc < 0) {
  365. perror("kernel_route(MODIFY)");
  366. return -1;
  367. }
  368. /* Remove source-specific conflicting routes */
  369. if(!kernel_disambiguate(v4mapped(old->nexthop))) {
  370. stream = route_stream(ROUTE_INSTALLED);
  371. if(!stream) {
  372. fprintf(stderr, "Couldn't allocate route stream.\n");
  373. return -1;
  374. }
  375. while(1) {
  376. rt1 = route_stream_next(stream);
  377. if(rt1 == NULL) break;
  378. inter(old, rt1, &zone);
  379. if(!(conflicts(old, rt1) &&
  380. !is_installed(&zone) &&
  381. rt_cmp(rt1, min_conflict(&zone, old)) == 0 &&
  382. rt_cmp(old, rt1) < 0 &&
  383. rt_cmp(old, min_conflict(&zone, rt1)) == 0))
  384. continue;
  385. chg_route(&zone, old, new);
  386. }
  387. route_stream_done(stream);
  388. }
  389. return rc;
  390. }
  391. int
  392. kchange_route_metric(const struct babel_route *route,
  393. unsigned refmetric, unsigned cost, unsigned add)
  394. {
  395. int old_metric = metric_to_kernel(route_metric(route));
  396. int new_metric = metric_to_kernel(MIN(refmetric + cost + add, INFINITY));
  397. int rc;
  398. struct babel_route *rt1 = NULL;
  399. struct route_stream *stream = NULL;
  400. struct zone zone;
  401. debugf("change_route_metric(%s from %s, %d -> %d)\n",
  402. format_prefix(route->src->prefix, route->src->plen),
  403. format_prefix(route->src->src_prefix, route->src->src_plen),
  404. old_metric, new_metric);
  405. to_zone(route, &zone);
  406. rc = chg_route_metric(&zone, route, old_metric, new_metric);
  407. if(rc < 0) {
  408. perror("kernel_route(MODIFY metric)");
  409. return -1;
  410. }
  411. if(!kernel_disambiguate(v4mapped(route->nexthop))) {
  412. stream = route_stream(ROUTE_INSTALLED);
  413. if(!stream) {
  414. fprintf(stderr, "Couldn't allocate route stream.\n");
  415. return -1;
  416. }
  417. while(1) {
  418. rt1 = route_stream_next(stream);
  419. if(rt1 == NULL) break;
  420. inter(route, rt1, &zone);
  421. if(!(conflicts(route, rt1) &&
  422. !is_installed(&zone) &&
  423. rt_cmp(rt1, min_conflict(&zone, route)) == 0 &&
  424. rt_cmp(route, rt1) < 0 &&
  425. rt_cmp(route, min_conflict(&zone, rt1)) == 0))
  426. continue;
  427. chg_route_metric(&zone, route, old_metric, new_metric);
  428. }
  429. route_stream_done(stream);
  430. }
  431. return rc;
  432. }