]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_epair.c
ifnet_byindex() actually requires network epoch
[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 <sys/param.h>
44 #include <sys/hash.h>
45 #include <sys/jail.h>
46 #include <sys/kernel.h>
47 #include <sys/libkern.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/module.h>
51 #include <sys/proc.h>
52 #include <sys/queue.h>
53 #include <sys/smp.h>
54 #include <sys/socket.h>
55 #include <sys/sockio.h>
56 #include <sys/sysctl.h>
57 #include <sys/types.h>
58 #include <sys/buf_ring.h>
59 #include <sys/bus.h>
60 #include <sys/interrupt.h>
61
62 #include <net/bpf.h>
63 #include <net/ethernet.h>
64 #include <net/if.h>
65 #include <net/if_var.h>
66 #include <net/if_clone.h>
67 #include <net/if_media.h>
68 #include <net/if_var.h>
69 #include <net/if_types.h>
70 #include <net/netisr.h>
71 #include <net/vnet.h>
72
73 static int epair_clone_match(struct if_clone *, const char *);
74 static int epair_clone_create(struct if_clone *, char *, size_t, caddr_t);
75 static int epair_clone_destroy(struct if_clone *, struct ifnet *);
76
77 static const char epairname[] = "epair";
78 #define RXRSIZE 4096    /* Probably overkill by 4-8x. */
79
80 static MALLOC_DEFINE(M_EPAIR, epairname,
81     "Pair of virtual cross-over connected Ethernet-like interfaces");
82
83 VNET_DEFINE_STATIC(struct if_clone *, epair_cloner);
84 #define V_epair_cloner  VNET(epair_cloner)
85
86 static unsigned int next_index = 0;
87 #define EPAIR_LOCK_INIT()               mtx_init(&epair_n_index_mtx, "epairidx", \
88                                             NULL, MTX_DEF)
89 #define EPAIR_LOCK_DESTROY()            mtx_destroy(&epair_n_index_mtx)
90 #define EPAIR_LOCK()                    mtx_lock(&epair_n_index_mtx)
91 #define EPAIR_UNLOCK()                  mtx_unlock(&epair_n_index_mtx)
92
93 static void                             *swi_cookie[MAXCPU];    /* swi(9). */
94 static STAILQ_HEAD(, epair_softc)       swi_sc[MAXCPU];
95
96 static struct mtx epair_n_index_mtx;
97 struct epair_softc {
98         struct ifnet    *ifp;           /* This ifp. */
99         struct ifnet    *oifp;          /* other ifp of pair. */
100         void            *swi_cookie;    /* swi(9). */
101         struct buf_ring *rxring[2];
102         volatile int    ridx;           /* 0 || 1 */
103         struct ifmedia  media;          /* Media config (fake). */
104         uint32_t        cpuidx;
105         STAILQ_ENTRY(epair_softc) entry;
106 };
107
108 static void
109 epair_clear_mbuf(struct mbuf *m)
110 {
111         /* Remove any CSUM_SND_TAG as ether_input will barf. */
112         if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) {
113                 m_snd_tag_rele(m->m_pkthdr.snd_tag);
114                 m->m_pkthdr.snd_tag = NULL;
115                 m->m_pkthdr.csum_flags &= ~CSUM_SND_TAG;
116         }
117
118         m_tag_delete_nonpersistent(m);
119 }
120
121 static void
122 epair_if_input(struct epair_softc *sc, int ridx)
123 {
124         struct epoch_tracker et;
125         struct ifnet *ifp;
126         struct mbuf *m;
127
128         ifp = sc->ifp;
129         NET_EPOCH_ENTER(et);
130         do {
131                 m = buf_ring_dequeue_sc(sc->rxring[ridx]);
132                 if (m == NULL)
133                         break;
134
135                 MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
136                 (*ifp->if_input)(ifp, m);
137
138         } while (1);
139         NET_EPOCH_EXIT(et);
140 }
141
142 static void
143 epair_sintr(struct epair_softc *sc)
144 {
145         int ridx, nidx;
146
147         if_ref(sc->ifp);
148         do {
149                 ridx = sc->ridx;
150                 nidx = (ridx == 0) ? 1 : 0;
151         } while (!atomic_cmpset_int(&sc->ridx, ridx, nidx));
152         epair_if_input(sc, ridx);
153
154         if_rele(sc->ifp);
155 }
156
157 static void
158 epair_intr(void *arg)
159 {
160         struct epair_softc *sc;
161         uint32_t cpuidx;
162
163         cpuidx = (uintptr_t)arg;
164         /* If this is a problem, this is a read-mostly situation. */
165         EPAIR_LOCK();
166         STAILQ_FOREACH(sc, &swi_sc[cpuidx], entry) {
167                 /* Do this lockless. */
168                 if (buf_ring_empty(sc->rxring[sc->ridx]))
169                         continue;
170                 epair_sintr(sc);
171         }
172         EPAIR_UNLOCK();
173
174         return;
175 }
176
177 static int
178 epair_menq(struct mbuf *m, struct epair_softc *osc)
179 {
180         struct ifnet *ifp, *oifp;
181         int len, ret;
182         int ridx;
183         short mflags;
184         bool was_empty;
185
186         /*
187          * I know this looks weird. We pass the "other sc" as we need that one
188          * and can get both ifps from it as well.
189          */
190         oifp = osc->ifp;
191         ifp = osc->oifp;
192
193         M_ASSERTPKTHDR(m);
194         epair_clear_mbuf(m);
195         if_setrcvif(m, oifp);
196         M_SETFIB(m, oifp->if_fib);
197
198         /* Save values as once the mbuf is queued, it's not ours anymore. */
199         len = m->m_pkthdr.len;
200         mflags = m->m_flags;
201
202         MPASS(m->m_nextpkt == NULL);
203         MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
204
205         ridx = atomic_load_int(&osc->ridx);
206         was_empty = buf_ring_empty(osc->rxring[ridx]);
207         ret = buf_ring_enqueue(osc->rxring[ridx], m);
208         if (ret != 0) {
209                 /* Ring is full. */
210                 m_freem(m);
211                 return (0);
212         }
213
214         if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
215         /*
216          * IFQ_HANDOFF_ADJ/ip_handoff() update statistics,
217          * but as we bypass all this we have to duplicate
218          * the logic another time.
219          */
220         if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
221         if (mflags & (M_BCAST|M_MCAST))
222                 if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
223         /* Someone else received the packet. */
224         if_inc_counter(oifp, IFCOUNTER_IPACKETS, 1);
225
226         /* Kick the interrupt handler for the first packet. */
227         if (was_empty && osc->swi_cookie != NULL)
228                 swi_sched(osc->swi_cookie, 0);
229
230         return (0);
231 }
232
233 static void
234 epair_start(struct ifnet *ifp)
235 {
236         struct mbuf *m;
237         struct epair_softc *sc;
238         struct ifnet *oifp;
239
240         /*
241          * We get packets here from ether_output via if_handoff()
242          * and need to put them into the input queue of the oifp
243          * and will put the packet into the receive-queue (rxq) of the
244          * other interface (oifp) of our pair.
245          */
246         sc = ifp->if_softc;
247         oifp = sc->oifp;
248         sc = oifp->if_softc;
249         for (;;) {
250                 IFQ_DEQUEUE(&ifp->if_snd, m);
251                 if (m == NULL)
252                         break;
253                 M_ASSERTPKTHDR(m);
254                 BPF_MTAP(ifp, m);
255
256                 /* In case either interface is not usable drop the packet. */
257                 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
258                     (ifp->if_flags & IFF_UP) == 0 ||
259                     (oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
260                     (oifp->if_flags & IFF_UP) == 0) {
261                         m_freem(m);
262                         continue;
263                 }
264
265                 (void) epair_menq(m, sc);
266         }
267 }
268
269 static int
270 epair_transmit(struct ifnet *ifp, struct mbuf *m)
271 {
272         struct epair_softc *sc;
273         struct ifnet *oifp;
274         int error;
275 #ifdef ALTQ
276         int len;
277         short mflags;
278 #endif
279
280         if (m == NULL)
281                 return (0);
282         M_ASSERTPKTHDR(m);
283
284         /*
285          * We are not going to use the interface en/dequeue mechanism
286          * on the TX side. We are called from ether_output_frame()
287          * and will put the packet into the receive-queue (rxq) of the
288          * other interface (oifp) of our pair.
289          */
290         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
291                 m_freem(m);
292                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
293                 return (ENXIO);
294         }
295         if ((ifp->if_flags & IFF_UP) == 0) {
296                 m_freem(m);
297                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
298                 return (ENETDOWN);
299         }
300
301         BPF_MTAP(ifp, m);
302
303         /*
304          * In case the outgoing interface is not usable,
305          * drop the packet.
306          */
307         sc = ifp->if_softc;
308         oifp = sc->oifp;
309         if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
310             (oifp->if_flags & IFF_UP) == 0) {
311                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
312                 m_freem(m);
313                 return (0);
314         }
315
316 #ifdef ALTQ
317         len = m->m_pkthdr.len;
318         mflags = m->m_flags;
319
320         /* Support ALTQ via the classic if_start() path. */
321         IF_LOCK(&ifp->if_snd);
322         if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
323                 ALTQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
324                 if (error)
325                         if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
326                 IF_UNLOCK(&ifp->if_snd);
327                 if (!error) {
328                         if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
329                         if (mflags & (M_BCAST|M_MCAST))
330                                 if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
331                         epair_start(ifp);
332                 }
333                 return (error);
334         }
335         IF_UNLOCK(&ifp->if_snd);
336 #endif
337
338         error = epair_menq(m, oifp->if_softc);
339         return (error);
340 }
341
342 static int
343 epair_media_change(struct ifnet *ifp __unused)
344 {
345
346         /* Do nothing. */
347         return (0);
348 }
349
350 static void
351 epair_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr)
352 {
353
354         imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
355         imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX;
356 }
357
358 static int
359 epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
360 {
361         struct epair_softc *sc;
362         struct ifreq *ifr;
363         int error;
364
365         ifr = (struct ifreq *)data;
366         switch (cmd) {
367         case SIOCSIFFLAGS:
368         case SIOCADDMULTI:
369         case SIOCDELMULTI:
370                 error = 0;
371                 break;
372
373         case SIOCSIFMEDIA:
374         case SIOCGIFMEDIA:
375                 sc = ifp->if_softc;
376                 error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
377                 break;
378
379         case SIOCSIFMTU:
380                 /* We basically allow all kinds of MTUs. */
381                 ifp->if_mtu = ifr->ifr_mtu;
382                 error = 0;
383                 break;
384
385         default:
386                 /* Let the common ethernet handler process this. */
387                 error = ether_ioctl(ifp, cmd, data);
388                 break;
389         }
390
391         return (error);
392 }
393
394 static void
395 epair_init(void *dummy __unused)
396 {
397 }
398
399 /*
400  * Interface cloning functions.
401  * We use our private ones so that we can create/destroy our secondary
402  * device along with the primary one.
403  */
404 static int
405 epair_clone_match(struct if_clone *ifc, const char *name)
406 {
407         const char *cp;
408
409         /*
410          * Our base name is epair.
411          * Our interfaces will be named epair<n>[ab].
412          * So accept anything of the following list:
413          * - epair
414          * - epair<n>
415          * but not the epair<n>[ab] versions.
416          */
417         if (strncmp(epairname, name, sizeof(epairname)-1) != 0)
418                 return (0);
419
420         for (cp = name + sizeof(epairname) - 1; *cp != '\0'; cp++) {
421                 if (*cp < '0' || *cp > '9')
422                         return (0);
423         }
424
425         return (1);
426 }
427
428 static void
429 epair_clone_add(struct if_clone *ifc, struct epair_softc *scb)
430 {
431         struct ifnet *ifp;
432         uint8_t eaddr[ETHER_ADDR_LEN];  /* 00:00:00:00:00:00 */
433
434         ifp = scb->ifp;
435         /* Copy epairNa etheraddr and change the last byte. */
436         memcpy(eaddr, scb->oifp->if_hw_addr, ETHER_ADDR_LEN);
437         eaddr[5] = 0x0b;
438         ether_ifattach(ifp, eaddr);
439
440         if_clone_addif(ifc, ifp);
441 }
442
443 static int
444 epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
445 {
446         struct epair_softc *sca, *scb;
447         struct ifnet *ifp;
448         char *dp;
449         int error, unit, wildcard;
450         uint64_t hostid;
451         uint32_t key[3];
452         uint32_t hash;
453         uint8_t eaddr[ETHER_ADDR_LEN];  /* 00:00:00:00:00:00 */
454
455         /* Try to see if a special unit was requested. */
456         error = ifc_name2unit(name, &unit);
457         if (error != 0)
458                 return (error);
459         wildcard = (unit < 0);
460
461         error = ifc_alloc_unit(ifc, &unit);
462         if (error != 0)
463                 return (error);
464
465         /*
466          * If no unit had been given, we need to adjust the ifName.
467          * Also make sure there is space for our extra [ab] suffix.
468          */
469         for (dp = name; *dp != '\0'; dp++);
470         if (wildcard) {
471                 error = snprintf(dp, len - (dp - name), "%d", unit);
472                 if (error > len - (dp - name) - 1) {
473                         /* ifName too long. */
474                         ifc_free_unit(ifc, unit);
475                         return (ENOSPC);
476                 }
477                 dp += error;
478         }
479         if (len - (dp - name) - 1 < 1) {
480                 /* No space left for our [ab] suffix. */
481                 ifc_free_unit(ifc, unit);
482                 return (ENOSPC);
483         }
484         *dp = 'b';
485         /* Must not change dp so we can replace 'a' by 'b' later. */
486         *(dp+1) = '\0';
487
488         /* Check if 'a' and 'b' interfaces already exist. */ 
489         if (ifunit(name) != NULL)
490                 return (EEXIST);
491         *dp = 'a';
492         if (ifunit(name) != NULL)
493                 return (EEXIST);
494
495         /* Allocate memory for both [ab] interfaces */
496         sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
497         sca->ifp = if_alloc(IFT_ETHER);
498         if (sca->ifp == NULL) {
499                 free(sca, M_EPAIR);
500                 ifc_free_unit(ifc, unit);
501                 return (ENOSPC);
502         }
503         sca->rxring[0] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK,NULL);
504         sca->rxring[1] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK, NULL);
505
506         scb = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
507         scb->ifp = if_alloc(IFT_ETHER);
508         if (scb->ifp == NULL) {
509                 free(scb, M_EPAIR);
510                 if_free(sca->ifp);
511                 free(sca, M_EPAIR);
512                 ifc_free_unit(ifc, unit);
513                 return (ENOSPC);
514         }
515         scb->rxring[0] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK, NULL);
516         scb->rxring[1] = buf_ring_alloc(RXRSIZE, M_EPAIR, M_WAITOK, NULL);
517
518         /*
519          * Cross-reference the interfaces so we will be able to free both.
520          */
521         sca->oifp = scb->ifp;
522         scb->oifp = sca->ifp;
523
524         EPAIR_LOCK();
525 #ifdef SMP
526         /* Get an approximate distribution. */
527         hash = next_index % mp_ncpus;
528 #else
529         hash = 0;
530 #endif
531         if (swi_cookie[hash] == NULL) {
532                 void *cookie;
533
534                 EPAIR_UNLOCK();
535                 error = swi_add(NULL, epairname,
536                     epair_intr, (void *)(uintptr_t)hash,
537                     SWI_NET, INTR_MPSAFE, &cookie);
538                 if (error) {
539                         buf_ring_free(scb->rxring[0], M_EPAIR);
540                         buf_ring_free(scb->rxring[1], M_EPAIR);
541                         if_free(scb->ifp);
542                         free(scb, M_EPAIR);
543                         buf_ring_free(sca->rxring[0], M_EPAIR);
544                         buf_ring_free(sca->rxring[1], M_EPAIR);
545                         if_free(sca->ifp);
546                         free(sca, M_EPAIR);
547                         ifc_free_unit(ifc, unit);
548                         return (ENOSPC);
549                 }
550                 EPAIR_LOCK();
551                 /* Recheck under lock even though a race is very unlikely. */
552                 if (swi_cookie[hash] == NULL) {
553                         swi_cookie[hash] = cookie;
554                 } else {
555                         EPAIR_UNLOCK();
556                         (void) swi_remove(cookie);
557                         EPAIR_LOCK();
558                 }
559         }
560         sca->cpuidx = hash;
561         STAILQ_INSERT_TAIL(&swi_sc[hash], sca, entry);
562         sca->swi_cookie = swi_cookie[hash];
563         scb->cpuidx = hash;
564         STAILQ_INSERT_TAIL(&swi_sc[hash], scb, entry);
565         scb->swi_cookie = swi_cookie[hash];
566         EPAIR_UNLOCK();
567
568         /* Initialise pseudo media types. */
569         ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status);
570         ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL);
571         ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T);
572         ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status);
573         ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL);
574         ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T);
575
576         /* Finish initialization of interface <n>a. */
577         ifp = sca->ifp;
578         ifp->if_softc = sca;
579         strlcpy(ifp->if_xname, name, IFNAMSIZ);
580         ifp->if_dname = epairname;
581         ifp->if_dunit = unit;
582         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
583         ifp->if_flags |= IFF_KNOWSEPOCH;
584         ifp->if_capabilities = IFCAP_VLAN_MTU;
585         ifp->if_capenable = IFCAP_VLAN_MTU;
586         ifp->if_start = epair_start;
587         ifp->if_ioctl = epair_ioctl;
588         ifp->if_init  = epair_init;
589         if_setsendqlen(ifp, ifqmaxlen);
590         if_setsendqready(ifp);
591
592         /*
593          * Calculate the etheraddr hashing the hostid and the
594          * interface index. The result would be hopefully unique.
595          * Note that the "a" component of an epair instance may get moved
596          * to a different VNET after creation. In that case its index
597          * will be freed and the index can get reused by new epair instance.
598          * Make sure we do not create same etheraddr again.
599          */
600         getcredhostid(curthread->td_ucred, (unsigned long *)&hostid);
601         if (hostid == 0) 
602                 arc4rand(&hostid, sizeof(hostid), 0);
603
604         EPAIR_LOCK();
605         if (ifp->if_index > next_index)
606                 next_index = ifp->if_index;
607         else
608                 next_index++;
609
610         key[0] = (uint32_t)next_index;
611         EPAIR_UNLOCK();
612         key[1] = (uint32_t)(hostid & 0xffffffff);
613         key[2] = (uint32_t)((hostid >> 32) & 0xfffffffff);
614         hash = jenkins_hash32(key, 3, 0);
615
616         eaddr[0] = 0x02;
617         memcpy(&eaddr[1], &hash, 4);
618         eaddr[5] = 0x0a;
619         ether_ifattach(ifp, eaddr);
620         ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */
621         ifp->if_transmit = epair_transmit;
622
623         /* Swap the name and finish initialization of interface <n>b. */
624         *dp = 'b';
625
626         ifp = scb->ifp;
627         ifp->if_softc = scb;
628         strlcpy(ifp->if_xname, name, IFNAMSIZ);
629         ifp->if_dname = epairname;
630         ifp->if_dunit = unit;
631         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
632         ifp->if_flags |= IFF_KNOWSEPOCH;
633         ifp->if_capabilities = IFCAP_VLAN_MTU;
634         ifp->if_capenable = IFCAP_VLAN_MTU;
635         ifp->if_start = epair_start;
636         ifp->if_ioctl = epair_ioctl;
637         ifp->if_init  = epair_init;
638         if_setsendqlen(ifp, ifqmaxlen);
639         if_setsendqready(ifp);
640         /* We need to play some tricks here for the second interface. */
641         strlcpy(name, epairname, len);
642
643         /* Correctly set the name for the cloner list. */
644         strlcpy(name, scb->ifp->if_xname, len);
645         epair_clone_add(ifc, scb);
646
647         ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */
648         ifp->if_transmit = epair_transmit;
649
650         /*
651          * Restore name to <n>a as the ifp for this will go into the
652          * cloner list for the initial call.
653          */
654         strlcpy(name, sca->ifp->if_xname, len);
655
656         /* Tell the world, that we are ready to rock. */
657         sca->ifp->if_drv_flags |= IFF_DRV_RUNNING;
658         if_link_state_change(sca->ifp, LINK_STATE_UP);
659         scb->ifp->if_drv_flags |= IFF_DRV_RUNNING;
660         if_link_state_change(scb->ifp, LINK_STATE_UP);
661
662         return (0);
663 }
664
665 static void
666 epair_drain_rings(struct epair_softc *sc)
667 {
668         int ridx;
669         struct mbuf *m;
670
671         for (ridx = 0; ridx < 2; ridx++) {
672                 do {
673                         m = buf_ring_dequeue_sc(sc->rxring[ridx]);
674                         if (m == NULL)
675                                 break;
676                         m_freem(m);
677                 } while (1);
678         }
679 }
680
681 static int
682 epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
683 {
684         struct ifnet *oifp;
685         struct epair_softc *sca, *scb;
686         int unit, error;
687
688         /*
689          * In case we called into if_clone_destroyif() ourselves
690          * again to remove the second interface, the softc will be
691          * NULL. In that case so not do anything but return success.
692          */
693         if (ifp->if_softc == NULL)
694                 return (0);
695
696         unit = ifp->if_dunit;
697         sca = ifp->if_softc;
698         oifp = sca->oifp;
699         scb = oifp->if_softc;
700
701         /* Frist get the interfaces down and detached. */
702         if_link_state_change(ifp, LINK_STATE_DOWN);
703         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
704         if_link_state_change(oifp, LINK_STATE_DOWN);
705         oifp->if_drv_flags &= ~IFF_DRV_RUNNING;
706
707         ether_ifdetach(ifp);
708         ether_ifdetach(oifp);
709
710         /* Second stop interrupt handler. */
711         EPAIR_LOCK();
712         STAILQ_REMOVE(&swi_sc[sca->cpuidx], sca, epair_softc, entry);
713         STAILQ_REMOVE(&swi_sc[scb->cpuidx], scb, epair_softc, entry);
714         EPAIR_UNLOCK();
715         sca->swi_cookie = NULL;
716         scb->swi_cookie = NULL;
717
718         /* Third free any queued packets and all the resources. */
719         CURVNET_SET_QUIET(oifp->if_vnet);
720         epair_drain_rings(scb);
721         oifp->if_softc = NULL;
722         error = if_clone_destroyif(ifc, oifp);
723         if (error)
724                 panic("%s: if_clone_destroyif() for our 2nd iface failed: %d",
725                     __func__, error);
726         if_free(oifp);
727         ifmedia_removeall(&scb->media);
728         buf_ring_free(scb->rxring[0], M_EPAIR);
729         buf_ring_free(scb->rxring[1], M_EPAIR);
730         free(scb, M_EPAIR);
731         CURVNET_RESTORE();
732
733         epair_drain_rings(sca);
734         if_free(ifp);
735         ifmedia_removeall(&sca->media);
736         buf_ring_free(sca->rxring[0], M_EPAIR);
737         buf_ring_free(sca->rxring[1], M_EPAIR);
738         free(sca, M_EPAIR);
739
740         /* Last free the cloner unit. */
741         ifc_free_unit(ifc, unit);
742
743         return (0);
744 }
745
746 static void
747 vnet_epair_init(const void *unused __unused)
748 {
749
750         V_epair_cloner = if_clone_advanced(epairname, 0,
751             epair_clone_match, epair_clone_create, epair_clone_destroy);
752 }
753 VNET_SYSINIT(vnet_epair_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
754     vnet_epair_init, NULL);
755
756 static void
757 vnet_epair_uninit(const void *unused __unused)
758 {
759
760         if_clone_detach(V_epair_cloner);
761 }
762 VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
763     vnet_epair_uninit, NULL);
764
765 static int
766 epair_modevent(module_t mod, int type, void *data)
767 {
768         int i;
769
770         switch (type) {
771         case MOD_LOAD:
772                 for (i = 0; i < MAXCPU; i++) {
773                         swi_cookie[i] = NULL;
774                         STAILQ_INIT(&swi_sc[i]);
775                 }
776                 EPAIR_LOCK_INIT();
777                 if (bootverbose)
778                         printf("%s: %s initialized.\n", __func__, epairname);
779                 break;
780         case MOD_UNLOAD:
781                 EPAIR_LOCK();
782                 for (i = 0; i < MAXCPU; i++) {
783                         if (!STAILQ_EMPTY(&swi_sc[i])) {
784                                 printf("%s: swi_sc[%d] active\n", __func__, i);
785                                 EPAIR_UNLOCK();
786                                 return (EBUSY);
787                         }
788                 }
789                 EPAIR_UNLOCK();
790                 for (i = 0; i < MAXCPU; i++)
791                         if (swi_cookie[i] != NULL)
792                                 (void) swi_remove(swi_cookie[i]);
793                 EPAIR_LOCK_DESTROY();
794                 if (bootverbose)
795                         printf("%s: %s unloaded.\n", __func__, epairname);
796                 break;
797         default:
798                 return (EOPNOTSUPP);
799         }
800         return (0);
801 }
802
803 static moduledata_t epair_mod = {
804         "if_epair",
805         epair_modevent,
806         0
807 };
808
809 DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
810 MODULE_VERSION(if_epair, 3);