Line data Source code
1 : /* $OpenBSD: if_switch.c,v 1.23 2018/02/19 08:59:52 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
5 : * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
6 : *
7 : * Permission to use, copy, modify, and distribute this software for any
8 : * purpose with or without fee is hereby granted, provided that the above
9 : * copyright notice and this permission notice appear in all copies.
10 : *
11 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 : */
19 :
20 : #include "bpfilter.h"
21 : #include "pf.h"
22 : #include "vlan.h"
23 :
24 : #include <sys/param.h>
25 : #include <sys/systm.h>
26 : #include <sys/mbuf.h>
27 : #include <sys/socket.h>
28 : #include <sys/ioctl.h>
29 : #include <sys/queue.h>
30 : #include <sys/selinfo.h>
31 : #include <sys/pool.h>
32 : #include <sys/syslog.h>
33 :
34 : #include <net/if_types.h>
35 : #include <net/netisr.h>
36 : #include <net/if.h>
37 :
38 : #include <netinet/in.h>
39 : #include <netinet/if_ether.h>
40 : #include <net/ethertypes.h>
41 : #include <netinet/ip.h>
42 : #include <netinet/ip6.h>
43 : #include <netinet/icmp6.h>
44 : #include <netinet6/nd6.h>
45 : #include <netinet/udp.h>
46 : #include <netinet/tcp.h>
47 : #include <netinet/ip_icmp.h>
48 :
49 : #if NPF > 0
50 : #include <net/pfvar.h>
51 : #endif
52 :
53 : #if NBPFILTER > 0
54 : #include <net/bpf.h>
55 : #endif
56 :
57 : #include <net/ofp.h>
58 : #include <net/if_bridge.h>
59 : #include <net/if_switch.h>
60 :
61 : int switch_clone_create(struct if_clone *, int);
62 : int switch_clone_destroy(struct ifnet *);
63 : void switch_process(struct ifnet *, struct mbuf *);
64 : int switch_port_set_local(struct switch_softc *, struct switch_port *);
65 : int switch_port_unset_local(struct switch_softc *, struct switch_port *);
66 : int switch_ioctl(struct ifnet *, unsigned long, caddr_t);
67 : int switch_port_add(struct switch_softc *, struct ifbreq *);
68 : void switch_port_detach(void *);
69 : int switch_port_del(struct switch_softc *, struct ifbreq *);
70 : int switch_port_list(struct switch_softc *, struct ifbifconf *);
71 : int switch_input(struct ifnet *, struct mbuf *, void *);
72 : struct mbuf
73 : *switch_port_ingress(struct switch_softc *, struct ifnet *,
74 : struct mbuf *);
75 : int switch_ifenqueue(struct switch_softc *, struct ifnet *,
76 : struct mbuf *, int);
77 : void switch_port_ifb_start(struct ifnet *);
78 :
79 : struct mbuf
80 : *switch_flow_classifier_udp(struct mbuf *, int *,
81 : struct switch_flow_classify *);
82 : struct mbuf
83 : *switch_flow_classifier_tcp(struct mbuf *, int *,
84 : struct switch_flow_classify *);
85 : struct mbuf
86 : *switch_flow_classifier_icmpv4(struct mbuf *, int *,
87 : struct switch_flow_classify *);
88 : struct mbuf
89 : *switch_flow_classifier_nd6(struct mbuf *, int *,
90 : struct switch_flow_classify *);
91 : struct mbuf
92 : *switch_flow_classifier_icmpv6(struct mbuf *, int *,
93 : struct switch_flow_classify *);
94 : struct mbuf
95 : *switch_flow_classifier_ipv4(struct mbuf *, int *,
96 : struct switch_flow_classify *);
97 : struct mbuf
98 : *switch_flow_classifier_ipv6(struct mbuf *, int *,
99 : struct switch_flow_classify *);
100 : struct mbuf
101 : *switch_flow_classifier_arp(struct mbuf *, int *,
102 : struct switch_flow_classify *);
103 : struct mbuf
104 : *switch_flow_classifier_ether(struct mbuf *, int *,
105 : struct switch_flow_classify *);
106 : struct mbuf
107 : *switch_flow_classifier_tunnel(struct mbuf *, int *,
108 : struct switch_flow_classify *);
109 : void switch_flow_classifier_dump(struct switch_softc *,
110 : struct switch_flow_classify *);
111 : void switchattach(int);
112 :
113 : struct if_clone switch_cloner =
114 : IF_CLONE_INITIALIZER("switch", switch_clone_create, switch_clone_destroy);
115 :
116 : LIST_HEAD(, switch_softc) switch_list;
117 : struct niqueue switchintrq = NIQUEUE_INITIALIZER(1024, NETISR_SWITCH);
118 : struct rwlock switch_ifs_lk = RWLOCK_INITIALIZER("switchifs");
119 :
120 : struct pool swfcl_pool;
121 :
122 : void
123 0 : switchattach(int n)
124 : {
125 0 : pool_init(&swfcl_pool, sizeof(union switch_field), 0, 0, 0,
126 : "swfcl", NULL);
127 0 : swofp_attach();
128 0 : LIST_INIT(&switch_list);
129 0 : if_clone_attach(&switch_cloner);
130 0 : }
131 :
132 : struct switch_softc *
133 0 : switch_lookup(int unit)
134 : {
135 : struct switch_softc *sc;
136 :
137 : /* must hold switch_ifs_lk */
138 0 : LIST_FOREACH(sc, &switch_list, sc_switch_next) {
139 0 : if (sc->sc_unit == unit)
140 0 : return (sc);
141 : }
142 :
143 0 : return (NULL);
144 0 : }
145 :
146 : int
147 0 : switch_clone_create(struct if_clone *ifc, int unit)
148 : {
149 : struct switch_softc *sc;
150 : struct ifnet *ifp;
151 :
152 0 : sc = malloc(sizeof(struct switch_softc), M_DEVBUF, M_WAITOK|M_ZERO);
153 0 : ifp = &sc->sc_if;
154 0 : snprintf(ifp->if_xname, sizeof ifp->if_xname, "switch%d", unit);
155 0 : ifp->if_softc = sc;
156 0 : ifp->if_mtu = ETHERMTU;
157 0 : ifp->if_ioctl = switch_ioctl;
158 0 : ifp->if_output = NULL;
159 0 : ifp->if_start = NULL;
160 0 : ifp->if_type = IFT_BRIDGE;
161 0 : ifp->if_hdrlen = ETHER_HDR_LEN;
162 0 : TAILQ_INIT(&sc->sc_swpo_list);
163 :
164 0 : sc->sc_unit = unit;
165 0 : sc->sc_stp = bstp_create(&sc->sc_if);
166 0 : if (!sc->sc_stp) {
167 0 : free(sc, M_DEVBUF, sizeof(*sc));
168 0 : return (ENOMEM);
169 : }
170 :
171 0 : if_attach(ifp);
172 0 : if_alloc_sadl(ifp);
173 :
174 : #if NBPFILTER > 0
175 0 : bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
176 : #endif
177 :
178 0 : swofp_create(sc);
179 :
180 0 : LIST_INSERT_HEAD(&switch_list, sc, sc_switch_next);
181 :
182 0 : return (0);
183 0 : }
184 :
185 : int
186 0 : switch_clone_destroy(struct ifnet *ifp)
187 : {
188 0 : struct switch_softc *sc = ifp->if_softc;
189 : struct switch_port *swpo, *tp;
190 : struct ifnet *ifs;
191 :
192 0 : TAILQ_FOREACH_SAFE(swpo, &sc->sc_swpo_list, swpo_list_next, tp) {
193 0 : if ((ifs = if_get(swpo->swpo_ifindex)) != NULL) {
194 0 : switch_port_detach(ifs);
195 0 : if_put(ifs);
196 0 : } else
197 0 : log(LOG_ERR, "failed to cleanup on ifindex(%d)\n",
198 0 : swpo->swpo_ifindex);
199 : }
200 0 : LIST_REMOVE(sc, sc_switch_next);
201 0 : bstp_destroy(sc->sc_stp);
202 0 : swofp_destroy(sc);
203 0 : switch_dev_destroy(sc);
204 0 : if_deactivate(ifp);
205 0 : if_detach(ifp);
206 0 : free(sc, M_DEVBUF, sizeof(*sc));
207 :
208 0 : return (0);
209 : }
210 :
211 :
212 : void
213 0 : switchintr(void)
214 : {
215 0 : struct mbuf_list ml;
216 : struct mbuf *m;
217 : struct ifnet *ifp;
218 :
219 0 : niq_delist(&switchintrq, &ml);
220 0 : if (ml_empty(&ml))
221 0 : return;
222 :
223 0 : while ((m = ml_dequeue(&ml)) != NULL) {
224 0 : ifp = if_get(m->m_pkthdr.ph_ifidx);
225 0 : if (ifp == NULL) {
226 0 : m_freem(m);
227 0 : continue;
228 : }
229 0 : switch_process(ifp, m);
230 0 : if_put(ifp);
231 : }
232 :
233 0 : }
234 :
235 : void
236 0 : switch_process(struct ifnet *ifp, struct mbuf *m)
237 : {
238 : struct switch_softc *sc = NULL;
239 : struct switch_port *swpo;
240 0 : struct switch_flow_classify swfcl = { 0 };
241 :
242 0 : swpo = (struct switch_port *)ifp->if_switchport;
243 0 : if (swpo == NULL)
244 : goto discard;
245 0 : sc = swpo->swpo_switch;
246 0 : if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
247 : goto discard;
248 :
249 : #if NBPFILTER > 0
250 0 : if (sc->sc_if.if_bpf)
251 0 : bpf_mtap_ether(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
252 : #endif
253 :
254 0 : if (m->m_pkthdr.len < sizeof(struct ether_header))
255 : goto discard;
256 :
257 0 : if ((m = switch_port_ingress(sc, ifp, m)) == NULL)
258 0 : return; /* m was freed in switch_process_ingress */
259 :
260 0 : if ((m = switch_flow_classifier(m, swpo->swpo_port_no,
261 0 : &swfcl)) == NULL) {
262 0 : switch_swfcl_free(&swfcl);
263 0 : return; /* m was freed in switch_flow_classifier */
264 : }
265 :
266 0 : if (sc->sc_if.if_flags & IFF_DEBUG)
267 0 : switch_flow_classifier_dump(sc, &swfcl);
268 :
269 0 : if (!sc->switch_process_forward)
270 : goto discard;
271 :
272 0 : (sc->switch_process_forward)(sc, &swfcl, m);
273 :
274 0 : switch_swfcl_free(&swfcl);
275 0 : return;
276 :
277 : discard:
278 0 : m_freem(m);
279 0 : switch_swfcl_free(&swfcl);
280 0 : if (sc)
281 0 : sc->sc_if.if_oerrors++;
282 0 : }
283 :
284 : int
285 0 : switch_port_set_local(struct switch_softc *sc, struct switch_port *swpo)
286 : {
287 : struct switch_port *tswpo;
288 0 : struct ifreq ifreq;
289 : struct ifnet *ifs;
290 : int error = 0, re_up = 0;
291 :
292 : /*
293 : * Only one local interface can exist per switch device.
294 : */
295 0 : TAILQ_FOREACH(tswpo, &sc->sc_swpo_list, swpo_list_next) {
296 0 : if (tswpo->swpo_flags & IFBIF_LOCAL)
297 0 : return (EEXIST);
298 : }
299 :
300 0 : ifs = if_get(swpo->swpo_ifindex);
301 0 : if (ifs == NULL)
302 0 : return (ENOENT);
303 :
304 0 : if (ifs->if_flags & IFF_UP) {
305 : re_up = 1;
306 0 : memset(&ifreq, 0, sizeof(ifreq));
307 0 : strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
308 0 : ifs->if_flags &= ~IFF_UP;
309 0 : ifreq.ifr_flags = ifs->if_flags;
310 0 : error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
311 0 : if (error)
312 : goto error;
313 : }
314 :
315 0 : swpo->swpo_flags |= IFBIF_LOCAL;
316 0 : swpo->swpo_port_no = OFP_PORT_LOCAL;
317 0 : swpo->swop_bk_start = ifs->if_start;
318 0 : ifs->if_start = switch_port_ifb_start;
319 :
320 0 : if (re_up) {
321 0 : memset(&ifreq, 0, sizeof(ifreq));
322 0 : strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
323 0 : ifs->if_flags &= IFF_UP;
324 0 : ifreq.ifr_flags = ifs->if_flags;
325 0 : error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
326 0 : if (error)
327 : goto error;
328 : }
329 :
330 : error:
331 0 : if_put(ifs);
332 0 : return (error);
333 0 : }
334 :
335 : int
336 0 : switch_port_unset_local(struct switch_softc *sc, struct switch_port *swpo)
337 : {
338 0 : struct ifreq ifreq;
339 : struct ifnet *ifs;
340 : int error = 0, re_up = 0;
341 :
342 0 : ifs = if_get(swpo->swpo_ifindex);
343 0 : if (ifs == NULL)
344 0 : return (ENOENT);
345 :
346 0 : if (ifs->if_flags & IFF_UP) {
347 : re_up = 1;
348 0 : memset(&ifreq, 0, sizeof(ifreq));
349 0 : strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
350 0 : ifs->if_flags &= ~IFF_UP;
351 0 : ifreq.ifr_flags = ifs->if_flags;
352 0 : error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
353 0 : if (error)
354 : goto error;
355 : }
356 :
357 0 : swpo->swpo_flags &= ~IFBIF_LOCAL;
358 0 : swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index);
359 0 : ifs->if_start = swpo->swop_bk_start;
360 0 : swpo->swop_bk_start = NULL;
361 :
362 0 : if (re_up) {
363 0 : memset(&ifreq, 0, sizeof(ifreq));
364 0 : strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
365 0 : ifs->if_flags &= IFF_UP;
366 0 : ifreq.ifr_flags = ifs->if_flags;
367 0 : error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
368 0 : if (error)
369 : goto error;
370 : }
371 :
372 : error:
373 0 : if_put(ifs);
374 0 : return (error);
375 0 : }
376 :
377 : int
378 0 : switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
379 : {
380 0 : struct ifbaconf *baconf = (struct ifbaconf *)data;
381 0 : struct ifbropreq *brop = (struct ifbropreq *)data;
382 0 : struct ifbrlconf *bc = (struct ifbrlconf *)data;
383 0 : struct ifbreq *breq = (struct ifbreq *)data;
384 0 : struct switch_softc *sc = ifp->if_softc;
385 0 : struct bstp_state *bs = sc->sc_stp;
386 : struct bstp_port *bp;
387 : struct ifnet *ifs;
388 : struct switch_port *swpo;
389 : int error = 0;
390 :
391 0 : switch (cmd) {
392 : case SIOCBRDGADD:
393 0 : if ((error = suser(curproc)) != 0)
394 : break;
395 0 : error = switch_port_add(sc, (struct ifbreq *)data);
396 0 : break;
397 : case SIOCBRDGDEL:
398 0 : if ((error = suser(curproc)) != 0)
399 : break;
400 0 : error = switch_port_del(sc, (struct ifbreq *)data);
401 0 : break;
402 : case SIOCBRDGIFS:
403 0 : error = switch_port_list(sc, (struct ifbifconf *)data);
404 0 : break;
405 : case SIOCBRDGADDL:
406 0 : if ((error = suser(curproc)) != 0)
407 : break;
408 0 : error = switch_port_add(sc, (struct ifbreq *)data);
409 0 : if (error && error != EEXIST)
410 : break;
411 0 : ifs = ifunit(breq->ifbr_ifsname);
412 0 : if (ifs == NULL) {
413 : error = ENOENT;
414 0 : break;
415 : }
416 0 : swpo = (struct switch_port *)ifs->if_switchport;
417 0 : if (swpo == NULL || swpo->swpo_switch != sc) {
418 : error = ESRCH;
419 0 : break;
420 : }
421 0 : error = switch_port_set_local(sc, swpo);
422 0 : break;
423 : case SIOCBRDGGIFFLGS:
424 0 : ifs = ifunit(breq->ifbr_ifsname);
425 0 : if (ifs == NULL) {
426 : error = ENOENT;
427 0 : break;
428 : }
429 0 : swpo = (struct switch_port *)ifs->if_switchport;
430 0 : if (swpo == NULL || swpo->swpo_switch != sc) {
431 : error = ESRCH;
432 0 : break;
433 : }
434 0 : breq->ifbr_ifsflags = swpo->swpo_flags;
435 0 : breq->ifbr_portno = swpo->swpo_port_no;
436 0 : break;
437 : case SIOCSIFFLAGS:
438 0 : if ((ifp->if_flags & IFF_UP) == IFF_UP)
439 0 : ifp->if_flags |= IFF_RUNNING;
440 :
441 0 : if ((ifp->if_flags & IFF_UP) == 0)
442 0 : ifp->if_flags &= ~IFF_RUNNING;
443 :
444 : break;
445 : case SIOCBRDGRTS:
446 0 : baconf->ifbac_len = 0;
447 0 : break;
448 : case SIOCBRDGGRL:
449 0 : bc->ifbrl_len = 0;
450 0 : break;
451 : case SIOCBRDGGPARAM:
452 0 : if ((bp = bs->bs_root_port) == NULL)
453 0 : brop->ifbop_root_port = 0;
454 : else
455 0 : brop->ifbop_root_port = bp->bp_ifp->if_index;
456 0 : brop->ifbop_maxage = bs->bs_bridge_max_age >> 8;
457 0 : brop->ifbop_hellotime = bs->bs_bridge_htime >> 8;
458 0 : brop->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8;
459 0 : brop->ifbop_holdcount = bs->bs_txholdcount;
460 0 : brop->ifbop_priority = bs->bs_bridge_priority;
461 0 : brop->ifbop_protocol = bs->bs_protover;
462 0 : brop->ifbop_root_bridge = bs->bs_root_pv.pv_root_id;
463 0 : brop->ifbop_root_path_cost = bs->bs_root_pv.pv_cost;
464 0 : brop->ifbop_root_port = bs->bs_root_pv.pv_port_id;
465 0 : brop->ifbop_desg_bridge = bs->bs_root_pv.pv_dbridge_id;
466 0 : brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
467 0 : brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
468 0 : break;
469 : case SIOCSWGDPID:
470 : case SIOCSWSDPID:
471 : case SIOCSWGMAXFLOW:
472 : case SIOCSWGMAXGROUP:
473 : case SIOCSWSPORTNO:
474 0 : error = swofp_ioctl(ifp, cmd, data);
475 0 : break;
476 : default:
477 : error = ENOTTY;
478 0 : break;
479 : }
480 :
481 0 : return (error);
482 : }
483 :
484 : int
485 0 : switch_port_add(struct switch_softc *sc, struct ifbreq *req)
486 : {
487 : struct ifnet *ifs;
488 : struct switch_port *swpo;
489 : int error;
490 :
491 0 : if ((ifs = ifunit(req->ifbr_ifsname)) == NULL)
492 0 : return (ENOENT);
493 :
494 0 : if (ifs->if_bridgeport != NULL)
495 0 : return (EBUSY);
496 :
497 0 : if (ifs->if_switchport != NULL) {
498 0 : swpo = (struct switch_port *)ifs->if_switchport;
499 0 : if (swpo->swpo_switch == sc)
500 0 : return (EEXIST);
501 : else
502 0 : return (EBUSY);
503 : }
504 :
505 0 : if (ifs->if_type == IFT_ETHER) {
506 0 : if ((error = ifpromisc(ifs, 1)) != 0)
507 0 : return (error);
508 : }
509 :
510 0 : swpo = malloc(sizeof(*swpo), M_DEVBUF, M_NOWAIT|M_ZERO);
511 0 : if (swpo == NULL) {
512 0 : if (ifs->if_type == IFT_ETHER)
513 0 : ifpromisc(ifs, 0);
514 0 : return (ENOMEM);
515 : }
516 0 : swpo->swpo_switch = sc;
517 0 : swpo->swpo_ifindex = ifs->if_index;
518 0 : ifs->if_switchport = (caddr_t)swpo;
519 0 : if_ih_insert(ifs, switch_input, NULL);
520 0 : swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index);
521 0 : swpo->swpo_dhcookie = hook_establish(ifs->if_detachhooks, 0,
522 0 : switch_port_detach, ifs);
523 :
524 0 : nanouptime(&swpo->swpo_appended);
525 :
526 0 : TAILQ_INSERT_TAIL(&sc->sc_swpo_list, swpo, swpo_list_next);
527 :
528 0 : return (0);
529 0 : }
530 :
531 : int
532 0 : switch_port_list(struct switch_softc *sc, struct ifbifconf *bifc)
533 : {
534 : struct switch_port *swpo;
535 : struct ifnet *ifs;
536 0 : struct ifbreq breq;
537 : int total = 0, n = 0, error = 0;
538 :
539 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next)
540 0 : total++;
541 :
542 0 : if (bifc->ifbic_len == 0)
543 : goto done;
544 :
545 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
546 0 : memset(&breq, 0, sizeof(breq));
547 :
548 0 : if (bifc->ifbic_len < sizeof(breq))
549 : break;
550 :
551 0 : ifs = if_get(swpo->swpo_ifindex);
552 0 : if (ifs == NULL) {
553 : error = ENOENT;
554 0 : goto done;
555 : }
556 0 : strlcpy(breq.ifbr_ifsname, ifs->if_xname, IFNAMSIZ);
557 0 : if_put(ifs);
558 :
559 0 : strlcpy(breq.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
560 0 : breq.ifbr_ifsflags = swpo->swpo_flags;
561 0 : breq.ifbr_portno = swpo->swpo_port_no;
562 :
563 0 : if ((error = copyout((caddr_t)&breq,
564 0 : (caddr_t)(bifc->ifbic_req + n), sizeof(breq))) != 0)
565 : goto done;
566 :
567 0 : bifc->ifbic_len -= sizeof(breq);
568 0 : n++;
569 : }
570 :
571 : done:
572 0 : bifc->ifbic_len = n * sizeof(breq);
573 0 : return (error);
574 0 : }
575 :
576 : void
577 0 : switch_port_detach(void *arg)
578 : {
579 0 : struct ifnet *ifp = (struct ifnet *)arg;
580 : struct switch_softc *sc;
581 : struct switch_port *swpo;
582 :
583 0 : swpo = (struct switch_port *)ifp->if_switchport;
584 0 : sc = swpo->swpo_switch;
585 0 : if (swpo->swpo_flags & IFBIF_LOCAL)
586 0 : switch_port_unset_local(sc, swpo);
587 :
588 0 : ifp->if_switchport = NULL;
589 0 : hook_disestablish(ifp->if_detachhooks, swpo->swpo_dhcookie);
590 0 : ifpromisc(ifp, 0);
591 0 : if_ih_remove(ifp, switch_input, NULL);
592 0 : TAILQ_REMOVE(&sc->sc_swpo_list, swpo, swpo_list_next);
593 0 : free(swpo, M_DEVBUF, sizeof(*swpo));
594 0 : }
595 :
596 : int
597 0 : switch_port_del(struct switch_softc *sc, struct ifbreq *req)
598 : {
599 : struct switch_port *swpo;
600 : struct ifnet *ifs;
601 : int error = 0;
602 :
603 0 : TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
604 0 : if ((ifs = if_get(swpo->swpo_ifindex)) == NULL)
605 : continue;
606 0 : if (strncmp(ifs->if_xname, req->ifbr_ifsname, IFNAMSIZ) == 0)
607 : break;
608 0 : if_put(ifs);
609 0 : }
610 :
611 0 : if (swpo) {
612 0 : switch_port_detach(ifs);
613 0 : if_put(ifs);
614 : error = 0;
615 0 : } else
616 : error = ENOENT;
617 :
618 0 : return (error);
619 : }
620 :
621 : int
622 0 : switch_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
623 : {
624 0 : KASSERT(m->m_flags & M_PKTHDR);
625 :
626 0 : if (m->m_flags & M_PROTO1) {
627 0 : m->m_flags &= ~M_PROTO1;
628 0 : return (0);
629 : }
630 :
631 0 : niq_enqueue(&switchintrq, m);
632 :
633 0 : return (1);
634 0 : }
635 :
636 :
637 : struct mbuf *
638 0 : switch_port_ingress(struct switch_softc *sc, struct ifnet *src_if,
639 : struct mbuf *m)
640 : {
641 : struct switch_port *swpo;
642 0 : struct ether_header eh;
643 :
644 0 : swpo = (struct switch_port *)src_if->if_switchport;
645 :
646 0 : sc->sc_if.if_ipackets++;
647 0 : sc->sc_if.if_ibytes += m->m_pkthdr.len;
648 :
649 0 : m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
650 : #if 0
651 : /* It's the "#if 0" because it doesn't test switch(4) with pf(4)
652 : * or with ipsec(4).
653 : */
654 : if ((m = bridge_ip((struct bridge_softc *)sc,
655 : PF_IN, src_if, &eh, m)) == NULL) {
656 : sc->sc_if.if_ierrors++;
657 : return (NULL);
658 : }
659 : #endif /* NPF */
660 :
661 0 : return (m);
662 0 : }
663 :
664 : void
665 0 : switch_port_egress(struct switch_softc *sc, struct switch_fwdp_queue *fwdp_q,
666 : struct mbuf *m)
667 : {
668 : struct switch_port *swpo;
669 : struct ifnet *dst_if;
670 : struct mbuf *mc;
671 0 : struct ether_header eh;
672 : int len, used = 0;
673 :
674 : #if NBPFILTER > 0
675 0 : if (sc->sc_if.if_bpf)
676 0 : bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
677 : #endif
678 :
679 0 : m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
680 0 : TAILQ_FOREACH(swpo, fwdp_q, swpo_fwdp_next) {
681 :
682 0 : if ((dst_if = if_get(swpo->swpo_ifindex)) == NULL)
683 : continue;
684 :
685 0 : if ((dst_if->if_flags & IFF_RUNNING) == 0)
686 : goto out;
687 :
688 0 : if (TAILQ_NEXT(swpo, swpo_fwdp_next) == NULL) {
689 : mc = m;
690 : used = 1;
691 0 : } else {
692 0 : mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
693 0 : if (mc == NULL)
694 : goto out;
695 : }
696 :
697 : #if 0
698 : /* It's the "#if 0" because it doesn't test switch(4) with pf(4)
699 : * or with ipsec(4).
700 : */
701 : if ((mc = bridge_ip((struct bridge_softc *)sc,
702 : PF_OUT, dst_if, &eh, mc)) == NULL) {
703 : sc->sc_if.if_ierrors++;
704 : goto out;
705 : }
706 : #endif
707 :
708 0 : len = mc->m_pkthdr.len;
709 : #if NVLAN > 0
710 0 : if ((mc->m_flags & M_VLANTAG) &&
711 0 : (dst_if->if_capabilities & IFCAP_VLAN_HWTAGGING) == 0)
712 0 : len += ETHER_VLAN_ENCAP_LEN;
713 : #endif
714 :
715 : /*
716 : * Only if egress port has local port capabilities, it doesn't
717 : * need fragment because a frame sends up local network stack.
718 : */
719 0 : if (!(swpo->swpo_flags & IFBIF_LOCAL) &&
720 0 : ((len - ETHER_HDR_LEN) > dst_if->if_mtu))
721 0 : bridge_fragment((struct bridge_softc *)sc,
722 : dst_if, &eh, mc);
723 : else
724 0 : switch_ifenqueue(sc, dst_if, mc,
725 0 : (swpo->swpo_flags & IFBIF_LOCAL));
726 : out:
727 :
728 0 : if_put(dst_if);
729 0 : }
730 :
731 0 : if (!used)
732 0 : m_freem(m);
733 0 : }
734 :
735 : int
736 0 : switch_ifenqueue(struct switch_softc *sc, struct ifnet *ifp,
737 : struct mbuf *m, int local)
738 : {
739 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
740 : int error, len;
741 :
742 : /* Loop prevention. */
743 0 : m->m_flags |= M_PROTO1;
744 :
745 0 : len = m->m_pkthdr.len;
746 :
747 0 : if (local) {
748 0 : ml_enqueue(&ml, m);
749 0 : if_input(ifp, &ml);
750 0 : } else {
751 0 : error = if_enqueue(ifp, m);
752 0 : if (error) {
753 0 : sc->sc_if.if_oerrors++;
754 0 : return (error);
755 : }
756 0 : sc->sc_if.if_opackets++;
757 0 : sc->sc_if.if_obytes += len;
758 : }
759 :
760 0 : return (0);
761 0 : }
762 :
763 : void
764 0 : switch_port_ifb_start(struct ifnet *ifp)
765 : {
766 : struct mbuf *m;
767 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
768 :
769 0 : for (;;) {
770 0 : IFQ_DEQUEUE(&ifp->if_snd, m);
771 0 : if (m == NULL)
772 : return;
773 :
774 : #if NBPFILTER > 0
775 0 : if (ifp->if_bpf)
776 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
777 : #endif /* NBPFILTER > 0 */
778 :
779 0 : ml_enqueue(&ml, m);
780 0 : if_input(ifp, &ml);
781 : }
782 0 : }
783 :
784 : /*
785 : * Flow Classifier
786 : */
787 :
788 : int
789 0 : switch_swfcl_dup(struct switch_flow_classify *from,
790 : struct switch_flow_classify *to)
791 : {
792 0 : memset(to, 0, sizeof(*to));
793 :
794 0 : to->swfcl_flow_hash = from->swfcl_flow_hash;
795 0 : to->swfcl_metadata = from->swfcl_metadata;
796 0 : to->swfcl_cookie = from->swfcl_cookie;
797 0 : to->swfcl_table_id = from->swfcl_table_id;
798 0 : to->swfcl_in_port = from->swfcl_in_port;
799 :
800 0 : if (from->swfcl_tunnel) {
801 0 : to->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
802 0 : if (to->swfcl_tunnel == NULL)
803 : goto failed;
804 0 : memcpy(to->swfcl_tunnel, from->swfcl_tunnel,
805 : sizeof(*from->swfcl_tunnel));
806 0 : }
807 0 : if (from->swfcl_ether) {
808 0 : to->swfcl_ether = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
809 0 : if (to->swfcl_ether == NULL)
810 : goto failed;
811 0 : memcpy(to->swfcl_ether, from->swfcl_ether,
812 : sizeof(*from->swfcl_ether));
813 0 : }
814 0 : if (from->swfcl_vlan) {
815 0 : to->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
816 0 : if (to->swfcl_vlan == NULL)
817 : goto failed;
818 0 : memcpy(to->swfcl_vlan, from->swfcl_vlan,
819 : sizeof(*from->swfcl_vlan));
820 0 : }
821 0 : if (from->swfcl_ipv4) {
822 0 : to->swfcl_ipv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
823 0 : if (to->swfcl_ipv4 == NULL)
824 : goto failed;
825 0 : memcpy(to->swfcl_ipv4, from->swfcl_ipv4,
826 : sizeof(*from->swfcl_ipv4));
827 0 : }
828 0 : if (from->swfcl_ipv6) {
829 0 : to->swfcl_ipv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
830 0 : if (to->swfcl_ipv6 == NULL)
831 : goto failed;
832 0 : memcpy(to->swfcl_ipv6, from->swfcl_ipv6,
833 : sizeof(*from->swfcl_ipv6));
834 0 : }
835 0 : if (from->swfcl_arp) {
836 0 : to->swfcl_arp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
837 0 : if (to->swfcl_arp == NULL)
838 : goto failed;
839 0 : memcpy(to->swfcl_arp, from->swfcl_arp,
840 : sizeof(*from->swfcl_arp));
841 :
842 0 : }
843 0 : if (from->swfcl_nd6) {
844 0 : to->swfcl_nd6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
845 0 : if (to->swfcl_nd6 == NULL)
846 : goto failed;
847 0 : memcpy(to->swfcl_nd6, from->swfcl_nd6,
848 : sizeof(*from->swfcl_nd6));
849 0 : }
850 0 : if (from->swfcl_icmpv4) {
851 0 : to->swfcl_icmpv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
852 0 : if (to->swfcl_icmpv4 == NULL)
853 : goto failed;
854 0 : memcpy(to->swfcl_icmpv4, from->swfcl_icmpv4,
855 : sizeof(*from->swfcl_icmpv4));
856 0 : }
857 0 : if (from->swfcl_icmpv6) {
858 0 : to->swfcl_icmpv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
859 0 : if (to->swfcl_icmpv6 == NULL)
860 : goto failed;
861 0 : memcpy(to->swfcl_icmpv6, from->swfcl_icmpv6,
862 : sizeof(*from->swfcl_icmpv6));
863 0 : }
864 0 : if (from->swfcl_tcp) {
865 0 : to->swfcl_tcp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
866 0 : if (to->swfcl_tcp == NULL)
867 : goto failed;
868 0 : memcpy(to->swfcl_tcp, from->swfcl_tcp,
869 : sizeof(*from->swfcl_tcp));
870 0 : }
871 0 : if (from->swfcl_udp) {
872 0 : to->swfcl_udp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
873 0 : if (to->swfcl_udp == NULL)
874 : goto failed;
875 0 : memcpy(to->swfcl_udp, from->swfcl_udp,
876 : sizeof(*from->swfcl_udp));
877 0 : }
878 0 : if (from->swfcl_sctp) {
879 0 : to->swfcl_sctp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
880 0 : if (to->swfcl_sctp == NULL)
881 : goto failed;
882 0 : memcpy(to->swfcl_sctp, from->swfcl_sctp,
883 : sizeof(*from->swfcl_sctp));
884 0 : }
885 :
886 0 : return (0);
887 : failed:
888 0 : switch_swfcl_free(to);
889 0 : return (ENOBUFS);
890 0 : }
891 :
892 : void
893 0 : switch_swfcl_free(struct switch_flow_classify *swfcl)
894 : {
895 0 : if (swfcl->swfcl_tunnel)
896 0 : pool_put(&swfcl_pool, swfcl->swfcl_tunnel);
897 0 : if (swfcl->swfcl_ether)
898 0 : pool_put(&swfcl_pool, swfcl->swfcl_ether);
899 0 : if (swfcl->swfcl_vlan)
900 0 : pool_put(&swfcl_pool, swfcl->swfcl_vlan);
901 0 : if (swfcl->swfcl_ipv4)
902 0 : pool_put(&swfcl_pool, swfcl->swfcl_ipv4);
903 0 : if (swfcl->swfcl_ipv6)
904 0 : pool_put(&swfcl_pool, swfcl->swfcl_ipv6);
905 0 : if (swfcl->swfcl_arp)
906 0 : pool_put(&swfcl_pool, swfcl->swfcl_arp);
907 0 : if (swfcl->swfcl_nd6)
908 0 : pool_put(&swfcl_pool, swfcl->swfcl_nd6);
909 0 : if (swfcl->swfcl_icmpv4)
910 0 : pool_put(&swfcl_pool, swfcl->swfcl_icmpv4);
911 0 : if (swfcl->swfcl_icmpv6)
912 0 : pool_put(&swfcl_pool, swfcl->swfcl_icmpv6);
913 0 : if (swfcl->swfcl_tcp)
914 0 : pool_put(&swfcl_pool, swfcl->swfcl_tcp);
915 0 : if (swfcl->swfcl_udp)
916 0 : pool_put(&swfcl_pool, swfcl->swfcl_udp);
917 0 : if (swfcl->swfcl_sctp)
918 0 : pool_put(&swfcl_pool, swfcl->swfcl_sctp);
919 :
920 0 : memset(swfcl, 0, sizeof(*swfcl));
921 0 : }
922 :
923 : struct mbuf *
924 0 : switch_flow_classifier_udp(struct mbuf *m, int *offset,
925 : struct switch_flow_classify *swfcl)
926 : {
927 : struct udphdr *uh;
928 :
929 0 : swfcl->swfcl_udp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
930 0 : if (swfcl->swfcl_udp == NULL) {
931 0 : m_freem(m);
932 0 : return (NULL);
933 : }
934 :
935 0 : if (m->m_len < (*offset + sizeof(*uh)) &&
936 0 : (m = m_pullup(m, *offset + sizeof(*uh))) == NULL)
937 0 : return (NULL);
938 :
939 0 : uh = (struct udphdr *)((m)->m_data + *offset);
940 :
941 0 : swfcl->swfcl_udp->udp_src = uh->uh_sport;
942 0 : swfcl->swfcl_udp->udp_dst = uh->uh_dport;
943 :
944 0 : return (m);
945 0 : }
946 :
947 : struct mbuf *
948 0 : switch_flow_classifier_tcp(struct mbuf *m, int *offset,
949 : struct switch_flow_classify *swfcl)
950 : {
951 : struct tcphdr *th;
952 :
953 0 : swfcl->swfcl_tcp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
954 0 : if (swfcl->swfcl_tcp == NULL) {
955 0 : m_freem(m);
956 0 : return (NULL);
957 : }
958 :
959 0 : if (m->m_len < (*offset + sizeof(*th)) &&
960 0 : (m = m_pullup(m, *offset + sizeof(*th))) == NULL)
961 0 : return (NULL);
962 :
963 0 : th = (struct tcphdr *)((m)->m_data + *offset);
964 :
965 0 : swfcl->swfcl_tcp->tcp_src = th->th_sport;
966 0 : swfcl->swfcl_tcp->tcp_dst = th->th_dport;
967 0 : swfcl->swfcl_tcp->tcp_flags = th->th_flags;
968 :
969 0 : return (m);
970 0 : }
971 :
972 : struct mbuf *
973 0 : switch_flow_classifier_icmpv4(struct mbuf *m, int *offset,
974 : struct switch_flow_classify *swfcl)
975 : {
976 : struct icmp *icmp;
977 :
978 0 : swfcl->swfcl_icmpv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
979 0 : if (swfcl->swfcl_icmpv4 == NULL) {
980 0 : m_freem(m);
981 0 : return (NULL);
982 : }
983 :
984 0 : if (m->m_len < (*offset + ICMP_MINLEN) &&
985 0 : (m = m_pullup(m, (*offset + ICMP_MINLEN))) == NULL)
986 0 : return (NULL);
987 :
988 0 : icmp = (struct icmp *)((m)->m_data + *offset);
989 :
990 0 : swfcl->swfcl_icmpv4->icmpv4_type = icmp->icmp_type;
991 0 : swfcl->swfcl_icmpv4->icmpv4_code = icmp->icmp_code;
992 :
993 0 : return (m);
994 0 : }
995 :
996 : #ifdef INET6
997 : struct mbuf *
998 0 : switch_flow_classifier_nd6(struct mbuf *m, int *offset,
999 : struct switch_flow_classify *swfcl)
1000 : {
1001 : struct icmp6_hdr *icmp6;
1002 : struct nd_neighbor_advert *nd_na;
1003 : struct nd_neighbor_solicit *nd_ns;
1004 0 : union nd_opts ndopts;
1005 : uint8_t *lladdr;
1006 : int lladdrlen;
1007 0 : int icmp6len = m->m_pkthdr.len - *offset;
1008 :
1009 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offset, sizeof(*icmp6));
1010 0 : if (icmp6 == NULL)
1011 : goto failed;
1012 :
1013 0 : switch (icmp6->icmp6_type) {
1014 : case ND_NEIGHBOR_ADVERT:
1015 0 : if (icmp6len < sizeof(struct nd_neighbor_advert))
1016 : goto failed;
1017 : break;
1018 : case ND_NEIGHBOR_SOLICIT:
1019 0 : if (icmp6len < sizeof(struct nd_neighbor_solicit))
1020 : goto failed;
1021 : break;
1022 : }
1023 :
1024 0 : swfcl->swfcl_nd6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1025 0 : if (swfcl->swfcl_nd6 == NULL)
1026 : goto failed;
1027 :
1028 0 : switch (icmp6->icmp6_type) {
1029 : case ND_NEIGHBOR_ADVERT:
1030 0 : IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m,
1031 : *offset, icmp6len);
1032 :
1033 0 : if (nd_na == NULL)
1034 : goto failed;
1035 :
1036 0 : swfcl->swfcl_nd6->nd6_target = nd_na->nd_na_target;
1037 0 : icmp6len -= sizeof(*nd_na);
1038 0 : nd6_option_init(nd_na + 1, icmp6len, &ndopts);
1039 0 : if (nd6_options(&ndopts) < 0)
1040 : goto failed;
1041 :
1042 0 : if (!ndopts.nd_opts_tgt_lladdr)
1043 : goto failed;
1044 :
1045 0 : lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
1046 0 : lladdrlen = (ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3) - 2;
1047 :
1048 : /* switch(4) only supports Ethernet interfaces */
1049 0 : if (lladdrlen != ETHER_ADDR_LEN)
1050 : goto failed;
1051 0 : memcpy(swfcl->swfcl_nd6->nd6_lladdr, lladdr, ETHER_ADDR_LEN);
1052 0 : break;
1053 : case ND_NEIGHBOR_SOLICIT:
1054 0 : IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m,
1055 : *offset, icmp6len);
1056 0 : if (nd_ns == NULL)
1057 : goto failed;
1058 0 : swfcl->swfcl_nd6->nd6_target = nd_ns->nd_ns_target;
1059 0 : icmp6len -= sizeof(*nd_ns);
1060 :
1061 0 : nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
1062 0 : if (nd6_options(&ndopts) < 0)
1063 : goto failed;
1064 :
1065 0 : if (!ndopts.nd_opts_src_lladdr)
1066 : goto failed;
1067 0 : lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
1068 0 : lladdrlen = (ndopts.nd_opts_src_lladdr->nd_opt_len << 3) - 2;
1069 :
1070 : /* switch(4) only supports Ethernet interfaces */
1071 0 : if (lladdrlen != ETHER_ADDR_LEN)
1072 : goto failed;
1073 0 : memcpy(swfcl->swfcl_nd6->nd6_lladdr, lladdr, ETHER_ADDR_LEN);
1074 :
1075 0 : break;
1076 : }
1077 :
1078 0 : return (m);
1079 :
1080 : failed:
1081 0 : m_freem(m);
1082 0 : return (NULL);
1083 0 : }
1084 :
1085 : struct mbuf *
1086 0 : switch_flow_classifier_icmpv6(struct mbuf *m, int *offset,
1087 : struct switch_flow_classify *swfcl)
1088 : {
1089 : struct icmp6_hdr *icmp6;
1090 :
1091 0 : swfcl->swfcl_icmpv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1092 0 : if (swfcl->swfcl_icmpv6 == NULL) {
1093 0 : m_freem(m);
1094 0 : return (NULL);
1095 : }
1096 :
1097 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offset, sizeof(*icmp6));
1098 0 : if (icmp6 == NULL)
1099 0 : return (NULL); /* m was already freed */
1100 :
1101 0 : swfcl->swfcl_icmpv6->icmpv6_type = icmp6->icmp6_type;
1102 0 : swfcl->swfcl_icmpv6->icmpv6_code = icmp6->icmp6_code;
1103 :
1104 0 : switch (icmp6->icmp6_type) {
1105 : case ND_NEIGHBOR_SOLICIT:
1106 : case ND_NEIGHBOR_ADVERT:
1107 0 : return switch_flow_classifier_nd6(m, offset, swfcl);
1108 : }
1109 :
1110 0 : return (m);
1111 0 : }
1112 : #endif /* INET6 */
1113 :
1114 : struct mbuf *
1115 0 : switch_flow_classifier_ipv4(struct mbuf *m, int *offset,
1116 : struct switch_flow_classify *swfcl)
1117 : {
1118 : struct ip *ip;
1119 :
1120 0 : swfcl->swfcl_ipv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1121 0 : if (swfcl->swfcl_ipv4 == NULL) {
1122 0 : m_freem(m);
1123 0 : return (NULL);
1124 : }
1125 :
1126 0 : if (m->m_len < (*offset + sizeof(*ip)) &&
1127 0 : (m = m_pullup(m, *offset + sizeof(*ip))) == NULL)
1128 0 : return (NULL);
1129 :
1130 0 : ip = (struct ip *)((m)->m_data + *offset);
1131 :
1132 0 : swfcl->swfcl_ipv4->ipv4_tos = ip->ip_tos;
1133 0 : swfcl->swfcl_ipv4->ipv4_ttl = ip->ip_ttl;
1134 0 : swfcl->swfcl_ipv4->ipv4_proto = ip->ip_p;
1135 :
1136 0 : memcpy(&swfcl->swfcl_ipv4->ipv4_src, &ip->ip_src.s_addr,
1137 : sizeof(uint32_t));
1138 0 : memcpy(&swfcl->swfcl_ipv4->ipv4_dst, &ip->ip_dst.s_addr,
1139 : sizeof(uint32_t));
1140 :
1141 0 : *offset += (ip->ip_hl << 2);
1142 :
1143 0 : switch (ip->ip_p) {
1144 : case IPPROTO_UDP:
1145 0 : return switch_flow_classifier_udp(m, offset, swfcl);
1146 : case IPPROTO_TCP:
1147 0 : return switch_flow_classifier_tcp(m, offset, swfcl);
1148 : case IPPROTO_ICMP:
1149 0 : return switch_flow_classifier_icmpv4(m, offset, swfcl);
1150 : }
1151 :
1152 0 : return (m);
1153 0 : }
1154 :
1155 : #ifdef INET6
1156 : struct mbuf *
1157 0 : switch_flow_classifier_ipv6(struct mbuf *m, int *offset,
1158 : struct switch_flow_classify *swfcl)
1159 : {
1160 : struct ip6_hdr *ip6;
1161 :
1162 0 : swfcl->swfcl_ipv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1163 0 : if (swfcl->swfcl_ipv6 == NULL) {
1164 0 : m_freem(m);
1165 0 : return (NULL);
1166 : }
1167 :
1168 0 : if (m->m_len < (*offset + sizeof(*ip6)) &&
1169 0 : (m = m_pullup(m, *offset + sizeof(*ip6))) == NULL)
1170 0 : return (NULL);
1171 :
1172 0 : ip6 = (struct ip6_hdr *)((m)->m_data + *offset);
1173 :
1174 0 : swfcl->swfcl_ipv6->ipv6_src = ip6->ip6_src;
1175 0 : swfcl->swfcl_ipv6->ipv6_dst = ip6->ip6_dst;
1176 0 : swfcl->swfcl_ipv6->ipv6_flow_label =
1177 0 : (ip6->ip6_flow & IPV6_FLOWLABEL_MASK);
1178 0 : swfcl->swfcl_ipv6->ipv6_tclass = (ntohl(ip6->ip6_flow) >> 20);
1179 0 : swfcl->swfcl_ipv6->ipv6_hlimit = ip6->ip6_hlim;
1180 0 : swfcl->swfcl_ipv6->ipv6_nxt = ip6->ip6_nxt;
1181 :
1182 0 : *offset += sizeof(*ip6);
1183 :
1184 0 : switch (ip6->ip6_nxt) {
1185 : case IPPROTO_UDP:
1186 0 : return switch_flow_classifier_udp(m, offset, swfcl);
1187 : case IPPROTO_TCP:
1188 0 : return switch_flow_classifier_tcp(m, offset, swfcl);
1189 : case IPPROTO_ICMPV6:
1190 0 : return switch_flow_classifier_icmpv6(m, offset, swfcl);
1191 : }
1192 :
1193 0 : return (m);
1194 0 : }
1195 : #endif /* INET6 */
1196 :
1197 : struct mbuf *
1198 0 : switch_flow_classifier_arp(struct mbuf *m, int *offset,
1199 : struct switch_flow_classify *swfcl)
1200 : {
1201 : struct ether_arp *ea;
1202 :
1203 0 : swfcl->swfcl_arp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1204 0 : if (swfcl->swfcl_arp == NULL) {
1205 0 : m_freem(m);
1206 0 : return (NULL);
1207 : }
1208 :
1209 0 : if (m->m_len < (*offset + sizeof(*ea)) &&
1210 0 : (m = m_pullup(m, *offset + sizeof(*ea))) == NULL)
1211 0 : return (NULL);
1212 :
1213 0 : ea = (struct ether_arp *)((m)->m_data + *offset);
1214 :
1215 0 : swfcl->swfcl_arp->_arp_op = ea->arp_op;
1216 :
1217 0 : memcpy(swfcl->swfcl_arp->arp_sha, &ea->arp_sha, ETHER_ADDR_LEN);
1218 0 : memcpy(swfcl->swfcl_arp->arp_tha, &ea->arp_tha, ETHER_ADDR_LEN);
1219 0 : memcpy(&swfcl->swfcl_arp->arp_sip, &ea->arp_spa, sizeof(uint32_t));
1220 0 : memcpy(&swfcl->swfcl_arp->arp_tip, &ea->arp_tpa, sizeof(uint32_t));
1221 :
1222 0 : return (m);
1223 0 : }
1224 :
1225 : struct mbuf *
1226 0 : switch_flow_classifier_ether(struct mbuf *m, int *offset,
1227 : struct switch_flow_classify *swfcl)
1228 : {
1229 : struct ether_header *eh;
1230 : struct ether_vlan_header *evl;
1231 : uint16_t ether_type;
1232 :
1233 0 : swfcl->swfcl_ether = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1234 0 : if (swfcl->swfcl_ether == NULL) {
1235 0 : m_freem(m);
1236 0 : return (NULL);
1237 : }
1238 :
1239 0 : if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL)
1240 0 : return (NULL);
1241 0 : eh = mtod(m, struct ether_header *);
1242 :
1243 0 : memcpy(swfcl->swfcl_ether->eth_src, eh->ether_shost, ETHER_ADDR_LEN);
1244 0 : memcpy(swfcl->swfcl_ether->eth_dst, eh->ether_dhost, ETHER_ADDR_LEN);
1245 :
1246 0 : if ((m->m_flags & M_VLANTAG) ||
1247 0 : (ntohs(eh->ether_type) == ETHERTYPE_VLAN) ||
1248 0 : (ntohs(eh->ether_type) == ETHERTYPE_QINQ)) {
1249 0 : swfcl->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1250 0 : if (swfcl->swfcl_vlan == NULL) {
1251 0 : m_freem(m);
1252 0 : return (NULL);
1253 : }
1254 : }
1255 :
1256 0 : if (m->m_flags & M_VLANTAG) {
1257 : /*
1258 : * Hardware VLAN tagging is only supported for 801.1Q VLAN,
1259 : * but not for 802.1ad QinQ.
1260 : */
1261 0 : swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN);
1262 0 : swfcl->swfcl_vlan->vlan_vid =
1263 0 : htons(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag));
1264 0 : swfcl->swfcl_vlan->vlan_pcp =
1265 0 : EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
1266 0 : ether_type = eh->ether_type;
1267 0 : *offset += sizeof(*eh);
1268 0 : } else if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) {
1269 0 : if (m->m_len < sizeof(*evl) &&
1270 0 : (m = m_pullup(m, sizeof(*evl))) == NULL)
1271 0 : return (NULL);
1272 0 : evl = mtod(m, struct ether_vlan_header *);
1273 :
1274 : /*
1275 : * Software VLAN tagging is currently only supported for
1276 : * 801.1Q VLAN, but not for 802.1ad QinQ.
1277 : */
1278 0 : swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN);
1279 0 : swfcl->swfcl_vlan->vlan_vid =
1280 0 : (evl->evl_tag & htons(EVL_VLID_MASK));
1281 0 : swfcl->swfcl_vlan->vlan_pcp =
1282 0 : EVL_PRIOFTAG(ntohs(evl->evl_tag));
1283 0 : ether_type = evl->evl_proto;
1284 0 : *offset += sizeof(*evl);
1285 0 : } else {
1286 : ether_type = eh->ether_type;
1287 0 : *offset += sizeof(*eh);
1288 : }
1289 :
1290 0 : swfcl->swfcl_ether->eth_type = ether_type;
1291 :
1292 0 : ether_type = ntohs(ether_type);
1293 0 : switch (ether_type) {
1294 : case ETHERTYPE_ARP:
1295 0 : return switch_flow_classifier_arp(m, offset, swfcl);
1296 : case ETHERTYPE_IP:
1297 0 : return switch_flow_classifier_ipv4(m, offset, swfcl);
1298 : #ifdef INET6
1299 : case ETHERTYPE_IPV6:
1300 0 : return switch_flow_classifier_ipv6(m, offset, swfcl);
1301 : #endif /* INET6 */
1302 : case ETHERTYPE_MPLS:
1303 : /* unsupported yet */
1304 : break;
1305 : }
1306 :
1307 0 : return (m);
1308 0 : }
1309 :
1310 : struct mbuf *
1311 0 : switch_flow_classifier_tunnel(struct mbuf *m, int *offset,
1312 : struct switch_flow_classify *swfcl)
1313 : {
1314 : struct bridge_tunneltag *brtag;
1315 :
1316 0 : if ((brtag = bridge_tunnel(m)) == NULL)
1317 : goto out;
1318 :
1319 0 : if ((brtag->brtag_peer.sa.sa_family != AF_INET) &&
1320 0 : (brtag->brtag_peer.sa.sa_family != AF_INET6))
1321 : goto out;
1322 :
1323 0 : swfcl->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
1324 0 : if (swfcl->swfcl_tunnel == NULL) {
1325 0 : m_freem(m);
1326 0 : return (NULL);
1327 : }
1328 :
1329 0 : swfcl->swfcl_tunnel->tun_af = brtag->brtag_peer.sa.sa_family;
1330 0 : swfcl->swfcl_tunnel->tun_key = htobe64(brtag->brtag_id);
1331 0 : if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
1332 0 : swfcl->swfcl_tunnel->tun_ipv4_src =
1333 0 : brtag->brtag_local.sin.sin_addr;
1334 0 : swfcl->swfcl_tunnel->tun_ipv4_dst =
1335 0 : brtag->brtag_peer.sin.sin_addr;
1336 0 : } else {
1337 0 : swfcl->swfcl_tunnel->tun_ipv6_src =
1338 0 : brtag->brtag_local.sin6.sin6_addr;
1339 0 : swfcl->swfcl_tunnel->tun_ipv6_dst =
1340 0 : brtag->brtag_peer.sin6.sin6_addr;
1341 : }
1342 0 : bridge_tunneluntag(m);
1343 : out:
1344 0 : return switch_flow_classifier_ether(m, offset, swfcl);
1345 0 : }
1346 :
1347 : struct mbuf *
1348 0 : switch_flow_classifier(struct mbuf *m, uint32_t in_port,
1349 : struct switch_flow_classify *swfcl)
1350 : {
1351 0 : int offset = 0;
1352 :
1353 0 : memset(swfcl, 0, sizeof(*swfcl));
1354 0 : swfcl->swfcl_in_port = in_port;
1355 :
1356 0 : return switch_flow_classifier_tunnel(m, &offset, swfcl);
1357 0 : }
1358 :
1359 : void
1360 0 : switch_flow_classifier_dump(struct switch_softc *sc,
1361 : struct switch_flow_classify *swfcl)
1362 : {
1363 0 : char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN];
1364 :
1365 0 : log(LOG_DEBUG, "%s: ", sc->sc_if.if_xname);
1366 0 : addlog("in_port(%u),", swfcl->swfcl_in_port);
1367 :
1368 0 : if (swfcl->swfcl_tunnel) {
1369 0 : if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
1370 0 : inet_ntop(AF_INET,
1371 0 : (void *)&swfcl->swfcl_tunnel->tun_ipv4_src,
1372 0 : saddr, sizeof(saddr));
1373 0 : inet_ntop(AF_INET,
1374 0 : (void *)&swfcl->swfcl_tunnel->tun_ipv4_dst,
1375 0 : daddr, sizeof(daddr));
1376 0 : addlog("tun_ipv4_src(%s),tun_ipv4_dst(%s),"
1377 : "tun_id(%llu),", saddr, daddr,
1378 0 : be64toh(swfcl->swfcl_tunnel->tun_key));
1379 0 : } else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) {
1380 0 : inet_ntop(AF_INET6,
1381 0 : (void *)&swfcl->swfcl_tunnel->tun_ipv6_src,
1382 0 : saddr, sizeof(saddr));
1383 0 : inet_ntop(AF_INET6,
1384 0 : (void *)&swfcl->swfcl_tunnel->tun_ipv6_dst,
1385 0 : daddr, sizeof(daddr));
1386 0 : addlog("tun_ipv6_src(%s) tun_ipv6_dst(%s),"
1387 : "tun_id(%llu),", saddr, daddr,
1388 0 : be64toh(swfcl->swfcl_tunnel->tun_key));
1389 0 : }
1390 : }
1391 :
1392 0 : if (swfcl->swfcl_vlan) {
1393 0 : addlog("vlan_tpid(0x%0x4x),vlan_pcp(%u),vlan_vid(%u),",
1394 0 : ntohs(swfcl->swfcl_vlan->vlan_tpid),
1395 0 : swfcl->swfcl_vlan->vlan_pcp,
1396 0 : ntohs(swfcl->swfcl_vlan->vlan_vid));
1397 0 : }
1398 :
1399 0 : if (swfcl->swfcl_ether) {
1400 0 : addlog("eth_dst(%s),eth_src(%s),eth_type(0x%04x)",
1401 0 : ether_sprintf(swfcl->swfcl_ether->eth_dst),
1402 0 : ether_sprintf(swfcl->swfcl_ether->eth_src),
1403 0 : ntohs(swfcl->swfcl_ether->eth_type));
1404 0 : }
1405 :
1406 0 : if (swfcl->swfcl_arp) {
1407 0 : inet_ntop(AF_INET, (void *)&swfcl->swfcl_arp->arp_sip,
1408 0 : saddr, sizeof(saddr));
1409 0 : inet_ntop(AF_INET, (void *)&swfcl->swfcl_arp->arp_tip,
1410 0 : daddr, sizeof(daddr));
1411 0 : addlog("arp_op(%x),arp_tha(%s),arp_sha(%s),arp_sip(%s),"
1412 0 : "arp_tip(%s),", swfcl->swfcl_arp->_arp_op,
1413 0 : ether_sprintf(swfcl->swfcl_arp->arp_tha),
1414 0 : ether_sprintf(swfcl->swfcl_arp->arp_sha), saddr, daddr);
1415 0 : }
1416 :
1417 0 : if (swfcl->swfcl_ipv4) {
1418 0 : inet_ntop(AF_INET, (void *)&swfcl->swfcl_ipv4->ipv4_src,
1419 0 : saddr, sizeof(saddr));
1420 0 : inet_ntop(AF_INET, (void *)&swfcl->swfcl_ipv4->ipv4_dst,
1421 0 : daddr, sizeof(daddr));
1422 0 : addlog("ip_proto(%u),ip_tos(%u),ip_ttl(%u),ip_src(%s),"
1423 0 : "ip_dst(%s),", swfcl->swfcl_ipv4->ipv4_proto,
1424 0 : swfcl->swfcl_ipv4->ipv4_tos, swfcl->swfcl_ipv4->ipv4_ttl,
1425 : saddr, daddr);
1426 0 : }
1427 :
1428 0 : if (swfcl->swfcl_ipv6) {
1429 0 : inet_ntop(AF_INET6, (void *)&swfcl->swfcl_ipv6->ipv6_src,
1430 0 : saddr, sizeof(saddr));
1431 0 : inet_ntop(AF_INET6, (void *)&swfcl->swfcl_ipv6->ipv6_dst,
1432 0 : daddr, sizeof(daddr));
1433 0 : addlog("ip6_nxt(%u),ip6_flow_label(%u),ip6_tclass(%d),"
1434 : "ip6_hlimit(%u),ip6_src(%s),ip6_dst(%s),",
1435 0 : swfcl->swfcl_ipv6->ipv6_nxt,
1436 0 : ntohl(swfcl->swfcl_ipv6->ipv6_flow_label),
1437 0 : swfcl->swfcl_ipv6->ipv6_tclass,
1438 0 : swfcl->swfcl_ipv6->ipv6_hlimit, saddr, daddr);
1439 0 : }
1440 :
1441 0 : if (swfcl->swfcl_icmpv4) {
1442 0 : addlog("icmp_type(%u),icmp_code(%u),",
1443 0 : swfcl->swfcl_icmpv4->icmpv4_type,
1444 0 : swfcl->swfcl_icmpv4->icmpv4_code);
1445 0 : }
1446 :
1447 0 : if (swfcl->swfcl_icmpv6) {
1448 0 : addlog("icmp6_type(%u),icmp6_code(%u),",
1449 0 : swfcl->swfcl_icmpv6->icmpv6_type,
1450 0 : swfcl->swfcl_icmpv6->icmpv6_code);
1451 0 : }
1452 :
1453 0 : if (swfcl->swfcl_nd6) {
1454 0 : inet_ntop(AF_INET6, (void *)&swfcl->swfcl_nd6->nd6_target,
1455 0 : saddr, sizeof(saddr));
1456 0 : addlog("nd_target(%s),nd_lladdr(%s),", saddr,
1457 0 : ether_sprintf(swfcl->swfcl_nd6->nd6_lladdr));
1458 0 : }
1459 :
1460 0 : if (swfcl->swfcl_tcp) {
1461 0 : addlog("tcp_src(%u),tcp_dst(%u),tcp_flags(%x),",
1462 0 : ntohs(swfcl->swfcl_tcp->tcp_src),
1463 0 : ntohs(swfcl->swfcl_tcp->tcp_dst),
1464 0 : swfcl->swfcl_tcp->tcp_flags);
1465 0 : }
1466 :
1467 0 : if (swfcl->swfcl_udp) {
1468 0 : addlog("udp_src(%u),udp_dst(%u),",
1469 0 : ntohs(swfcl->swfcl_udp->udp_src),
1470 0 : ntohs(swfcl->swfcl_udp->udp_dst));
1471 0 : }
1472 :
1473 0 : addlog("\n");
1474 0 : }
1475 :
1476 : int
1477 0 : switch_mtap(caddr_t arg, struct mbuf *m, int dir, uint64_t datapath_id)
1478 : {
1479 0 : struct dlt_openflow_hdr of;
1480 :
1481 0 : of.of_datapath_id = htobe64(datapath_id);
1482 0 : of.of_direction = htonl(dir == BPF_DIRECTION_IN ?
1483 : DLT_OPENFLOW_TO_SWITCH : DLT_OPENFLOW_TO_CONTROLLER);
1484 :
1485 0 : return (bpf_mtap_hdr(arg, (caddr_t)&of, sizeof(of), m, dir, NULL));
1486 0 : }
1487 :
1488 : int
1489 0 : ofp_split_mbuf(struct mbuf *m, struct mbuf **mtail)
1490 : {
1491 : struct ofp_header *oh;
1492 : uint16_t ohlen;
1493 :
1494 0 : *mtail = NULL;
1495 :
1496 : again:
1497 : /* We need more data. */
1498 0 : if (m->m_pkthdr.len < sizeof(*oh))
1499 0 : return (-1);
1500 :
1501 0 : oh = mtod(m, struct ofp_header *);
1502 0 : ohlen = ntohs(oh->oh_length);
1503 :
1504 : /* We got an invalid packet header, skip it. */
1505 0 : if (ohlen < sizeof(*oh)) {
1506 0 : m_adj(m, sizeof(*oh));
1507 0 : goto again;
1508 : }
1509 :
1510 : /* Nothing to split. */
1511 0 : if (m->m_pkthdr.len == ohlen)
1512 0 : return (0);
1513 0 : else if (m->m_pkthdr.len < ohlen)
1514 0 : return (-1);
1515 :
1516 0 : *mtail = m_split(m, ohlen, M_NOWAIT);
1517 : /* No memory, try again later. */
1518 0 : if (*mtail == NULL)
1519 0 : return (-1);
1520 :
1521 0 : return (0);
1522 0 : }
|