mpls_output.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* $OpenBSD: mpls_output.c,v 1.21 2015/07/15 22:16:42 deraadt Exp $ */
  2. /*
  3. * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.org>
  4. * Copyright (c) 2008 Michele Marchetto <michele@openbsd.org>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  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/route.h>
  25. #include <netmpls/mpls.h>
  26. #include <netinet/in.h>
  27. #include <netinet/ip.h>
  28. #ifdef INET6
  29. #include <netinet/ip6.h>
  30. #endif
  31. #ifdef MPLS_DEBUG
  32. #define MPLS_LABEL_GET(l) ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
  33. #endif
  34. void mpls_do_cksum(struct mbuf *);
  35. u_int8_t mpls_getttl(struct mbuf *, sa_family_t);
  36. int
  37. mpls_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst,
  38. struct rtentry *rt0)
  39. {
  40. struct ifnet *ifp = ifp0;
  41. struct sockaddr_mpls *smpls;
  42. struct sockaddr_mpls sa_mpls;
  43. struct shim_hdr *shim;
  44. struct rtentry *rt = rt0;
  45. struct rt_mpls *rt_mpls;
  46. int i, error;
  47. u_int8_t ttl;
  48. if (rt0 == NULL || (dst->sa_family != AF_INET &&
  49. dst->sa_family != AF_INET6 && dst->sa_family != AF_MPLS)) {
  50. if (!ISSET(ifp->if_xflags, IFXF_MPLS))
  51. return (ifp->if_output(ifp, m, dst, rt));
  52. else
  53. return (ifp->if_ll_output(ifp, m, dst, rt));
  54. }
  55. /* need to calculate checksums now if necessary */
  56. mpls_do_cksum(m);
  57. /* initialize sockaddr_mpls */
  58. bzero(&sa_mpls, sizeof(sa_mpls));
  59. smpls = &sa_mpls;
  60. smpls->smpls_family = AF_MPLS;
  61. smpls->smpls_len = sizeof(*smpls);
  62. ttl = mpls_getttl(m, dst->sa_family);
  63. for (i = 0; i < mpls_inkloop; i++) {
  64. rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
  65. if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
  66. /* no MPLS information for this entry */
  67. if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
  68. #ifdef MPLS_DEBUG
  69. printf("MPLS_DEBUG: interface not mpls enabled\n");
  70. #endif
  71. error = ENETUNREACH;
  72. goto bad;
  73. }
  74. return (ifp->if_ll_output(ifp0, m, dst, rt0));
  75. }
  76. switch (rt_mpls->mpls_operation) {
  77. case MPLS_OP_PUSH:
  78. m = mpls_shim_push(m, rt_mpls);
  79. break;
  80. case MPLS_OP_POP:
  81. m = mpls_shim_pop(m);
  82. break;
  83. case MPLS_OP_SWAP:
  84. m = mpls_shim_swap(m, rt_mpls);
  85. break;
  86. default:
  87. error = EINVAL;
  88. goto bad;
  89. }
  90. if (m == NULL) {
  91. error = ENOBUFS;
  92. goto bad;
  93. }
  94. /* refetch label */
  95. shim = mtod(m, struct shim_hdr *);
  96. /* mark first label with BOS flag */
  97. if (rt0 == rt && dst->sa_family != AF_MPLS)
  98. shim->shim_label |= MPLS_BOS_MASK;
  99. ifp = rt->rt_ifp;
  100. if (ifp != NULL)
  101. break;
  102. smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
  103. rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
  104. if (rt == NULL) {
  105. /* no entry for this label */
  106. #ifdef MPLS_DEBUG
  107. printf("MPLS_DEBUG: label %d not found\n",
  108. MPLS_LABEL_GET(shim->shim_label));
  109. #endif
  110. error = EHOSTUNREACH;
  111. goto bad;
  112. }
  113. rt->rt_use++;
  114. rt->rt_refcnt--;
  115. }
  116. /* write back TTL */
  117. shim->shim_label &= ~MPLS_TTL_MASK;
  118. shim->shim_label |= htonl(ttl);
  119. #ifdef MPLS_DEBUG
  120. printf("MPLS: sending on %s outshim %x outlabel %d\n",
  121. ifp->if_xname, ntohl(shim->shim_label),
  122. MPLS_LABEL_GET(rt_mpls->mpls_label));
  123. #endif
  124. /* Output iface is not MPLS-enabled */
  125. if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
  126. #ifdef MPLS_DEBUG
  127. printf("MPLS_DEBUG: interface not mpls enabled\n");
  128. #endif
  129. error = ENETUNREACH;
  130. goto bad;
  131. }
  132. /* reset broadcast and multicast flags, this is a P2P tunnel */
  133. m->m_flags &= ~(M_BCAST | M_MCAST);
  134. smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
  135. return (ifp->if_ll_output(ifp, m, smplstosa(smpls), rt));
  136. bad:
  137. m_freem(m);
  138. return (error);
  139. }
  140. void
  141. mpls_do_cksum(struct mbuf *m)
  142. {
  143. struct ip *ip;
  144. u_int16_t hlen;
  145. in_proto_cksum_out(m, NULL);
  146. if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) {
  147. ip = mtod(m, struct ip *);
  148. hlen = ip->ip_hl << 2;
  149. ip->ip_sum = in_cksum(m, hlen);
  150. m->m_pkthdr.csum_flags &= ~M_IPV4_CSUM_OUT;
  151. }
  152. }
  153. u_int8_t
  154. mpls_getttl(struct mbuf *m, sa_family_t af)
  155. {
  156. struct shim_hdr *shim;
  157. struct ip *ip;
  158. #ifdef INET6
  159. struct ip6_hdr *ip6hdr;
  160. #endif
  161. u_int8_t ttl = mpls_defttl;
  162. /* If the AF is MPLS then inherit the TTL from the present label. */
  163. if (af == AF_MPLS) {
  164. shim = mtod(m, struct shim_hdr *);
  165. ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
  166. return (ttl);
  167. }
  168. /* Else extract TTL from the encapsualted packet. */
  169. switch (*mtod(m, u_char *) >> 4) {
  170. case IPVERSION:
  171. if (!mpls_mapttl_ip)
  172. break;
  173. if (m->m_len < sizeof(*ip))
  174. break; /* impossible */
  175. ip = mtod(m, struct ip *);
  176. ttl = ip->ip_ttl;
  177. break;
  178. #ifdef INET6
  179. case IPV6_VERSION >> 4:
  180. if (!mpls_mapttl_ip6)
  181. break;
  182. if (m->m_len < sizeof(struct ip6_hdr))
  183. break; /* impossible */
  184. ip6hdr = mtod(m, struct ip6_hdr *);
  185. ttl = ip6hdr->ip6_hlim;
  186. break;
  187. #endif
  188. default:
  189. break;
  190. }
  191. return (ttl);
  192. }