mpls_input.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /* $OpenBSD: mpls_input.c,v 1.47 2015/07/29 00:04:03 rzalamena Exp $ */
  2. /*
  3. * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "mpe.h"
  18. #include <sys/param.h>
  19. #include <sys/mbuf.h>
  20. #include <sys/systm.h>
  21. #include <sys/socket.h>
  22. #include <net/if.h>
  23. #include <net/if_var.h>
  24. #include <net/if_types.h>
  25. #include <net/netisr.h>
  26. #include <net/route.h>
  27. #include <netinet/in.h>
  28. #include <netinet/ip.h>
  29. #include <netinet/ip_var.h>
  30. #include <netinet/ip_icmp.h>
  31. #ifdef INET6
  32. #include <netinet/ip6.h>
  33. #endif /* INET6 */
  34. #include <netmpls/mpls.h>
  35. #ifdef MPLS_DEBUG
  36. #define MPLS_LABEL_GET(l) ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
  37. #define MPLS_TTL_GET(l) (ntohl((l) & MPLS_TTL_MASK))
  38. #endif
  39. int mpls_ip_adjttl(struct mbuf *, u_int8_t);
  40. #ifdef INET6
  41. int mpls_ip6_adjttl(struct mbuf *, u_int8_t);
  42. #endif
  43. struct mbuf *mpls_do_error(struct mbuf *, int, int, int);
  44. void
  45. mpls_init(void)
  46. {
  47. }
  48. void
  49. mpls_input(struct ifnet *ifp, struct mbuf *m)
  50. {
  51. struct sockaddr_mpls *smpls;
  52. struct sockaddr_mpls sa_mpls;
  53. struct shim_hdr *shim;
  54. struct rtentry *rt = NULL;
  55. struct rt_mpls *rt_mpls;
  56. u_int8_t ttl;
  57. int i, hasbos;
  58. if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
  59. m_freem(m);
  60. return;
  61. }
  62. /* drop all broadcast and multicast packets */
  63. if (m->m_flags & (M_BCAST | M_MCAST)) {
  64. m_freem(m);
  65. return;
  66. }
  67. if (m->m_len < sizeof(*shim))
  68. if ((m = m_pullup(m, sizeof(*shim))) == NULL)
  69. return;
  70. shim = mtod(m, struct shim_hdr *);
  71. #ifdef MPLS_DEBUG
  72. printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
  73. ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
  74. MPLS_TTL_GET(shim->shim_label),
  75. MPLS_BOS_ISSET(shim->shim_label));
  76. #endif
  77. /* check and decrement TTL */
  78. ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
  79. if (ttl-- <= 1) {
  80. /* TTL exceeded */
  81. m = mpls_do_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0);
  82. if (m == NULL)
  83. return;
  84. shim = mtod(m, struct shim_hdr *);
  85. ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
  86. }
  87. bzero(&sa_mpls, sizeof(sa_mpls));
  88. smpls = &sa_mpls;
  89. smpls->smpls_family = AF_MPLS;
  90. smpls->smpls_len = sizeof(*smpls);
  91. for (i = 0; i < mpls_inkloop; i++) {
  92. smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
  93. #ifdef MPLS_DEBUG
  94. printf("smpls af %d len %d in_label %d in_ifindex %d\n",
  95. smpls->smpls_family, smpls->smpls_len,
  96. MPLS_LABEL_GET(smpls->smpls_label),
  97. ifp->if_index);
  98. #endif
  99. if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) {
  100. hasbos = MPLS_BOS_ISSET(shim->shim_label);
  101. m = mpls_shim_pop(m);
  102. shim = mtod(m, struct shim_hdr *);
  103. switch (ntohl(smpls->smpls_label)) {
  104. case MPLS_LABEL_IPV4NULL:
  105. /*
  106. * RFC 4182 relaxes the position of the
  107. * explicit NULL labels. The no longer need
  108. * to be at the beginning of the stack.
  109. */
  110. if (hasbos) {
  111. do_v4:
  112. if (mpls_ip_adjttl(m, ttl))
  113. goto done;
  114. niq_enqueue(&ipintrq, m);
  115. goto done;
  116. }
  117. continue;
  118. #ifdef INET6
  119. case MPLS_LABEL_IPV6NULL:
  120. if (hasbos) {
  121. do_v6:
  122. if (mpls_ip6_adjttl(m, ttl))
  123. goto done;
  124. niq_enqueue(&ip6intrq, m);
  125. goto done;
  126. }
  127. continue;
  128. #endif /* INET6 */
  129. case MPLS_LABEL_IMPLNULL:
  130. if (hasbos) {
  131. switch (*mtod(m, u_char *) >> 4) {
  132. case IPVERSION:
  133. goto do_v4;
  134. #ifdef INET6
  135. case IPV6_VERSION >> 4:
  136. goto do_v6;
  137. #endif
  138. default:
  139. m_freem(m);
  140. goto done;
  141. }
  142. }
  143. /* FALLTHROUGH */
  144. default:
  145. /* Other cases are not handled for now */
  146. m_freem(m);
  147. goto done;
  148. }
  149. }
  150. KERNEL_LOCK();
  151. rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
  152. KERNEL_UNLOCK();
  153. if (rt == NULL) {
  154. /* no entry for this label */
  155. #ifdef MPLS_DEBUG
  156. printf("MPLS_DEBUG: label not found\n");
  157. #endif
  158. m_freem(m);
  159. goto done;
  160. }
  161. rt->rt_use++;
  162. rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
  163. if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
  164. #ifdef MPLS_DEBUG
  165. printf("MPLS_DEBUG: no MPLS information "
  166. "attached\n");
  167. #endif
  168. m_freem(m);
  169. goto done;
  170. }
  171. hasbos = MPLS_BOS_ISSET(shim->shim_label);
  172. switch (rt_mpls->mpls_operation) {
  173. case MPLS_OP_LOCAL:
  174. /* Packet is for us */
  175. m = mpls_shim_pop(m);
  176. if (!hasbos)
  177. /* redo lookup with next label */
  178. break;
  179. if (!rt->rt_gateway) {
  180. m_freem(m);
  181. goto done;
  182. }
  183. switch(rt->rt_gateway->sa_family) {
  184. case AF_INET:
  185. if (mpls_ip_adjttl(m, ttl))
  186. break;
  187. niq_enqueue(&ipintrq, m);
  188. break;
  189. #ifdef INET6
  190. case AF_INET6:
  191. if (mpls_ip6_adjttl(m, ttl))
  192. break;
  193. niq_enqueue(&ip6intrq, m);
  194. break;
  195. #endif
  196. default:
  197. m_freem(m);
  198. }
  199. goto done;
  200. case MPLS_OP_POP:
  201. m = mpls_shim_pop(m);
  202. if (!hasbos)
  203. /* redo lookup with next label */
  204. break;
  205. ifp = rt->rt_ifp;
  206. #if NMPE > 0
  207. if (ifp->if_type == IFT_MPLS) {
  208. smpls = satosmpls(rt_key(rt));
  209. mpe_input(m, rt->rt_ifp, smpls, ttl);
  210. goto done;
  211. }
  212. #endif
  213. if (ifp->if_type == IFT_MPLSTUNNEL) {
  214. ifp->if_output(ifp, m, rt_key(rt), rt);
  215. goto done;
  216. }
  217. if (!rt->rt_gateway) {
  218. m_freem(m);
  219. goto done;
  220. }
  221. switch(rt->rt_gateway->sa_family) {
  222. case AF_INET:
  223. if (mpls_ip_adjttl(m, ttl))
  224. goto done;
  225. break;
  226. #ifdef INET6
  227. case AF_INET6:
  228. if (mpls_ip6_adjttl(m, ttl))
  229. goto done;
  230. break;
  231. #endif
  232. default:
  233. m_freem(m);
  234. goto done;
  235. }
  236. /* Output iface is not MPLS-enabled */
  237. if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
  238. m_freem(m);
  239. goto done;
  240. }
  241. (*ifp->if_ll_output)(ifp, m, rt->rt_gateway, rt);
  242. goto done;
  243. case MPLS_OP_PUSH:
  244. m = mpls_shim_push(m, rt_mpls);
  245. break;
  246. case MPLS_OP_SWAP:
  247. m = mpls_shim_swap(m, rt_mpls);
  248. break;
  249. }
  250. if (m == NULL)
  251. goto done;
  252. /* refetch label */
  253. shim = mtod(m, struct shim_hdr *);
  254. ifp = rt->rt_ifp;
  255. if (ifp != NULL && rt_mpls->mpls_operation != MPLS_OP_LOCAL)
  256. break;
  257. KERNEL_LOCK();
  258. rtfree(rt);
  259. KERNEL_UNLOCK();
  260. rt = NULL;
  261. }
  262. if (rt == NULL) {
  263. m_freem(m);
  264. goto done;
  265. }
  266. /* write back TTL */
  267. shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
  268. #ifdef MPLS_DEBUG
  269. printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
  270. ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
  271. MPLS_LABEL_GET(smpls->smpls_label),
  272. MPLS_LABEL_GET(rt_mpls->mpls_label));
  273. #endif
  274. /* Output iface is not MPLS-enabled */
  275. if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
  276. #ifdef MPLS_DEBUG
  277. printf("MPLS_DEBUG: interface not mpls enabled\n");
  278. #endif
  279. goto done;
  280. }
  281. KERNEL_LOCK();
  282. (*ifp->if_ll_output)(ifp, m, smplstosa(smpls), rt);
  283. KERNEL_UNLOCK();
  284. done:
  285. if (rt) {
  286. KERNEL_LOCK();
  287. rtfree(rt);
  288. KERNEL_UNLOCK();
  289. }
  290. }
  291. int
  292. mpls_ip_adjttl(struct mbuf *m, u_int8_t ttl)
  293. {
  294. struct ip *ip;
  295. int hlen;
  296. if (mpls_mapttl_ip) {
  297. if (m->m_len < sizeof(struct ip) &&
  298. (m = m_pullup(m, sizeof(struct ip))) == NULL)
  299. return -1;
  300. ip = mtod(m, struct ip *);
  301. hlen = ip->ip_hl << 2;
  302. if (m->m_len < hlen) {
  303. if ((m = m_pullup(m, hlen)) == NULL)
  304. return -1;
  305. ip = mtod(m, struct ip *);
  306. }
  307. /* make sure we have a valid header */
  308. if (in_cksum(m, hlen) != 0) {
  309. m_free(m);
  310. return -1;
  311. }
  312. /* set IP ttl from MPLS ttl */
  313. ip->ip_ttl = ttl;
  314. /* recalculate checksum */
  315. ip->ip_sum = 0;
  316. ip->ip_sum = in_cksum(m, hlen);
  317. }
  318. return 0;
  319. }
  320. #ifdef INET6
  321. int
  322. mpls_ip6_adjttl(struct mbuf *m, u_int8_t ttl)
  323. {
  324. struct ip6_hdr *ip6hdr;
  325. if (mpls_mapttl_ip6) {
  326. if (m->m_len < sizeof(struct ip6_hdr) &&
  327. (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
  328. return -1;
  329. ip6hdr = mtod(m, struct ip6_hdr *);
  330. /* set IPv6 ttl from MPLS ttl */
  331. ip6hdr->ip6_hlim = ttl;
  332. }
  333. return 0;
  334. }
  335. #endif /* INET6 */
  336. struct mbuf *
  337. mpls_do_error(struct mbuf *m, int type, int code, int destmtu)
  338. {
  339. struct shim_hdr stack[MPLS_INKERNEL_LOOP_MAX];
  340. struct sockaddr_mpls sa_mpls;
  341. struct sockaddr_mpls *smpls;
  342. struct rtentry *rt = NULL;
  343. struct shim_hdr *shim;
  344. struct in_ifaddr *ia;
  345. struct icmp *icp;
  346. struct ip *ip;
  347. int nstk;
  348. for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) {
  349. if (m->m_len < sizeof(*shim) &&
  350. (m = m_pullup(m, sizeof(*ip))) == NULL)
  351. return (NULL);
  352. stack[nstk] = *mtod(m, struct shim_hdr *);
  353. m_adj(m, sizeof(*shim));
  354. if (MPLS_BOS_ISSET(stack[nstk].shim_label))
  355. break;
  356. }
  357. shim = &stack[0];
  358. switch (*mtod(m, u_char *) >> 4) {
  359. case IPVERSION:
  360. if (m->m_len < sizeof(*ip) &&
  361. (m = m_pullup(m, sizeof(*ip))) == NULL)
  362. return (NULL);
  363. m = icmp_do_error(m, type, code, 0, destmtu);
  364. if (m == NULL)
  365. return (NULL);
  366. if (icmp_do_exthdr(m, ICMP_EXT_MPLS, 1, stack,
  367. (nstk + 1) * sizeof(*shim)))
  368. return (NULL);
  369. /* set ip_src to something usable, based on the MPLS label */
  370. bzero(&sa_mpls, sizeof(sa_mpls));
  371. smpls = &sa_mpls;
  372. smpls->smpls_family = AF_MPLS;
  373. smpls->smpls_len = sizeof(*smpls);
  374. smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
  375. KERNEL_LOCK();
  376. rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
  377. KERNEL_UNLOCK();
  378. if (rt == NULL) {
  379. /* no entry for this label */
  380. m_freem(m);
  381. return (NULL);
  382. }
  383. if (rt->rt_ifa->ifa_addr->sa_family == AF_INET)
  384. ia = ifatoia(rt->rt_ifa);
  385. else {
  386. /* XXX this needs fixing, if the MPLS is on an IP
  387. * less interface we need to find some other IP to
  388. * use as source.
  389. */
  390. KERNEL_LOCK();
  391. rtfree(rt);
  392. KERNEL_UNLOCK();
  393. m_freem(m);
  394. return (NULL);
  395. }
  396. rt->rt_use++;
  397. KERNEL_LOCK();
  398. rtfree(rt);
  399. if (icmp_reflect(m, NULL, ia)) {
  400. KERNEL_UNLOCK();
  401. return (NULL);
  402. }
  403. KERNEL_UNLOCK();
  404. ip = mtod(m, struct ip *);
  405. /* stuff to fix up which is normaly done in ip_output */
  406. ip->ip_v = IPVERSION;
  407. ip->ip_id = htons(ip_randomid());
  408. ip->ip_sum = 0;
  409. ip->ip_sum = in_cksum(m, sizeof(*ip));
  410. /* stolen from icmp_send() */
  411. icp = (struct icmp *)(mtod(m, caddr_t) + sizeof(*ip));
  412. icp->icmp_cksum = 0;
  413. icp->icmp_cksum = in4_cksum(m, 0, sizeof(*ip),
  414. ntohs(ip->ip_len) - sizeof(*ip));
  415. break;
  416. #ifdef INET6
  417. case IPV6_VERSION >> 4:
  418. #endif
  419. default:
  420. m_freem(m);
  421. return (NULL);
  422. }
  423. /* add mpls stack back to new packet */
  424. M_PREPEND(m, (nstk + 1) * sizeof(*shim), M_NOWAIT);
  425. if (m == NULL)
  426. return (NULL);
  427. m_copyback(m, 0, (nstk + 1) * sizeof(*shim), stack, M_NOWAIT);
  428. /* change TTL to default */
  429. shim = mtod(m, struct shim_hdr *);
  430. shim->shim_label =
  431. (shim->shim_label & ~MPLS_TTL_MASK) | htonl(mpls_defttl);
  432. return (m);
  433. }