Created
May 7, 2025 19:23
-
-
Save paigeadelethompson/5410597d92ce5c8be1cbdb48207ba473 to your computer and use it in GitHub Desktop.
VRF experiment for FreeBSD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2023 Your Name | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
*/ | |
/* | |
* VRF (Virtual Routing and Forwarding) network interface for FreeBSD | |
* This interface acts as a layer 3 bridge that auto-assigns interfaces | |
* to specific FIBs (Forwarding Information Bases) they're associated with. | |
*/ | |
#include <sys/param.h> | |
#include <sys/module.h> | |
#include <sys/kernel.h> | |
#include <sys/systm.h> | |
#include <sys/mbuf.h> | |
#include <sys/malloc.h> | |
#include <sys/socket.h> | |
#include <sys/sockio.h> | |
#include <sys/sysctl.h> | |
#include <sys/priv.h> | |
#include <sys/proc.h> | |
#include <sys/lock.h> | |
#include <sys/rmlock.h> | |
#include <sys/sx.h> | |
#include <sys/queue.h> | |
#include <sys/taskqueue.h> | |
#include <net/if.h> | |
#include <net/if_var.h> | |
#include <net/if_types.h> | |
#include <net/if_clone.h> | |
#include <net/if_dl.h> | |
#include <net/vnet.h> | |
#include <net/route.h> | |
#include <net/pfil.h> | |
#include <net/netisr.h> | |
#include <net/ethernet.h> | |
#include <net/bpf.h> | |
#include <net/if_bridgevar.h> | |
#include <netinet/in.h> | |
#include <netinet/in_var.h> | |
#include <netinet/ip.h> | |
#include <netinet/ip_var.h> | |
#ifdef INET6 | |
#include <netinet/ip6.h> | |
#include <netinet6/ip6_var.h> | |
#endif | |
#include "if_vrf.h" | |
MALLOC_DEFINE(M_VRF, "vrf", "Virtual Routing and Forwarding"); | |
/* Maximum number of VRF interfaces */ | |
#define VRF_MAXUNIT 0xFFFF /* Same as ifnet max */ | |
/* Per-interface structure */ | |
struct vrf_softc { | |
struct ifnet *vrf_ifp; /* Base interface */ | |
u_int vrf_fibnum; /* FIB number */ | |
uint32_t vrf_vni; /* VNI value */ | |
struct rmlock vrf_mtx; /* For protecting members */ | |
LIST_HEAD(, vrf_iflist) vrf_iflist; /* List of member interfaces */ | |
eventhandler_tag vrf_detach_cookie; | |
}; | |
/* Member interface structure */ | |
struct vrf_iflist { | |
LIST_ENTRY(vrf_iflist) vrif_next; /* List of member interfaces */ | |
struct ifnet *vrif_ifp; /* Member interface */ | |
u_int32_t vrif_saved_fib; /* Original FIB before joining */ | |
}; | |
/* Interface cloner */ | |
static struct if_clone *vrf_cloner; | |
static const char vrf_name[] = "vrf"; | |
/* Forward declarations */ | |
static int vrf_clone_create(struct if_clone *, int, caddr_t); | |
static void vrf_clone_destroy(struct ifnet *); | |
static int vrf_ioctl(struct ifnet *, u_long, caddr_t); | |
static int vrf_transmit(struct ifnet *, struct mbuf *); | |
static void vrf_qflush(struct ifnet *); | |
static int vrf_output(struct ifnet *, struct mbuf *, | |
const struct sockaddr *, struct route *); | |
static int vrf_attach_interface(struct vrf_softc *, struct ifnet *); | |
static int vrf_detach_interface(struct vrf_softc *, struct ifnet *); | |
static void vrf_interface_detached(void *, struct ifnet *); | |
static int vrf_add_interface(struct ifnet *, struct ifnet *); | |
static int vrf_remove_interface(struct ifnet *, struct ifnet *); | |
static void vrf_init(void *); | |
static int vrf_setfib(struct vrf_softc *, u_int); | |
static u_int vrf_get_fibnum(struct vrf_softc *); | |
static int vrf_setvni(struct vrf_softc *, uint32_t); | |
static uint32_t vrf_get_vni(struct vrf_softc *); | |
static struct vrf_iflist *vrf_find_iflist(struct vrf_softc *, struct ifnet *); | |
static int vrf_flush_interfaces(struct vrf_softc *, int); | |
static int vrf_cmd_handler(struct vrf_softc *, u_long, void *, size_t, int); | |
/* sysctl variables */ | |
SYSCTL_DECL(_net_link); | |
SYSCTL_NODE(_net_link, IFT_VRF, vrf, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | |
"Virtual Routing and Forwarding"); | |
/* | |
* Driver initialization | |
*/ | |
static void | |
vrf_init(void *dummy __unused) | |
{ | |
/* Register if_clone */ | |
vrf_cloner = if_clone_simple(vrf_name, vrf_clone_create, vrf_clone_destroy, | |
0); | |
} | |
SYSINIT(vrf_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vrf_init, NULL); | |
/* | |
* Create a VRF interface | |
*/ | |
static int | |
vrf_clone_create(struct if_clone *ifc, int unit, caddr_t params) | |
{ | |
struct vrf_softc *sc; | |
struct ifnet *ifp; | |
struct vrfparam *vrfp = (struct vrfparam *)params; | |
/* Allocate VRF softc */ | |
sc = malloc(sizeof(struct vrf_softc), M_VRF, M_WAITOK | M_ZERO); | |
rm_init(&sc->vrf_mtx, "vrf_mtx"); | |
LIST_INIT(&sc->vrf_iflist); | |
/* Default VNI is unset */ | |
sc->vrf_vni = VRF_VNI_NONE; | |
/* Default FIB number is the same as the unit number, but caps at rt_numfibs */ | |
sc->vrf_fibnum = min(unit, rt_numfibs - 1); | |
/* Process creation parameters if provided */ | |
if (vrfp != NULL) { | |
if (vrfp->vrfp_with & VRF_PARAM_WITH_VNI && | |
vrfp->vrfp_vni < VRF_VNI_MAX) { | |
sc->vrf_vni = vrfp->vrfp_vni; | |
} | |
if (vrfp->vrfp_with & VRF_PARAM_WITH_FIB && | |
vrfp->vrfp_fib < rt_numfibs) { | |
sc->vrf_fibnum = vrfp->vrfp_fib; | |
} | |
} | |
/* Allocate ifnet structure */ | |
ifp = if_alloc(IFT_VRF); | |
if (ifp == NULL) { | |
rm_destroy(&sc->vrf_mtx); | |
free(sc, M_VRF); | |
return (ENOSPC); | |
} | |
sc->vrf_ifp = ifp; | |
ifp->if_softc = sc; | |
/* Set ifnet fields */ | |
if_initname(ifp, vrf_name, unit); | |
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | |
ifp->if_ioctl = vrf_ioctl; | |
ifp->if_transmit = vrf_transmit; | |
ifp->if_qflush = vrf_qflush; | |
ifp->if_output = vrf_output; | |
ifp->if_hdrlen = 0; | |
ifp->if_capabilities |= IFCAP_LINKSTATE; | |
ifp->if_capenable |= IFCAP_LINKSTATE; | |
/* Attach interface */ | |
if_attach(ifp); | |
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); | |
/* Register event handler for interface deletions */ | |
sc->vrf_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, | |
vrf_interface_detached, sc, EVENTHANDLER_PRI_ANY); | |
return (0); | |
} | |
/* | |
* Destroy a VRF interface | |
*/ | |
static void | |
vrf_clone_destroy(struct ifnet *ifp) | |
{ | |
struct vrf_softc *sc = ifp->if_softc; | |
struct vrf_iflist *vifl, *next; | |
/* Check if interface exists */ | |
if (ifp == NULL || sc == NULL) | |
return; | |
/* Unregister event handler */ | |
EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->vrf_detach_cookie); | |
/* Detach all member interfaces */ | |
LIST_FOREACH_SAFE(vifl, &sc->vrf_iflist, vrif_next, next) { | |
vrf_detach_interface(sc, vifl->vrif_ifp); | |
} | |
/* Detach interface */ | |
bpfdetach(ifp); | |
if_detach(ifp); | |
if_free(ifp); | |
/* Free softc */ | |
rm_destroy(&sc->vrf_mtx); | |
free(sc, M_VRF); | |
} | |
/* | |
* Handle ioctl requests for VRF interfaces | |
*/ | |
static int | |
vrf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | |
{ | |
struct vrf_softc *sc = ifp->if_softc; | |
struct ifreq *ifr = (struct ifreq *)data; | |
struct ifbreq *req = (struct ifbreq *)data; | |
struct ifdrv *ifd = (struct ifdrv *)data; | |
struct ifnet *ifs; | |
int error = 0; | |
switch (cmd) { | |
case SIOCADDMULTI: | |
case SIOCDELMULTI: | |
/* Nothing to do */ | |
break; | |
case SIOCGVRFFIB: | |
/* Get VRF FIB number */ | |
ifr->ifr_fib = vrf_get_fibnum(sc); | |
break; | |
case SIOCGVNETID: | |
/* Get FIB ID for application compatibility */ | |
ifr->ifr_fib = vrf_get_vni(sc); | |
break; | |
case SIOCSVRFFIB: | |
/* Set VRF FIB number */ | |
error = priv_check(curthread, PRIV_NET_SETIFFIB); | |
if (error) | |
break; | |
error = vrf_setfib(sc, ifr->ifr_fib); | |
break; | |
case SIOCSVNETID: | |
/* Set FIB ID for application compatibility */ | |
error = priv_check(curthread, PRIV_NET_SETIFFIB); | |
if (error) | |
break; | |
error = vrf_setvni(sc, ifr->ifr_fib); | |
break; | |
case SIOCSDRVSPEC: | |
case SIOCGDRVSPEC: | |
/* Handle driver-specific ioctls */ | |
error = priv_check(curthread, PRIV_NET_SETIFFIB); | |
if (error) | |
break; | |
if (ifd->ifd_cmd < VRF_CMD_GET_CONFIG || | |
ifd->ifd_len < sizeof(struct vrfcmd)) { | |
error = EINVAL; | |
break; | |
} | |
error = vrf_cmd_handler(sc, ifd->ifd_cmd, ifd->ifd_data, | |
ifd->ifd_len, cmd == SIOCSDRVSPEC); | |
break; | |
case SIOCIFCREATE: | |
case SIOCIFDESTROY: | |
/* Let the cloner handle these */ | |
return (EOPNOTSUPP); | |
case SIOCAIFGROUP: | |
case SIOCDIFGROUP: | |
/* Just pass these along to the underlying interfaces */ | |
break; | |
case SIOCIFGMEMBERS: | |
/* Get list of member interfaces */ | |
break; | |
case SIOCBRDGADD: | |
/* Add an interface to the VRF */ | |
ifs = ifunit(req->ifbr_ifsname); | |
if (ifs == NULL) | |
return (ENOENT); | |
error = vrf_add_interface(ifp, ifs); | |
break; | |
case SIOCBRDGDEL: | |
/* Remove an interface from the VRF */ | |
ifs = ifunit(req->ifbr_ifsname); | |
if (ifs == NULL) | |
return (ENOENT); | |
error = vrf_remove_interface(ifp, ifs); | |
break; | |
case SIOCSIFFLAGS: | |
/* Handle IFF_UP changes */ | |
if (ifp->if_flags & IFF_UP) | |
ifp->if_drv_flags |= IFF_DRV_RUNNING; | |
else | |
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | |
break; | |
default: | |
error = ether_ioctl(ifp, cmd, data); | |
break; | |
} | |
return (error); | |
} | |
/* | |
* Handle VRF-specific commands | |
*/ | |
static int | |
vrf_cmd_handler(struct vrf_softc *sc, u_long cmd, void *data, size_t datalen, int set) | |
{ | |
struct vrfcmd *vrfcmd; | |
struct vrfcfg *vrfcfg; | |
struct vrf_iflist *vifl; | |
struct rm_priotracker tracker; | |
int error = 0; | |
/* Check parameter validity */ | |
if (data == NULL || sc == NULL) | |
return (EINVAL); | |
switch (cmd) { | |
case VRF_CMD_GET_CONFIG: | |
if (!set && datalen >= sizeof(struct vrfcfg)) { | |
vrfcfg = (struct vrfcfg *)data; | |
vrfcfg->vrfc_vni = vrf_get_vni(sc); | |
vrfcfg->vrfc_fib = vrf_get_fibnum(sc); | |
/* Count member interfaces */ | |
vrfcfg->vrfc_ifcnt = 0; | |
rm_rlock(&sc->vrf_mtx, &tracker); | |
LIST_FOREACH(vifl, &sc->vrf_iflist, vrif_next) { | |
vrfcfg->vrfc_ifcnt++; | |
} | |
rm_runlock(&sc->vrf_mtx, &tracker); | |
} else { | |
error = EINVAL; | |
} | |
break; | |
case VRF_CMD_SET_VNI: | |
if (set && datalen >= sizeof(struct vrfcmd)) { | |
vrfcmd = (struct vrfcmd *)data; | |
error = vrf_setvni(sc, vrfcmd->vrfcmd_vni); | |
} else { | |
error = EINVAL; | |
} | |
break; | |
case VRF_CMD_SET_FIB: | |
if (set && datalen >= sizeof(struct vrfcmd)) { | |
vrfcmd = (struct vrfcmd *)data; | |
error = vrf_setfib(sc, vrfcmd->vrfcmd_fib); | |
} else { | |
error = EINVAL; | |
} | |
break; | |
case VRF_CMD_FLUSH: | |
if (set && datalen >= sizeof(struct vrfcmd)) { | |
vrfcmd = (struct vrfcmd *)data; | |
error = vrf_flush_interfaces(sc, | |
(vrfcmd->vrfcmd_flags & VRF_CMD_FLAG_FLUSH_ALL) != 0); | |
} else { | |
error = EINVAL; | |
} | |
break; | |
default: | |
error = EINVAL; | |
break; | |
} | |
return (error); | |
} | |
/* | |
* Transmit function - we drop packets for a VRF itself | |
*/ | |
static int | |
vrf_transmit(struct ifnet *ifp, struct mbuf *m) | |
{ | |
/* VRF interfaces don't transmit packets directly */ | |
m_freem(m); | |
return (0); | |
} | |
/* | |
* Flush output queue | |
*/ | |
static void | |
vrf_qflush(struct ifnet *ifp) | |
{ | |
/* Nothing to do, we don't buffer packets */ | |
} | |
/* | |
* Output function - we drop packets for a VRF itself | |
*/ | |
static int | |
vrf_output(struct ifnet *ifp, struct mbuf *m, | |
const struct sockaddr *dst, struct route *ro) | |
{ | |
/* VRF interfaces don't transmit packets directly */ | |
m_freem(m); | |
return (ENETDOWN); | |
} | |
/* | |
* Add a member interface to the VRF | |
*/ | |
static int | |
vrf_add_interface(struct ifnet *vrf_ifp, struct ifnet *ifs) | |
{ | |
struct vrf_softc *sc = vrf_ifp->if_softc; | |
int error; | |
/* Don't allow adding a VRF to itself or another VRF */ | |
if (ifs->if_type == IFT_VRF) | |
return (EINVAL); | |
/* Add interface to VRF */ | |
error = vrf_attach_interface(sc, ifs); | |
return (error); | |
} | |
/* | |
* Remove a member interface from the VRF | |
*/ | |
static int | |
vrf_remove_interface(struct ifnet *vrf_ifp, struct ifnet *ifs) | |
{ | |
struct vrf_softc *sc = vrf_ifp->if_softc; | |
int error; | |
/* Remove interface from VRF */ | |
error = vrf_detach_interface(sc, ifs); | |
return (error); | |
} | |
/* | |
* Attach a member interface to a VRF | |
*/ | |
static int | |
vrf_attach_interface(struct vrf_softc *sc, struct ifnet *ifs) | |
{ | |
struct vrf_iflist *vifl; | |
/* Check if already a member */ | |
rm_wlock(&sc->vrf_mtx); | |
if (vrf_find_iflist(sc, ifs) != NULL) { | |
rm_wunlock(&sc->vrf_mtx); | |
return (EEXIST); | |
} | |
/* Allocate and add new member */ | |
vifl = malloc(sizeof(struct vrf_iflist), M_VRF, M_NOWAIT | M_ZERO); | |
if (vifl == NULL) { | |
rm_wunlock(&sc->vrf_mtx); | |
return (ENOMEM); | |
} | |
vifl->vrif_ifp = ifs; | |
vifl->vrif_saved_fib = ifs->if_fib; | |
/* Set interface FIB to VRF FIB */ | |
ifs->if_fib = sc->vrf_fibnum; | |
/* Add to list */ | |
LIST_INSERT_HEAD(&sc->vrf_iflist, vifl, vrif_next); | |
rm_wunlock(&sc->vrf_mtx); | |
printf("VRF %s: Added interface %s (FIB %u)\n", | |
sc->vrf_ifp->if_xname, ifs->if_xname, sc->vrf_fibnum); | |
return (0); | |
} | |
/* | |
* Detach a member interface from a VRF | |
*/ | |
static int | |
vrf_detach_interface(struct vrf_softc *sc, struct ifnet *ifs) | |
{ | |
struct vrf_iflist *vifl; | |
/* Find and remove member */ | |
rm_wlock(&sc->vrf_mtx); | |
vifl = vrf_find_iflist(sc, ifs); | |
if (vifl == NULL) { | |
rm_wunlock(&sc->vrf_mtx); | |
return (ENOENT); | |
} | |
/* Restore original FIB */ | |
ifs->if_fib = vifl->vrif_saved_fib; | |
/* Remove from list */ | |
LIST_REMOVE(vifl, vrif_next); | |
rm_wunlock(&sc->vrf_mtx); | |
printf("VRF %s: Removed interface %s (restored FIB %u)\n", | |
sc->vrf_ifp->if_xname, ifs->if_xname, vifl->vrif_saved_fib); | |
free(vifl, M_VRF); | |
return (0); | |
} | |
/* | |
* Remove all interfaces from the VRF | |
*/ | |
static int | |
vrf_flush_interfaces(struct vrf_softc *sc, int all) | |
{ | |
struct vrf_iflist *vifl, *next; | |
int count = 0; | |
rm_wlock(&sc->vrf_mtx); | |
LIST_FOREACH_SAFE(vifl, &sc->vrf_iflist, vrif_next, next) { | |
/* Restore original FIB */ | |
vifl->vrif_ifp->if_fib = vifl->vrif_saved_fib; | |
/* Remove from list */ | |
LIST_REMOVE(vifl, vrif_next); | |
printf("VRF %s: Flushed interface %s (restored FIB %u)\n", | |
sc->vrf_ifp->if_xname, vifl->vrif_ifp->if_xname, | |
vifl->vrif_saved_fib); | |
free(vifl, M_VRF); | |
count++; | |
/* If not flushing all, just remove one interface */ | |
if (!all) | |
break; | |
} | |
rm_wunlock(&sc->vrf_mtx); | |
return (count > 0 ? 0 : ENOENT); | |
} | |
/* | |
* Handle interface detach events | |
*/ | |
static void | |
vrf_interface_detached(void *arg, struct ifnet *ifs) | |
{ | |
struct vrf_softc *sc = arg; | |
struct vrf_iflist *vifl; | |
struct rm_priotracker tracker; | |
/* Check if the detached interface is a member of our VRF */ | |
rm_rlock(&sc->vrf_mtx, &tracker); | |
vifl = vrf_find_iflist(sc, ifs); | |
if (vifl != NULL) { | |
rm_runlock(&sc->vrf_mtx, &tracker); | |
vrf_detach_interface(sc, ifs); | |
} else { | |
rm_runlock(&sc->vrf_mtx, &tracker); | |
} | |
} | |
/* | |
* Set the FIB number for a VRF | |
*/ | |
static int | |
vrf_setfib(struct vrf_softc *sc, u_int fibnum) | |
{ | |
struct vrf_iflist *vifl; | |
struct rm_priotracker tracker; | |
u_int oldfib; | |
/* Check if FIB is valid */ | |
if (fibnum >= rt_numfibs) | |
return (EINVAL); | |
/* Check if FIB is changing */ | |
if (sc->vrf_fibnum == fibnum) | |
return (0); | |
oldfib = sc->vrf_fibnum; | |
/* Update all member interfaces */ | |
rm_rlock(&sc->vrf_mtx, &tracker); | |
sc->vrf_fibnum = fibnum; | |
LIST_FOREACH(vifl, &sc->vrf_iflist, vrif_next) { | |
vifl->vrif_ifp->if_fib = fibnum; | |
} | |
rm_runlock(&sc->vrf_mtx, &tracker); | |
printf("VRF %s: FIB changed from %u to %u\n", | |
sc->vrf_ifp->if_xname, oldfib, fibnum); | |
return (0); | |
} | |
/* | |
* Get the FIB number for a VRF | |
*/ | |
static u_int | |
vrf_get_fibnum(struct vrf_softc *sc) | |
{ | |
return (sc->vrf_fibnum); | |
} | |
/* | |
* Set the VNI for a VRF | |
*/ | |
static int | |
vrf_setvni(struct vrf_softc *sc, uint32_t vni) | |
{ | |
uint32_t oldvni; | |
/* Check if VNI is valid */ | |
if (vni >= VRF_VNI_MAX) | |
return (EINVAL); | |
/* Check if VNI is changing */ | |
if (sc->vrf_vni == vni) | |
return (0); | |
oldvni = sc->vrf_vni; | |
sc->vrf_vni = vni; | |
printf("VRF %s: VNI changed from %u to %u\n", | |
sc->vrf_ifp->if_xname, oldvni, vni); | |
return (0); | |
} | |
/* | |
* Get the VNI for a VRF | |
*/ | |
static uint32_t | |
vrf_get_vni(struct vrf_softc *sc) | |
{ | |
return (sc->vrf_vni); | |
} | |
/* | |
* Find a member interface in a VRF | |
*/ | |
static struct vrf_iflist * | |
vrf_find_iflist(struct vrf_softc *sc, struct ifnet *ifs) | |
{ | |
struct vrf_iflist *vifl; | |
LIST_FOREACH(vifl, &sc->vrf_iflist, vrif_next) { | |
if (vifl->vrif_ifp == ifs) | |
return (vifl); | |
} | |
return (NULL); | |
} | |
/* | |
* Module event handler | |
*/ | |
static int | |
vrf_modevent(module_t mod, int type, void *data) | |
{ | |
int error = 0; | |
switch (type) { | |
case MOD_LOAD: | |
/* Module initialization is handled by SYSINIT */ | |
printf("VRF: Virtual Routing and Forwarding interface loaded\n"); | |
break; | |
case MOD_UNLOAD: | |
/* Check if any instances exist */ | |
if (vrf_cloner != NULL) { | |
if_clone_detach(vrf_cloner); | |
printf("VRF: Virtual Routing and Forwarding interface unloaded\n"); | |
} | |
break; | |
default: | |
error = EOPNOTSUPP; | |
break; | |
} | |
return (error); | |
} | |
/* Module declaration */ | |
static moduledata_t vrf_mod = { | |
"if_vrf", | |
vrf_modevent, | |
0 | |
}; | |
DECLARE_MODULE(if_vrf, vrf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); | |
MODULE_VERSION(if_vrf, 1); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2023 Your Name | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
*/ | |
#ifndef _NET_IF_VRF_H_ | |
#define _NET_IF_VRF_H_ | |
#include <netinet/in.h> | |
#include <sys/ioccom.h> | |
/* Define a unique interface type for VRF */ | |
#define IFT_VRF 0xFA /* Virtual Routing and Forwarding */ | |
/* VRF-specific ioctls */ | |
#define SIOCGVRFFIB _IOR('i', 150, struct ifreq) /* get VRF FIB */ | |
#define SIOCSVRFFIB _IOW('i', 151, struct ifreq) /* set VRF FIB */ | |
#define SIOCGVNETID _IOR('i', 152, struct ifreq) /* get VRF VNI */ | |
#define SIOCSVNETID _IOW('i', 153, struct ifreq) /* set VRF VNI */ | |
#define SIOCIFGMEMBERS _IOWR('i', 154, struct ifdrv) /* get VRF members */ | |
#define SIOCBRDGADD _IOW('i', 155, struct ifbreq) /* add interface */ | |
#define SIOCBRDGDEL _IOW('i', 156, struct ifbreq) /* remove interface */ | |
/* Maximum VNI value (24 bits, matching VXLAN) */ | |
#define VRF_VNI_MAX ((1 << 24) - 1) | |
#define VRF_VNI_NONE VRF_VNI_MAX /* Unset VNI value */ | |
/* VRF specific ioctl commands */ | |
#define VRF_CMD_GET_CONFIG 1 | |
#define VRF_CMD_SET_VNI 2 | |
#define VRF_CMD_SET_FIB 3 | |
#define VRF_CMD_FLUSH 4 | |
/* Structure to pass VRF commands via ioctl */ | |
struct vrfcmd { | |
uint32_t vrfcmd_vni; /* VNI */ | |
uint32_t vrfcmd_fib; /* FIB number */ | |
uint32_t vrfcmd_flags; /* Command flags */ | |
#define VRF_CMD_FLAG_FLUSH_ALL 0x00000001 /* Flush all interfaces */ | |
}; | |
/* VRF configuration data */ | |
struct vrfcfg { | |
uint32_t vrfc_vni; /* VNI */ | |
uint32_t vrfc_fib; /* FIB number */ | |
uint32_t vrfc_ifcnt; /* Number of member interfaces */ | |
}; | |
/* Structure to set up a VRF interface */ | |
struct vrfparam { | |
uint32_t vrfp_vni; /* VNI */ | |
uint32_t vrfp_fib; /* FIB number */ | |
uint32_t vrfp_with; /* Flags indicating which params are valid */ | |
#define VRF_PARAM_WITH_VNI 0x00000001 | |
#define VRF_PARAM_WITH_FIB 0x00000002 | |
}; | |
#ifdef _KERNEL | |
/* Function prototypes for kernel components */ | |
void rt_set_ifscope(struct ifnet *ifp, u_int fibnum); | |
#else /* !_KERNEL */ | |
/* These are only used from userland */ | |
#endif /* _KERNEL */ | |
#endif /* _NET_IF_VRF_H_ */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define SMP 1 | |
#define MAC 1 | |
#define VIMAGE 1 | |
#define EARLY_AP_STARTUP 1 | |
#define CC_CUBIC 1 | |
#define NEW_PCIB 1 | |
#define NETLINK 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment