]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_epair.c
epair: Remove unneeded includes and sort some of the rest
[FreeBSD/FreeBSD.git] / sys / net / if_epair.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008 The FreeBSD Foundation
5  * Copyright (c) 2009-2021 Bjoern A. Zeeb <bz@FreeBSD.org>
6  *
7  * This software was developed by CK Software GmbH under sponsorship
8  * from the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  * A pair of virtual back-to-back connected ethernet like interfaces
34  * (``two interfaces with a virtual cross-over cable'').
35  *
36  * This is mostly intended to be used to provide connectivity between
37  * different virtual network stack instances.
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include "opt_rss.h"
44 #include "opt_inet.h"
45 #include "opt_inet6.h"
46
47 #include <sys/param.h>
48 #include <sys/bus.h>
49 #include <sys/hash.h>
50 #include <sys/interrupt.h>
51 #include <sys/jail.h>
52 #include <sys/kernel.h>
53 #include <sys/libkern.h>
54 #include <sys/malloc.h>
55 #include <sys/mbuf.h>
56 #include <sys/module.h>
57 #include <sys/proc.h>
58 #include <sys/queue.h>
59 #include <sys/sched.h>
60 #include <sys/smp.h>
61 #include <sys/socket.h>
62 #include <sys/sockio.h>
63 #include <sys/taskqueue.h>
64
65 #include <net/bpf.h>
66 #include <net/ethernet.h>
67 #include <net/if.h>
68 #include <net/if_var.h>
69 #include <net/if_clone.h>
70 #include <net/if_media.h>
71 #include <net/if_var.h>
72 #include <net/if_types.h>
73 #include <net/netisr.h>
74 #ifdef RSS
75 #include <net/rss_config.h>
76 #ifdef INET
77 #include <netinet/in_rss.h>
78 #endif
79 #ifdef INET6
80 #include <netinet6/in6_rss.h>
81 #endif
82 #endif
83 #include <net/vnet.h>
84
85 static int epair_clone_match(struct if_clone *, const char *);
86 static int epair_clone_create(struct if_clone *, char *, size_t, caddr_t);
87 static int epair_clone_destroy(struct if_clone *, struct ifnet *);
88
89 static const char epairname[] = "epair";
90 #define RXRSIZE 4096    /* Probably overkill by 4-8x. */
91
92 static MALLOC_DEFINE(M_EPAIR, epairname,
93     "Pair of virtual cross-over connected Ethernet-like interfaces");
94
95 VNET_DEFINE_STATIC(struct if_clone *, epair_cloner);
96 #define V_epair_cloner  VNET(epair_cloner)
97
98 static unsigned int next_index = 0;
99 #define EPAIR_LOCK_INIT()               mtx_init(&epair_n_index_mtx, "epairidx", \
100                                             NULL, MTX_DEF)
101 #define EPAIR_LOCK_DESTROY()            mtx_destroy(&epair_n_index_mtx)
102 #define EPAIR_LOCK()                    mtx_lock(&epair_n_index_mtx)
103 #define EPAIR_UNLOCK()                  mtx_unlock(&epair_n_index_mtx)
104
105 struct epair_softc;
106 struct epair_queue {
107         struct mtx               mtx;
108         struct mbufq             q;
109         int                      id;
110         enum {
111                 EPAIR_QUEUE_IDLE,
112                 EPAIR_QUEUE_WAKING,
113                 EPAIR_QUEUE_RUNNING,
114         }                        state;
115         struct task              tx_task;
116         struct epair_softc      *sc;
117 };
118
119 static struct mtx epair_n_index_mtx;
120 struct epair_softc {
121         struct ifnet            *ifp;           /* This ifp. */
122         struct ifnet            *oifp;          /* other ifp of pair. */
123         int                      num_queues;
124         struct epair_queue      *queues;
125         struct ifmedia           media;         /* Media config (fake). */
126         STAILQ_ENTRY(epair_softc) entry;
127 };
128
129 struct epair_tasks_t {
130         int                      tasks;
131         struct taskqueue         *tq[MAXCPU];
132 };
133
134 static struct epair_tasks_t epair_tasks;
135
136 static void
137 epair_clear_mbuf(struct mbuf *m)
138 {
139         /* Remove any CSUM_SND_TAG as ether_input will barf. */
140         if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) {
141                 m_snd_tag_rele(m->m_pkthdr.snd_tag);
142                 m->m_pkthdr.snd_tag = NULL;
143                 m->m_pkthdr.csum_flags &= ~CSUM_SND_TAG;
144         }
145
146         m_tag_delete_nonpersistent(m);
147 }
148
149 static void
150 epair_tx_start_deferred(void *arg, int pending)
151 {
152         struct epair_queue *q = (struct epair_queue *)arg;
153         if_t ifp;
154         struct mbuf *m, *n;
155         bool resched;
156
157         ifp = q->sc->ifp;
158
159         if_ref(ifp);
160         CURVNET_SET(ifp->if_vnet);
161
162         mtx_lock(&q->mtx);
163         m = mbufq_flush(&q->q);
164         q->state = EPAIR_QUEUE_RUNNING;
165         mtx_unlock(&q->mtx);
166
167         while (m != NULL) {
168                 n = STAILQ_NEXT(m, m_stailqpkt);
169                 m->m_nextpkt = NULL;
170                 if_input(ifp, m);
171                 m = n;
172         }
173
174         /*
175          * Avoid flushing the queue more than once per task.  We can otherwise
176          * end up starving ourselves in a multi-epair routing configuration.
177          */
178         mtx_lock(&q->mtx);
179         if (mbufq_len(&q->q) > 0) {
180                 resched = true;
181                 q->state = EPAIR_QUEUE_WAKING;
182         } else {
183                 resched = false;
184                 q->state = EPAIR_QUEUE_IDLE;
185         }
186         mtx_unlock(&q->mtx);
187
188         if (resched)
189                 taskqueue_enqueue(epair_tasks.tq[q->id], &q->tx_task);
190
191         CURVNET_RESTORE();
192         if_rele(ifp);
193 }
194
195 static struct epair_queue *
196 epair_select_queue(struct epair_softc *sc, struct mbuf *m)
197 {
198         uint32_t bucket;
199 #ifdef RSS
200         struct ether_header *eh;
201         int ret;
202
203         ret = rss_m2bucket(m, &bucket);
204         if (ret) {
205                 /* Actually hash the packet. */
206                 eh = mtod(m, struct ether_header *);
207
208                 switch (ntohs(eh->ether_type)) {
209 #ifdef INET
210                 case ETHERTYPE_IP:
211                         rss_soft_m2cpuid_v4(m, 0, &bucket);
212                         break;
213 #endif
214 #ifdef INET6
215                 case ETHERTYPE_IPV6:
216                         rss_soft_m2cpuid_v6(m, 0, &bucket);
217                         break;
218 #endif
219                 default:
220                         bucket = 0;
221                         break;
222                 }
223         }
224         bucket %= sc->num_queues;
225 #else
226         bucket = 0;
227 #endif
228         return (&sc->queues[bucket]);
229 }
230
231 static void
232 epair_prepare_mbuf(struct mbuf *m, struct ifnet *src_ifp)
233 {
234         M_ASSERTPKTHDR(m);
235         epair_clear_mbuf(m);
236         if_setrcvif(m, src_ifp);
237         M_SETFIB(m, src_ifp->if_fib);
238
239         MPASS(m->m_nextpkt == NULL);
240         MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
241 }
242
243 static void
244 epair_menq(struct mbuf *m, struct epair_softc *osc)
245 {
246         struct epair_queue *q;
247         struct ifnet *ifp, *oifp;
248         int error, len;
249         bool mcast;
250
251         /*
252          * I know this looks weird. We pass the "other sc" as we need that one
253          * and can get both ifps from it as well.
254          */
255         oifp = osc->ifp;
256         ifp = osc->oifp;
257
258         epair_prepare_mbuf(m, oifp);
259
260         /* Save values as once the mbuf is queued, it's not ours anymore. */
261         len = m->m_pkthdr.len;
262         mcast = (m->m_flags & (M_BCAST | M_MCAST)) != 0;
263
264         q = epair_select_queue(osc, m);
265
266         mtx_lock(&q->mtx);
267         if (q->state == EPAIR_QUEUE_IDLE) {
268                 q->state = EPAIR_QUEUE_WAKING;
269                 taskqueue_enqueue(epair_tasks.tq[q->id], &q->tx_task);
270         }
271         error = mbufq_enqueue(&q->q, m);
272         mtx_unlock(&q->mtx);
273
274         if (error != 0) {
275                 m_freem(m);
276                 if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
277         } else {
278                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
279                 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
280                 if (mcast)
281                         if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
282                 if_inc_counter(oifp, IFCOUNTER_IPACKETS, 1);
283         }
284 }
285
286 static void
287 epair_start(struct ifnet *ifp)
288 {
289         struct mbuf *m;
290         struct epair_softc *sc;
291         struct ifnet *oifp;
292
293         /*
294          * We get packets here from ether_output via if_handoff()
295          * and need to put them into the input queue of the oifp
296          * and will put the packet into the receive-queue (rxq) of the
297          * other interface (oifp) of our pair.
298          */
299         sc = ifp->if_softc;
300         oifp = sc->oifp;
301         sc = oifp->if_softc;
302         for (;;) {
303                 IFQ_DEQUEUE(&ifp->if_snd, m);
304                 if (m == NULL)
305                         break;
306                 M_ASSERTPKTHDR(m);
307                 BPF_MTAP(ifp, m);
308
309                 /* In case either interface is not usable drop the packet. */
310                 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
311                     (ifp->if_flags & IFF_UP) == 0 ||
312                     (oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
313                     (oifp->if_flags & IFF_UP) == 0) {
314                         m_freem(m);
315                         continue;
316                 }
317
318                 (void) epair_menq(m, sc);
319         }
320 }
321
322 static int
323 epair_transmit(struct ifnet *ifp, struct mbuf *m)
324 {
325         struct epair_softc *sc;
326         struct ifnet *oifp;
327 #ifdef ALTQ
328         int len;
329         bool mcast;
330 #endif
331
332         if (m == NULL)
333                 return (0);
334         M_ASSERTPKTHDR(m);
335
336         /*
337          * We are not going to use the interface en/dequeue mechanism
338          * on the TX side. We are called from ether_output_frame()
339          * and will put the packet into the receive-queue (rxq) of the
340          * other interface (oifp) of our pair.
341          */
342         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
343                 m_freem(m);
344                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
345                 return (ENXIO);
346         }
347         if ((ifp->if_flags & IFF_UP) == 0) {
348                 m_freem(m);
349                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
350                 return (ENETDOWN);
351         }
352
353         BPF_MTAP(ifp, m);
354
355         /*
356          * In case the outgoing interface is not usable,
357          * drop the packet.
358          */
359         sc = ifp->if_softc;
360         oifp = sc->oifp;
361         if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
362             (oifp->if_flags & IFF_UP) == 0) {
363                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
364                 m_freem(m);
365                 return (0);
366         }
367
368 #ifdef ALTQ
369         len = m->m_pkthdr.len;
370         mcast = (m->m_flags & (M_BCAST | M_MCAST)) != 0;
371         int error = 0;
372
373         /* Support ALTQ via the classic if_start() path. */
374         IF_LOCK(&ifp->if_snd);
375         if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
376                 ALTQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
377                 if (error)
378                         if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
379                 IF_UNLOCK(&ifp->if_snd);
380                 if (!error) {
381                         if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
382                         if (mcast)
383                                 if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
384                         epair_start(ifp);
385                 }
386                 return (error);
387         }
388         IF_UNLOCK(&ifp->if_snd);
389 #endif
390
391         epair_menq(m, oifp->if_softc);
392         return (0);
393 }
394
395 static int
396 epair_media_change(struct ifnet *ifp __unused)
397 {
398
399         /* Do nothing. */
400         return (0);
401 }
402
403 static void
404 epair_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr)
405 {
406
407         imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
408         imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX;
409 }
410
411 static int
412 epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
413 {
414         struct epair_softc *sc;
415         struct ifreq *ifr;
416         int error;
417
418         ifr = (struct ifreq *)data;
419         switch (cmd) {
420         case SIOCSIFFLAGS:
421         case SIOCADDMULTI:
422         case SIOCDELMULTI:
423                 error = 0;
424                 break;
425
426         case SIOCSIFMEDIA:
427         case SIOCGIFMEDIA:
428                 sc = ifp->if_softc;
429                 error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
430                 break;
431
432         case SIOCSIFMTU:
433                 /* We basically allow all kinds of MTUs. */
434                 ifp->if_mtu = ifr->ifr_mtu;
435                 error = 0;
436                 break;
437
438         default:
439                 /* Let the common ethernet handler process this. */
440                 error = ether_ioctl(ifp, cmd, data);
441                 break;
442         }
443
444         return (error);
445 }
446
447 static void
448 epair_init(void *dummy __unused)
449 {
450 }
451
452 /*
453  * Interface cloning functions.
454  * We use our private ones so that we can create/destroy our secondary
455  * device along with the primary one.
456  */
457 static int
458 epair_clone_match(struct if_clone *ifc, const char *name)
459 {
460         const char *cp;
461
462         /*
463          * Our base name is epair.
464          * Our interfaces will be named epair<n>[ab].
465          * So accept anything of the following list:
466          * - epair
467          * - epair<n>
468          * but not the epair<n>[ab] versions.
469          */
470         if (strncmp(epairname, name, sizeof(epairname)-1) != 0)
471                 return (0);
472
473         for (cp = name + sizeof(epairname) - 1; *cp != '\0'; cp++) {
474                 if (*cp < '0' || *cp > '9')
475                         return (0);
476         }
477
478         return (1);
479 }
480
481 static void
482 epair_clone_add(struct if_clone *ifc, struct epair_softc *scb)
483 {
484         struct ifnet *ifp;
485         uint8_t eaddr[ETHER_ADDR_LEN];  /* 00:00:00:00:00:00 */
486
487         ifp = scb->ifp;
488         /* Copy epairNa etheraddr and change the last byte. */
489         memcpy(eaddr, scb->oifp->if_hw_addr, ETHER_ADDR_LEN);
490         eaddr[5] = 0x0b;
491         ether_ifattach(ifp, eaddr);
492
493         if_clone_addif(ifc, ifp);
494 }
495
496 static int
497 epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
498 {
499         struct epair_softc *sca, *scb;
500         struct ifnet *ifp;
501         char *dp;
502         int error, unit, wildcard;
503         uint64_t hostid;
504         uint32_t key[3];
505         uint32_t hash;
506         uint8_t eaddr[ETHER_ADDR_LEN];  /* 00:00:00:00:00:00 */
507
508         /* Try to see if a special unit was requested. */
509         error = ifc_name2unit(name, &unit);
510         if (error != 0)
511                 return (error);
512         wildcard = (unit < 0);
513
514         error = ifc_alloc_unit(ifc, &unit);
515         if (error != 0)
516                 return (error);
517
518         /*
519          * If no unit had been given, we need to adjust the ifName.
520          * Also make sure there is space for our extra [ab] suffix.
521          */
522         for (dp = name; *dp != '\0'; dp++);
523         if (wildcard) {
524                 error = snprintf(dp, len - (dp - name), "%d", unit);
525                 if (error > len - (dp - name) - 1) {
526                         /* ifName too long. */
527                         ifc_free_unit(ifc, unit);
528                         return (ENOSPC);
529                 }
530                 dp += error;
531         }
532         if (len - (dp - name) - 1 < 1) {
533                 /* No space left for our [ab] suffix. */
534                 ifc_free_unit(ifc, unit);
535                 return (ENOSPC);
536         }
537         *dp = 'b';
538         /* Must not change dp so we can replace 'a' by 'b' later. */
539         *(dp+1) = '\0';
540
541         /* Check if 'a' and 'b' interfaces already exist. */ 
542         if (ifunit(name) != NULL)
543                 return (EEXIST);
544         *dp = 'a';
545         if (ifunit(name) != NULL)
546                 return (EEXIST);
547
548         /* Allocate memory for both [ab] interfaces */
549         sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
550         sca->ifp = if_alloc(IFT_ETHER);
551         sca->num_queues = epair_tasks.tasks;
552         if (sca->ifp == NULL) {
553                 free(sca, M_EPAIR);
554                 ifc_free_unit(ifc, unit);
555                 return (ENOSPC);
556         }
557         sca->queues = mallocarray(sca->num_queues, sizeof(struct epair_queue),
558             M_EPAIR, M_WAITOK);
559         for (int i = 0; i < sca->num_queues; i++) {
560                 struct epair_queue *q = &sca->queues[i];
561                 q->id = i;
562                 q->state = EPAIR_QUEUE_IDLE;
563                 mtx_init(&q->mtx, "epaiq", NULL, MTX_DEF | MTX_NEW);
564                 mbufq_init(&q->q, RXRSIZE);
565                 q->sc = sca;
566                 NET_TASK_INIT(&q->tx_task, 0, epair_tx_start_deferred, q);
567         }
568
569         scb = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
570         scb->ifp = if_alloc(IFT_ETHER);
571         scb->num_queues = epair_tasks.tasks;
572         if (scb->ifp == NULL) {
573                 free(scb, M_EPAIR);
574                 if_free(sca->ifp);
575                 free(sca, M_EPAIR);
576                 ifc_free_unit(ifc, unit);
577                 return (ENOSPC);
578         }
579         scb->queues = mallocarray(scb->num_queues, sizeof(struct epair_queue),
580             M_EPAIR, M_WAITOK);
581         for (int i = 0; i < scb->num_queues; i++) {
582                 struct epair_queue *q = &scb->queues[i];
583                 q->id = i;
584                 q->state = EPAIR_QUEUE_IDLE;
585                 mtx_init(&q->mtx, "epaiq", NULL, MTX_DEF | MTX_NEW);
586                 mbufq_init(&q->q, RXRSIZE);
587                 q->sc = scb;
588                 NET_TASK_INIT(&q->tx_task, 0, epair_tx_start_deferred, q);
589         }
590
591         /*
592          * Cross-reference the interfaces so we will be able to free both.
593          */
594         sca->oifp = scb->ifp;
595         scb->oifp = sca->ifp;
596
597         EPAIR_LOCK();
598 #ifdef SMP
599         /* Get an approximate distribution. */
600         hash = next_index % mp_ncpus;
601 #else
602         hash = 0;
603 #endif
604         EPAIR_UNLOCK();
605
606         /* Initialise pseudo media types. */
607         ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status);
608         ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL);
609         ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T);
610         ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status);
611         ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL);
612         ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T);
613
614         /* Finish initialization of interface <n>a. */
615         ifp = sca->ifp;
616         ifp->if_softc = sca;
617         strlcpy(ifp->if_xname, name, IFNAMSIZ);
618         ifp->if_dname = epairname;
619         ifp->if_dunit = unit;
620         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
621         ifp->if_flags |= IFF_KNOWSEPOCH;
622         ifp->if_capabilities = IFCAP_VLAN_MTU;
623         ifp->if_capenable = IFCAP_VLAN_MTU;
624         ifp->if_start = epair_start;
625         ifp->if_ioctl = epair_ioctl;
626         ifp->if_init  = epair_init;
627         if_setsendqlen(ifp, ifqmaxlen);
628         if_setsendqready(ifp);
629
630         /*
631          * Calculate the etheraddr hashing the hostid and the
632          * interface index. The result would be hopefully unique.
633          * Note that the "a" component of an epair instance may get moved
634          * to a different VNET after creation. In that case its index
635          * will be freed and the index can get reused by new epair instance.
636          * Make sure we do not create same etheraddr again.
637          */
638         getcredhostid(curthread->td_ucred, (unsigned long *)&hostid);
639         if (hostid == 0) 
640                 arc4rand(&hostid, sizeof(hostid), 0);
641
642         EPAIR_LOCK();
643         if (ifp->if_index > next_index)
644                 next_index = ifp->if_index;
645         else
646                 next_index++;
647
648         key[0] = (uint32_t)next_index;
649         EPAIR_UNLOCK();
650         key[1] = (uint32_t)(hostid & 0xffffffff);
651         key[2] = (uint32_t)((hostid >> 32) & 0xfffffffff);
652         hash = jenkins_hash32(key, 3, 0);
653
654         eaddr[0] = 0x02;
655         memcpy(&eaddr[1], &hash, 4);
656         eaddr[5] = 0x0a;
657         ether_ifattach(ifp, eaddr);
658         ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */
659         ifp->if_transmit = epair_transmit;
660
661         /* Swap the name and finish initialization of interface <n>b. */
662         *dp = 'b';
663
664         ifp = scb->ifp;
665         ifp->if_softc = scb;
666         strlcpy(ifp->if_xname, name, IFNAMSIZ);
667         ifp->if_dname = epairname;
668         ifp->if_dunit = unit;
669         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
670         ifp->if_flags |= IFF_KNOWSEPOCH;
671         ifp->if_capabilities = IFCAP_VLAN_MTU;
672         ifp->if_capenable = IFCAP_VLAN_MTU;
673         ifp->if_start = epair_start;
674         ifp->if_ioctl = epair_ioctl;
675         ifp->if_init  = epair_init;
676         if_setsendqlen(ifp, ifqmaxlen);
677         if_setsendqready(ifp);
678         /* We need to play some tricks here for the second interface. */
679         strlcpy(name, epairname, len);
680
681         /* Correctly set the name for the cloner list. */
682         strlcpy(name, scb->ifp->if_xname, len);
683         epair_clone_add(ifc, scb);
684
685         ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */
686         ifp->if_transmit = epair_transmit;
687
688         /*
689          * Restore name to <n>a as the ifp for this will go into the
690          * cloner list for the initial call.
691          */
692         strlcpy(name, sca->ifp->if_xname, len);
693
694         /* Tell the world, that we are ready to rock. */
695         sca->ifp->if_drv_flags |= IFF_DRV_RUNNING;
696         if_link_state_change(sca->ifp, LINK_STATE_UP);
697         scb->ifp->if_drv_flags |= IFF_DRV_RUNNING;
698         if_link_state_change(scb->ifp, LINK_STATE_UP);
699
700         return (0);
701 }
702
703 static void
704 epair_drain_rings(struct epair_softc *sc)
705 {
706         for (int i = 0; i < sc->num_queues; i++) {
707                 struct epair_queue *q;
708                 struct mbuf *m, *n;
709
710                 q = &sc->queues[i];
711                 mtx_lock(&q->mtx);
712                 m = mbufq_flush(&q->q);
713                 mtx_unlock(&q->mtx);
714
715                 for (; m != NULL; m = n) {
716                         n = m->m_nextpkt;
717                         m_freem(m);
718                 }
719         }
720 }
721
722 static int
723 epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
724 {
725         struct ifnet *oifp;
726         struct epair_softc *sca, *scb;
727         int unit, error;
728
729         /*
730          * In case we called into if_clone_destroyif() ourselves
731          * again to remove the second interface, the softc will be
732          * NULL. In that case so not do anything but return success.
733          */
734         if (ifp->if_softc == NULL)
735                 return (0);
736
737         unit = ifp->if_dunit;
738         sca = ifp->if_softc;
739         oifp = sca->oifp;
740         scb = oifp->if_softc;
741
742         /* Frist get the interfaces down and detached. */
743         if_link_state_change(ifp, LINK_STATE_DOWN);
744         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
745         if_link_state_change(oifp, LINK_STATE_DOWN);
746         oifp->if_drv_flags &= ~IFF_DRV_RUNNING;
747
748         ether_ifdetach(ifp);
749         ether_ifdetach(oifp);
750
751         /* Third free any queued packets and all the resources. */
752         CURVNET_SET_QUIET(oifp->if_vnet);
753         epair_drain_rings(scb);
754         oifp->if_softc = NULL;
755         error = if_clone_destroyif(ifc, oifp);
756         if (error)
757                 panic("%s: if_clone_destroyif() for our 2nd iface failed: %d",
758                     __func__, error);
759         if_free(oifp);
760         ifmedia_removeall(&scb->media);
761         for (int i = 0; i < scb->num_queues; i++) {
762                 struct epair_queue *q = &scb->queues[i];
763                 mtx_destroy(&q->mtx);
764         }
765         free(scb->queues, M_EPAIR);
766         free(scb, M_EPAIR);
767         CURVNET_RESTORE();
768
769         epair_drain_rings(sca);
770         if_free(ifp);
771         ifmedia_removeall(&sca->media);
772         for (int i = 0; i < sca->num_queues; i++) {
773                 struct epair_queue *q = &sca->queues[i];
774                 mtx_destroy(&q->mtx);
775         }
776         free(sca->queues, M_EPAIR);
777         free(sca, M_EPAIR);
778
779         /* Last free the cloner unit. */
780         ifc_free_unit(ifc, unit);
781
782         return (0);
783 }
784
785 static void
786 vnet_epair_init(const void *unused __unused)
787 {
788
789         V_epair_cloner = if_clone_advanced(epairname, 0,
790             epair_clone_match, epair_clone_create, epair_clone_destroy);
791 }
792 VNET_SYSINIT(vnet_epair_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
793     vnet_epair_init, NULL);
794
795 static void
796 vnet_epair_uninit(const void *unused __unused)
797 {
798
799         if_clone_detach(V_epair_cloner);
800 }
801 VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
802     vnet_epair_uninit, NULL);
803
804 static int
805 epair_mod_init()
806 {
807         char name[32];
808         epair_tasks.tasks = 0;
809
810 #ifdef RSS
811         int cpu;
812
813         CPU_FOREACH(cpu) {
814                 cpuset_t cpu_mask;
815
816                 /* Pin to this CPU so we get appropriate NUMA allocations. */
817                 thread_lock(curthread);
818                 sched_bind(curthread, cpu);
819                 thread_unlock(curthread);
820
821                 snprintf(name, sizeof(name), "epair_task_%d", cpu);
822
823                 epair_tasks.tq[cpu] = taskqueue_create(name, M_WAITOK,
824                     taskqueue_thread_enqueue,
825                     &epair_tasks.tq[cpu]);
826                 CPU_SETOF(cpu, &cpu_mask);
827                 taskqueue_start_threads_cpuset(&epair_tasks.tq[cpu], 1, PI_NET,
828                     &cpu_mask, "%s", name);
829
830                 epair_tasks.tasks++;
831         }
832         thread_lock(curthread);
833         sched_unbind(curthread);
834         thread_unlock(curthread);
835 #else
836         snprintf(name, sizeof(name), "epair_task");
837
838         epair_tasks.tq[0] = taskqueue_create(name, M_WAITOK,
839             taskqueue_thread_enqueue,
840             &epair_tasks.tq[0]);
841         taskqueue_start_threads(&epair_tasks.tq[0], 1, PI_NET, "%s", name);
842
843         epair_tasks.tasks = 1;
844 #endif
845
846         return (0);
847 }
848
849 static void
850 epair_mod_cleanup()
851 {
852
853         for (int i = 0; i < epair_tasks.tasks; i++) {
854                 taskqueue_drain_all(epair_tasks.tq[i]);
855                 taskqueue_free(epair_tasks.tq[i]);
856         }
857 }
858
859 static int
860 epair_modevent(module_t mod, int type, void *data)
861 {
862         int ret;
863
864         switch (type) {
865         case MOD_LOAD:
866                 EPAIR_LOCK_INIT();
867                 ret = epair_mod_init();
868                 if (ret != 0)
869                         return (ret);
870                 if (bootverbose)
871                         printf("%s: %s initialized.\n", __func__, epairname);
872                 break;
873         case MOD_UNLOAD:
874                 epair_mod_cleanup();
875                 EPAIR_LOCK_DESTROY();
876                 if (bootverbose)
877                         printf("%s: %s unloaded.\n", __func__, epairname);
878                 break;
879         default:
880                 return (EOPNOTSUPP);
881         }
882         return (0);
883 }
884
885 static moduledata_t epair_mod = {
886         "if_epair",
887         epair_modevent,
888         0
889 };
890
891 DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
892 MODULE_VERSION(if_epair, 3);