if_mpw.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /* $OpenBSD: if_mpw.c,v 1.2 2015/07/21 04:58:52 rzalamena Exp $ */
  2. /*
  3. * Copyright (c) 2015 Rafael Zalamena <rzalamena@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 "bpfilter.h"
  18. #include "vlan.h"
  19. #include <sys/param.h>
  20. #include <sys/systm.h>
  21. #include <sys/mbuf.h>
  22. #include <sys/socket.h>
  23. #include <sys/ioctl.h>
  24. #include <sys/errno.h>
  25. #include <net/if.h>
  26. #include <net/if_types.h>
  27. #include <net/route.h>
  28. #include <netinet/in.h>
  29. #include <netinet/if_ether.h>
  30. #include <netmpls/mpls.h>
  31. #if NBPFILTER > 0
  32. #include <net/bpf.h>
  33. #endif /* NBPFILTER */
  34. #if NVLAN > 0
  35. #include <net/if_vlan_var.h>
  36. #endif
  37. struct mpw_softc {
  38. struct ifnet sc_if;
  39. struct ifaddr sc_ifa;
  40. struct sockaddr_mpls sc_smpls; /* Local label */
  41. uint32_t sc_flags;
  42. uint32_t sc_type;
  43. struct shim_hdr sc_rshim;
  44. struct sockaddr_storage sc_nexthop;
  45. };
  46. void mpwattach(int);
  47. int mpw_clone_create(struct if_clone *, int);
  48. int mpw_clone_destroy(struct ifnet *);
  49. int mpw_ioctl(struct ifnet *, u_long, caddr_t);
  50. int mpw_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  51. struct rtentry *);
  52. void mpw_start(struct ifnet *);
  53. int mpw_input(struct ifnet *, struct mbuf *);
  54. #if NVLAN > 0
  55. struct mbuf *mpw_vlan_handle(struct mbuf *, struct mpw_softc *);
  56. #endif /* NVLAN */
  57. struct if_clone mpw_cloner =
  58. IF_CLONE_INITIALIZER("mpw", mpw_clone_create, mpw_clone_destroy);
  59. /* ARGSUSED */
  60. void
  61. mpwattach(int n)
  62. {
  63. if_clone_attach(&mpw_cloner);
  64. }
  65. int
  66. mpw_clone_create(struct if_clone *ifc, int unit)
  67. {
  68. struct mpw_softc *sc;
  69. struct ifnet *ifp;
  70. struct ifih *ifih;
  71. sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO);
  72. if (sc == NULL)
  73. return (ENOMEM);
  74. ifih = malloc(sizeof(*ifih), M_DEVBUF, M_NOWAIT | M_ZERO);
  75. if (ifih == NULL) {
  76. free(sc, M_DEVBUF, sizeof(*sc));
  77. return (ENOMEM);
  78. }
  79. ifp = &sc->sc_if;
  80. snprintf(ifp->if_xname, sizeof(ifp->if_xname), "mpw%d", unit);
  81. ifp->if_softc = sc;
  82. ifp->if_mtu = ETHERMTU;
  83. ifp->if_flags = IFF_POINTOPOINT;
  84. ifp->if_ioctl = mpw_ioctl;
  85. ifp->if_output = mpw_output;
  86. ifp->if_start = mpw_start;
  87. ifp->if_type = IFT_MPLSTUNNEL;
  88. ifp->if_hdrlen = ETHER_HDR_LEN;
  89. IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
  90. IFQ_SET_READY(&ifp->if_snd);
  91. if_attach(ifp);
  92. if_alloc_sadl(ifp);
  93. sc->sc_ifa.ifa_ifp = ifp;
  94. sc->sc_ifa.ifa_rtrequest = link_rtrequest;
  95. sc->sc_ifa.ifa_addr = (struct sockaddr *) ifp->if_sadl;
  96. sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls);
  97. sc->sc_smpls.smpls_family = AF_MPLS;
  98. ifih->ifih_input = mpw_input;
  99. SLIST_INSERT_HEAD(&ifp->if_inputs, ifih, ifih_next);
  100. #if NBPFILTER > 0
  101. bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
  102. #endif /* NBFILTER */
  103. return (0);
  104. }
  105. int
  106. mpw_clone_destroy(struct ifnet *ifp)
  107. {
  108. struct mpw_softc *sc = ifp->if_softc;
  109. struct ifih *ifih = SLIST_FIRST(&ifp->if_inputs);
  110. int s;
  111. ifp->if_flags &= ~IFF_RUNNING;
  112. if (sc->sc_smpls.smpls_label) {
  113. s = splsoftnet();
  114. rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_UP,
  115. smplstosa(&sc->sc_smpls));
  116. splx(s);
  117. }
  118. SLIST_REMOVE(&ifp->if_inputs, ifih, ifih, ifih_next);
  119. free(ifih, M_DEVBUF, sizeof(*ifih));
  120. if_detach(ifp);
  121. free(sc, M_DEVBUF, sizeof(*sc));
  122. return (0);
  123. }
  124. int
  125. mpw_input(struct ifnet *ifp, struct mbuf *m)
  126. {
  127. /* Don't have local broadcast. */
  128. m_freem(m);
  129. return (1);
  130. }
  131. int
  132. mpw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  133. {
  134. struct ifreq *ifr = (struct ifreq *) data;
  135. struct mpw_softc *sc = ifp->if_softc;
  136. struct sockaddr_in *sin;
  137. struct sockaddr_in *sin_nexthop;
  138. int error = 0;
  139. int s;
  140. struct ifmpwreq imr;
  141. switch (cmd) {
  142. case SIOCSIFMTU:
  143. if (ifr->ifr_mtu < MPE_MTU_MIN ||
  144. ifr->ifr_mtu > MPE_MTU_MAX)
  145. error = EINVAL;
  146. else
  147. ifp->if_mtu = ifr->ifr_mtu;
  148. break;
  149. case SIOCSIFFLAGS:
  150. if ((ifp->if_flags & IFF_UP))
  151. ifp->if_flags |= IFF_RUNNING;
  152. else
  153. ifp->if_flags &= ~IFF_RUNNING;
  154. break;
  155. case SIOCSETMPWCFG:
  156. error = suser(curproc, 0);
  157. if (error != 0)
  158. break;
  159. error = copyin(ifr->ifr_data, &imr, sizeof(imr));
  160. if (error != 0)
  161. break;
  162. /* Teardown all configuration if got no nexthop */
  163. sin = (struct sockaddr_in *) &imr.imr_nexthop;
  164. if (sin->sin_addr.s_addr == 0) {
  165. s = splsoftnet();
  166. if (rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_UP,
  167. smplstosa(&sc->sc_smpls)) == 0)
  168. sc->sc_smpls.smpls_label = 0;
  169. splx(s);
  170. memset(&sc->sc_rshim, 0, sizeof(sc->sc_rshim));
  171. memset(&sc->sc_nexthop, 0, sizeof(sc->sc_nexthop));
  172. sc->sc_flags = 0;
  173. sc->sc_type = 0;
  174. break;
  175. }
  176. /* Validate input */
  177. if (sin->sin_family != AF_INET ||
  178. imr.imr_lshim.shim_label > MPLS_LABEL_MAX ||
  179. imr.imr_lshim.shim_label <= MPLS_LABEL_RESERVED_MAX ||
  180. imr.imr_rshim.shim_label > MPLS_LABEL_MAX ||
  181. imr.imr_rshim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
  182. error = EINVAL;
  183. break;
  184. }
  185. /* Setup labels and create inbound route */
  186. imr.imr_lshim.shim_label =
  187. htonl(imr.imr_lshim.shim_label << MPLS_LABEL_OFFSET);
  188. imr.imr_rshim.shim_label =
  189. htonl(imr.imr_rshim.shim_label << MPLS_LABEL_OFFSET);
  190. if (sc->sc_smpls.smpls_label != imr.imr_lshim.shim_label) {
  191. s = splsoftnet();
  192. if (sc->sc_smpls.smpls_label)
  193. rt_ifa_del(&sc->sc_ifa, RTF_MPLS | RTF_UP,
  194. smplstosa(&sc->sc_smpls));
  195. sc->sc_smpls.smpls_label = imr.imr_lshim.shim_label;
  196. error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS | RTF_UP,
  197. smplstosa(&sc->sc_smpls));
  198. splx(s);
  199. if (error != 0) {
  200. sc->sc_smpls.smpls_label = 0;
  201. break;
  202. }
  203. }
  204. /* Apply configuration */
  205. sc->sc_flags = imr.imr_flags;
  206. sc->sc_type = imr.imr_type;
  207. sc->sc_rshim.shim_label = imr.imr_rshim.shim_label;
  208. sc->sc_rshim.shim_label |= MPLS_BOS_MASK;
  209. memset(&sc->sc_nexthop, 0, sizeof(sc->sc_nexthop));
  210. sin_nexthop = (struct sockaddr_in *) &sc->sc_nexthop;
  211. sin_nexthop->sin_family = sin->sin_family;
  212. sin_nexthop->sin_len = sizeof(struct sockaddr_in);
  213. sin_nexthop->sin_addr.s_addr = sin->sin_addr.s_addr;
  214. break;
  215. case SIOCGETMPWCFG:
  216. imr.imr_flags = sc->sc_flags;
  217. imr.imr_type = sc->sc_type;
  218. imr.imr_lshim.shim_label =
  219. ((ntohl(sc->sc_smpls.smpls_label & MPLS_LABEL_MASK)) >>
  220. MPLS_LABEL_OFFSET);
  221. imr.imr_rshim.shim_label =
  222. ((ntohl(sc->sc_rshim.shim_label & MPLS_LABEL_MASK)) >>
  223. MPLS_LABEL_OFFSET);
  224. memcpy(&imr.imr_nexthop, &sc->sc_nexthop,
  225. sizeof(imr.imr_nexthop));
  226. error = copyout(&imr, ifr->ifr_data, sizeof(imr));
  227. break;
  228. default:
  229. error = ENOTTY;
  230. break;
  231. }
  232. return (error);
  233. }
  234. int
  235. mpw_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
  236. struct rtentry *rt)
  237. {
  238. struct mpw_softc *sc = ifp->if_softc;
  239. struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  240. struct ether_header *eh, ehc;
  241. struct shim_hdr *shim;
  242. int s;
  243. if (sc->sc_type == IMR_TYPE_NONE) {
  244. m_freem(m);
  245. return (EHOSTUNREACH);
  246. }
  247. if (sc->sc_flags & IMR_FLAG_CONTROLWORD) {
  248. shim = mtod(m, struct shim_hdr *);
  249. m_adj(m, MPLS_HDRLEN);
  250. /*
  251. * The first 4 bits identifies that this packet is a
  252. * control word. If the control word is configured and
  253. * we received an IP datagram we shall drop it.
  254. */
  255. if (shim->shim_label & CW_ZERO_MASK) {
  256. ifp->if_ierrors++;
  257. m_freem(m);
  258. return (EINVAL);
  259. }
  260. /* We don't support fragmentation just yet. */
  261. if (shim->shim_label & CW_FRAG_MASK) {
  262. ifp->if_ierrors++;
  263. m_freem(m);
  264. return (EINVAL);
  265. }
  266. }
  267. if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED) {
  268. m_copydata(m, 0, sizeof(ehc), (caddr_t) &ehc);
  269. m_adj(m, ETHER_HDR_LEN);
  270. /* Ethernet tagged expects at least 2 VLANs */
  271. if (ntohs(ehc.ether_type) != ETHERTYPE_QINQ) {
  272. ifp->if_ierrors++;
  273. m_freem(m);
  274. return (EINVAL);
  275. }
  276. /* Remove dummy VLAN and update ethertype */
  277. if (EVL_VLANOFTAG(*mtod(m, uint16_t *)) == 0) {
  278. m_adj(m, EVL_ENCAPLEN);
  279. ehc.ether_type = htons(ETHERTYPE_VLAN);
  280. }
  281. M_PREPEND(m, sizeof(*eh), M_NOWAIT);
  282. if (m == NULL)
  283. return (ENOMEM);
  284. eh = mtod(m, struct ether_header *);
  285. memcpy(eh, &ehc, sizeof(*eh));
  286. }
  287. ml_enqueue(&ml, m);
  288. s = splnet();
  289. if_input(ifp, &ml);
  290. splx(s);
  291. return (0);
  292. }
  293. #if NVLAN > 0
  294. extern void vlan_start(struct ifnet *ifp);
  295. /*
  296. * This routine handles VLAN tag reinsertion in packets flowing through
  297. * the pseudowire. Also it does the necessary modifications to the VLANs
  298. * to respect the RFC.
  299. */
  300. struct mbuf *
  301. mpw_vlan_handle(struct mbuf *m, struct mpw_softc *sc)
  302. {
  303. int needsdummy = 0;
  304. int fakeifv = 0;
  305. struct ifvlan *ifv = NULL;
  306. struct ether_vlan_header *evh;
  307. struct ifnet *ifp, *ifp0;
  308. int nvlan, moff;
  309. struct ether_header eh;
  310. struct ifvlan fifv;
  311. struct vlan_shim {
  312. uint16_t vs_tpid;
  313. uint16_t vs_tci;
  314. } vs;
  315. ifp0 = ifp = if_get(m->m_pkthdr.ph_ifidx);
  316. KASSERT(ifp != NULL);
  317. if (ifp->if_start == vlan_start)
  318. ifv = ifp->if_softc;
  319. /* If we were relying on VLAN HW support, fake an ifv */
  320. if (ifv == NULL && (m->m_flags & M_VLANTAG) == M_VLANTAG) {
  321. memset(&fifv, 0, sizeof(fifv));
  322. fifv.ifv_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
  323. fifv.ifv_prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
  324. ifv = &fifv;
  325. fakeifv = 1;
  326. }
  327. /*
  328. * Always remove VLAN flag as we are inserting them here. Also we
  329. * might get a tagged packet with no VLAN interface, in this case
  330. * we can't do anything.
  331. */
  332. m->m_flags &= ~M_VLANTAG;
  333. /*
  334. * Do VLAN managing.
  335. *
  336. * Case ethernet (raw):
  337. * No VLAN: just pass it.
  338. * One or more VLANs: insert VLAN tag back.
  339. *
  340. * NOTE: In case of raw access mode, the if_vlan will do the job
  341. * of dropping non tagged packets for us.
  342. */
  343. if (sc->sc_type == IMR_TYPE_ETHERNET && ifv == NULL)
  344. return (m);
  345. /*
  346. * Case ethernet-tagged:
  347. * 0 VLAN: Drop packet
  348. * 1 VLAN: Tag packet with dummy VLAN
  349. * >1 VLAN: Nothing
  350. */
  351. if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED && ifv == NULL) {
  352. m_freem(m);
  353. return (NULL);
  354. }
  355. /* Copy and remove ethernet header */
  356. m_copydata(m, 0, sizeof(eh), (caddr_t) &eh);
  357. if (ntohs(eh.ether_type) == ETHERTYPE_VLAN ||
  358. ntohs(eh.ether_type) == ETHERTYPE_QINQ)
  359. m_adj(m, sizeof(*evh));
  360. else
  361. m_adj(m, sizeof(eh));
  362. /* Count VLAN stack size */
  363. nvlan = 0;
  364. while ((ifp = ifv->ifv_p) != NULL && ifp->if_start == vlan_start) {
  365. ifv = ifp->if_softc;
  366. nvlan++;
  367. }
  368. moff = sizeof(*evh) + (nvlan * EVL_ENCAPLEN);
  369. /* The mode ethernet tagged always need at least 2 VLANs */
  370. if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED && nvlan == 0) {
  371. needsdummy = 1;
  372. moff += EVL_ENCAPLEN;
  373. }
  374. /* Add VLAN to the beginning of the packet */
  375. M_PREPEND(m, moff, M_NOWAIT);
  376. if (m == NULL)
  377. return (NULL);
  378. /* Copy original ethernet type */
  379. moff -= sizeof(eh.ether_type);
  380. m_copyback(m, moff, sizeof(eh.ether_type), &eh.ether_type, M_NOWAIT);
  381. /* Fill inner VLAN values */
  382. ifv = ifp0->if_softc;
  383. while (nvlan-- > 0) {
  384. vs.vs_tci = htons((ifv->ifv_prio << EVL_PRIO_BITS) +
  385. ifv->ifv_tag);
  386. vs.vs_tpid = htons(ifv->ifv_type);
  387. moff -= sizeof(vs);
  388. m_copyback(m, moff, sizeof(vs), &vs, M_NOWAIT);
  389. ifp = ifv->ifv_p;
  390. ifv = ifp->if_softc;
  391. }
  392. /* Copy ethernet header back */
  393. evh = mtod(m, struct ether_vlan_header *);
  394. memcpy(evh->evl_dhost, eh.ether_dhost, sizeof(evh->evl_dhost));
  395. memcpy(evh->evl_shost, eh.ether_shost, sizeof(evh->evl_shost));
  396. if (fakeifv)
  397. ifv = &fifv;
  398. /* Insert the last VLAN and optionally a dummy VLAN */
  399. if (needsdummy) {
  400. evh->evl_encap_proto = ntohs(ETHERTYPE_QINQ);
  401. evh->evl_tag = 0;
  402. vs.vs_tci = ntohs((m->m_pkthdr.pf.prio << EVL_PRIO_BITS) +
  403. ifv->ifv_tag);
  404. vs.vs_tpid = ntohs(ETHERTYPE_VLAN);
  405. m_copyback(m, moff, sizeof(vs), &vs, M_NOWAIT);
  406. } else {
  407. evh->evl_encap_proto = (nvlan > 0) ?
  408. ntohs(ETHERTYPE_QINQ) : ntohs(ETHERTYPE_VLAN);
  409. evh->evl_tag = ntohs((m->m_pkthdr.pf.prio << EVL_PRIO_BITS) +
  410. ifv->ifv_tag);
  411. }
  412. return (m);
  413. }
  414. #endif /* NVLAN */
  415. void
  416. mpw_start(struct ifnet *ifp)
  417. {
  418. struct mpw_softc *sc = ifp->if_softc;
  419. struct mbuf *m;
  420. struct rtentry *rt;
  421. struct shim_hdr *shim;
  422. struct sockaddr_storage ss;
  423. rt = rtalloc((struct sockaddr *) &sc->sc_nexthop,
  424. RT_REPORT | RT_RESOLVE, 0);
  425. if (rt == NULL)
  426. return;
  427. /*
  428. * XXX: lie about being MPLS, so mpls_output() get the TTL from
  429. * the right place.
  430. */
  431. memcpy(&ss, &sc->sc_nexthop, sizeof(sc->sc_nexthop));
  432. ((struct sockaddr *) &ss)->sa_family = AF_MPLS;
  433. for (;;) {
  434. IF_DEQUEUE(&ifp->if_snd, m);
  435. if (m == NULL)
  436. break;
  437. if ((ifp->if_flags & IFF_RUNNING) == 0 ||
  438. sc->sc_rshim.shim_label == 0 ||
  439. sc->sc_type == IMR_TYPE_NONE) {
  440. m_freem(m);
  441. continue;
  442. }
  443. #if NVLAN > 0
  444. m = mpw_vlan_handle(m, sc);
  445. if (m == NULL)
  446. continue;
  447. #else
  448. /* Ethernet tagged doesn't work without VLANs'*/
  449. if (sc->sc_type == IMR_TYPE_ETHERNET_TAGGED) {
  450. m_freem(m);
  451. continue;
  452. }
  453. #endif /* NVLAN */
  454. #if NBPFILTER > 0
  455. if (sc->sc_if.if_bpf)
  456. bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
  457. #endif /* NBPFILTER */
  458. if (sc->sc_flags & IMR_FLAG_CONTROLWORD) {
  459. M_PREPEND(m, sizeof(*shim), M_NOWAIT);
  460. if (m == NULL)
  461. continue;
  462. shim = mtod(m, struct shim_hdr *);
  463. memset(shim, 0, sizeof(*shim));
  464. }
  465. M_PREPEND(m, sizeof(*shim), M_NOWAIT);
  466. if (m == NULL)
  467. continue;
  468. shim = mtod(m, struct shim_hdr *);
  469. shim->shim_label = htonl(mpls_defttl) & MPLS_TTL_MASK;
  470. shim->shim_label |= sc->sc_rshim.shim_label;
  471. /* XXX: MPLS only uses domain 0 */
  472. m->m_pkthdr.ph_rtableid = 0;
  473. mpls_output(rt->rt_ifp, m, (struct sockaddr *) &ss, rt);
  474. }
  475. rtfree(rt);
  476. }