Date: Thu, 7 May 2009 21:39:40 GMT From: Marko Zec <zec@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 161749 for review Message-ID: <200905072139.n47LdeGN099635@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=161749 Change 161749 by zec@zec_tpx32 on 2009/05/07 21:39:21 Glue in the interim management API and make it compile. Affected files ... .. //depot/projects/vimage-commit2/src/sys/kern/kern_vimage.c#30 edit .. //depot/projects/vimage-commit2/src/sys/net/if.c#54 edit .. //depot/projects/vimage-commit2/src/sys/net/if_var.h#22 edit .. //depot/projects/vimage-commit2/src/sys/sys/sockio.h#3 edit .. //depot/projects/vimage-commit2/src/sys/sys/vimage.h#55 edit Differences ... ==== //depot/projects/vimage-commit2/src/sys/kern/kern_vimage.c#30 (text+ko) ==== @@ -34,16 +34,23 @@ #include "opt_ddb.h" #include <sys/param.h> -#include <sys/types.h> #include <sys/kernel.h> #include <sys/linker.h> +#include <sys/lock.h> #include <sys/malloc.h> -#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sx.h> +#include <sys/refcount.h> #include <sys/vimage.h> #ifdef DDB #include <ddb/ddb.h> #endif +#include <net/if.h> +#include <net/route.h> +#include <net/vnet.h> + #ifndef VIMAGE_GLOBALS MALLOC_DEFINE(M_VIMAGE, "vimage", "vimage resource container"); @@ -56,17 +63,375 @@ static int vnet_mod_constructor(struct vnet_modlink *); static int vnet_mod_destructor(struct vnet_modlink *); +static struct vimage *vimage_by_name(struct vimage *, char *); +static struct vimage *vi_alloc(struct vimage *, char *); + +#define VNET_LIST_LOCK() \ + mtx_lock(&vnet_list_refc_mtx); \ + while (vnet_list_refc != 0) \ + cv_wait(&vnet_list_condvar, &vnet_list_refc_mtx); + +#define VNET_LIST_UNLOCK() \ + mtx_unlock(&vnet_list_refc_mtx); + #ifdef VIMAGE struct vimage_list_head vimage_head; struct vnet_list_head vnet_head; struct vprocg_list_head vprocg_head; + +struct cv vnet_list_condvar; +struct mtx vnet_list_refc_mtx; +int vnet_list_refc = 0; + +static u_int last_vi_id = 0; +static u_int last_vnet_id = 0; +static u_int last_vprocg_id = 0; #else #ifndef VIMAGE_GLOBALS struct vprocg vprocg_0; #endif #endif +/* + * Userspace interfaces. + */ + +static int +vi_child_of(struct vimage *parent, struct vimage *child) +{ + if (child == parent) + return (0); + for (; child; child = child->vi_parent) + if (child == parent) + return (1); + return (0); +} + +/* + * if_reassign_common() should be called by all device specific + * ifnet reassignment routines after the interface is detached from + * current vnet and before the interface gets attached to the target + * vnet. This routine attempts to shrink if_index in current vnet, + * find an unused if_index in target vnet and calls if_grow() if + * necessary, and finally finds an unused if_xname for the target + * vnet. + * + * XXX this routine should hold a lock over if_index and return with + * such a lock held, and the caller should release that lock + * after ifattach completes! + */ void +if_reassign_common(struct ifnet *ifp, struct vnet *new_vnet, const char *dname) +{ + /* do/while construct needed to confine scope of INIT_VNET_NET() */ + do { + INIT_VNET_NET(curvnet); + + IFNET_WLOCK(); + ifnet_setbyindex(ifp->if_index, NULL); + while (V_if_index > 0 && ifnet_byindex(V_if_index) == NULL) + V_if_index--; + IFNET_WUNLOCK(); + } while (0); + + CURVNET_SET_QUIET(new_vnet); + INIT_VNET_NET(new_vnet); + /* + * Try to find an empty slot below if_index. If we fail, take + * the next slot. + */ + IFNET_WLOCK(); + for (ifp->if_index = 1; ifp->if_index <= V_if_index; ifp->if_index++) { + if (ifnet_byindex(ifp->if_index) == NULL) + break; + } + /* Catch if_index overflow. */ + if (ifp->if_index < 1) + panic("vi_if_move: if_index overflow"); + + if (ifp->if_index > V_if_index) + V_if_index = ifp->if_index; + if (V_if_index >= V_if_indexlim) + if_grow(); + ifnet_setbyindex(ifp->if_index, ifp); + IFNET_WUNLOCK(); + + /* Rename the ifnet */ + if (new_vnet == ifp->if_home_vnet) { + /* always restore the original name on return to home vnet */ + snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ifp->if_dname, + ifp->if_dunit); + } else { + int unit = 0; + struct ifnet *iter; + + do { + snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", dname, unit); + TAILQ_FOREACH(iter, &V_ifnet, if_link) + if (strcmp(ifp->if_xname, iter->if_xname) == 0) + break; + unit++; + } while (iter); + } + CURVNET_RESTORE(); +} + +/* + * Move the interface to another vnet. The interface can be specified either + * by ifp argument, or by name contained in vi_req->vi_if_xname if NULL is + * passed as ifp. The interface will be renamed to vi_req->vi_parent_name + * if vi_req->vi_parent_name is not an empty string (uff ugly ugly)... + * Similary, the target vnet can be specified either by vnet argument or + * by name. If vnet name equals to ".." or vi_req is set to NULL the + * interface is moved to the parent vnet. + */ +int +vi_if_move(struct vi_req *vi_req, struct ifnet *ifp, struct vimage *vip) +{ + struct vimage *new_vip; + struct vnet *new_vnet = NULL; + + if (vi_req == NULL || strcmp(vi_req->vi_name, "..") == 0) { + if (IS_DEFAULT_VIMAGE(vip)) + return (ENXIO); + new_vnet = vip->vi_parent->v_net; + } else { + new_vip = vimage_by_name(vip, vi_req->vi_name); + if (new_vip == NULL) + return (ENXIO); + new_vnet = new_vip->v_net; + } + + if (ifp == NULL) + ifp = ifunit(vi_req->vi_if_xname); + if (ifp == NULL) + return (ENXIO); + + /* Abort if driver did not provide a if_reassign() method */ + if (ifp->if_reassign == NULL) + return (ENODEV); + + if (vi_req != NULL) { + struct ifnet *t_ifp; + + CURVNET_SET_QUIET(new_vnet); + t_ifp = ifunit(vi_req->vi_if_xname); + CURVNET_RESTORE(); + if (t_ifp != NULL) + return (EEXIST); + } + + if (vi_req && strlen(vi_req->vi_if_xname) > 0) + ifp->if_reassign(ifp, new_vnet, vi_req->vi_if_xname); + else + ifp->if_reassign(ifp, new_vnet, NULL); + getmicrotime(&ifp->if_lastchange); + + /* Report the new if_xname back to the userland */ + if (vi_req != NULL) + sprintf(vi_req->vi_if_xname, "%s", ifp->if_xname); + + return (0); +} + +static struct vimage * +vimage_by_name(struct vimage *top, char *name) +{ + struct vimage *vip; + char *next_name; + int namelen; + + next_name = strchr(name, '.'); + if (next_name != NULL) { + namelen = next_name - name; + next_name++; + if (namelen == 0) { + if (strlen(next_name) == 0) + return(top); /* '.' == this vimage */ + else + return(NULL); + } + } else + namelen = strlen(name); + if (namelen == 0) + return(NULL); + LIST_FOREACH(vip, &top->vi_child_head, vi_sibling) + if (strlen(vip->vi_name) == namelen && + strncmp(name, vip->vi_name, namelen) == 0) { + if (next_name != NULL) + return(vimage_by_name(vip, next_name)); + else + return(vip); + } + return(NULL); +} + +static void +vimage_relative_name(struct vimage *top, struct vimage *where, + char *buffer, int bufflen) +{ + int used = 1; + + if (where == top) { + sprintf(buffer, "."); + return; + } else + *buffer = 0; + + do { + int namelen = strlen(where->vi_name); + + if (namelen + used + 1 >= bufflen) + panic("buffer overflow"); + + if (used > 1) { + bcopy(buffer, &buffer[namelen + 1], used); + buffer[namelen] = '.'; + used++; + } else + bcopy(buffer, &buffer[namelen], used); + bcopy(where->vi_name, buffer, namelen); + used += namelen; + where = where->vi_parent; + } while (where != top); +} + +static struct vimage * +vimage_get_next(struct vimage *top, struct vimage *where, int recurse) +{ + struct vimage *next; + + if (recurse) { + /* Try to go deeper in the hierarchy */ + next = LIST_FIRST(&where->vi_child_head); + if (next != NULL) + return(next); + } + + do { + /* Try to find next sibling */ + next = LIST_NEXT(where, vi_sibling); + if (!recurse || next != NULL) + return(next); + + /* Nothing left on this level, go one level up */ + where = where->vi_parent; + } while (where != top->vi_parent); + + /* Nothing left to be visited, we are done */ + return(NULL); +} + +int +vi_td_ioctl(u_long cmd, struct vi_req *vi_req, struct thread *td) +{ + int error = 0; + struct vimage *vip = TD_TO_VIMAGE(td); + struct vimage *vip_r = NULL; + +#if 0 + error = priv_check(td, PRIV_ROOT); + if (error) + return (error); +#endif + + vip_r = vimage_by_name(vip, vi_req->vi_name); + if (vip_r == NULL && !(vi_req->vi_req_action & VI_CREATE)) + return (ESRCH); + if (vip_r != NULL && vi_req->vi_req_action & VI_CREATE) + return (EADDRINUSE); + if (vi_req->vi_req_action == VI_GETNEXT) { + vip_r = vimage_get_next(vip, vip_r, 0); + if (vip_r == NULL) + return (ESRCH); + } + if (vi_req->vi_req_action == VI_GETNEXT_RECURSE) { + vip_r = vimage_get_next(vip, vip_r, 1); + if (vip_r == NULL) + return (ESRCH); + } + + if (vip_r && !vi_child_of(vip, vip_r) && /* XXX delete the rest? */ + vi_req->vi_req_action != VI_GET && + vi_req->vi_req_action != VI_GETNEXT) + return (EPERM); + + switch (cmd) { + + case SIOCGPVIMAGE: + vimage_relative_name(vip, vip_r, vi_req->vi_name, + sizeof (vi_req->vi_name)); + vi_req->vi_proc_count = vip_r->v_procg->nprocs; + vi_req->vi_if_count = vip_r->v_net->ifcnt; + vi_req->vi_sock_count = vip_r->v_net->sockcnt; + break; + + case SIOCSPVIMAGE: + if (vi_req->vi_req_action == VI_DESTROY) { +#ifdef NOTYET + error = vi_destroy(vip_r); +#endif + break; + } + + if (vi_req->vi_req_action == VI_SWITCHTO) { + struct proc *p = td->td_proc; + struct ucred *oldcred, *newcred; + + /* + * XXX priv_check()? + * XXX allow only a single td per proc here? + */ + newcred = crget(); + PROC_LOCK(p); + oldcred = p->p_ucred; + setsugid(p); + crcopy(newcred, oldcred); + refcount_release(&newcred->cr_vimage->vi_ucredrefc); + newcred->cr_vimage = vip_r; + refcount_acquire(&newcred->cr_vimage->vi_ucredrefc); + p->p_ucred = newcred; + PROC_UNLOCK(p); + sx_xlock(&allproc_lock); + oldcred->cr_vimage->v_procg->nprocs--; + refcount_release(&oldcred->cr_vimage->vi_ucredrefc); + P_TO_VPROCG(p)->nprocs++; + sx_xunlock(&allproc_lock); + crfree(oldcred); + break; + } + + if (vi_req->vi_req_action & VI_CREATE) { + char *dotpos; + + dotpos = strrchr(vi_req->vi_name, '.'); + if (dotpos != NULL) { + *dotpos = 0; + vip = vimage_by_name(vip, vi_req->vi_name); + if (vip == NULL) + return (ESRCH); + dotpos++; + vip_r = vi_alloc(vip, dotpos); + } else + vip_r = vi_alloc(vip, vi_req->vi_name); + if (vip_r == NULL) + return (ENOMEM); + } + + /* XXX What the hell is this doing here? */ + if (vip == vip_r && !IS_DEFAULT_VIMAGE(vip)) + return (EPERM); + } + + return (error); +} + + +/* + * Kernel interfaces and handlers. + */ + +void vnet_mod_register(const struct vnet_modinfo *vmi) { @@ -297,6 +662,68 @@ return (ENOENT); } +static struct vimage * +vi_alloc(struct vimage *parent, char *name) +{ + struct vimage *vip; + struct vnet *vnet; + struct vprocg *vprocg; + struct vnet_modlink *vml; + + /* + * XXX don't forget the locking + */ + + /* A brute force check whether there's enough mem for a new vimage */ + vip = malloc(512*1024, M_VIMAGE, M_NOWAIT); /* XXX aaaargh... */ + if (vip == NULL) + goto vi_alloc_done; + free(vip, M_VIMAGE); + + vip = malloc(sizeof(struct vimage), M_VIMAGE, M_NOWAIT | M_ZERO); + if (vip == NULL) + panic("vi_alloc: malloc failed for vimage \"%s\"\n", name); + vip->vi_id = last_vi_id++; + LIST_INIT(&vip->vi_child_head); + sprintf(vip->vi_name, "%s", name); + vip->vi_parent = parent; + /* XXX locking */ + if (parent != NULL) + LIST_INSERT_HEAD(&parent->vi_child_head, vip, vi_sibling); + else if (!LIST_EMPTY(&vimage_head)) + panic("there can be only one default vimage!"); + LIST_INSERT_HEAD(&vimage_head, vip, vi_le); + + vnet = malloc(sizeof(struct vnet), M_VNET, M_NOWAIT | M_ZERO); + if (vnet == NULL) + panic("vi_alloc: malloc failed for vnet \"%s\"\n", name); + vip->v_net = vnet; + vnet->vnet_id = last_vnet_id++; + vnet->vnet_magic_n = VNET_MAGIC_N; + + vprocg = malloc(sizeof(struct vprocg), M_VPROCG, M_NOWAIT | M_ZERO); + if (vprocg == NULL) + panic("vi_alloc: malloc failed for vprocg \"%s\"\n", name); + vip->v_procg = vprocg; + vprocg->vprocg_id = last_vprocg_id++; + + /* Initialize / attach vnet module instances. */ + CURVNET_SET_QUIET(vnet); + TAILQ_FOREACH(vml, &vnet_modlink_head, vml_mod_le) + vnet_mod_constructor(vml); + CURVNET_RESTORE(); + + VNET_LIST_LOCK(); + LIST_INSERT_HEAD(&vnet_head, vnet, vnet_le); + VNET_LIST_UNLOCK(); + + /* XXX locking */ + LIST_INSERT_HEAD(&vprocg_head, vprocg, vprocg_le); + +vi_alloc_done: + return (vip); +} + static void vi_init(void *unused) { ==== //depot/projects/vimage-commit2/src/sys/net/if.c#54 (text+ko) ==== @@ -2187,6 +2187,20 @@ ifr = (struct ifreq *)data; switch (cmd) { +#ifdef VIMAGE + /* + * XXX Should be implemented as separate system calls. This is + * just a temporary hack! + */ + case SIOCSIFVIMAGE: + error = vi_if_move((struct vi_req *) data, NULL, + TD_TO_VIMAGE(td)); + return (error); + case SIOCSPVIMAGE: + case SIOCGPVIMAGE: + error = vi_td_ioctl(cmd, (struct vi_req *) data, td); + return (error); +#endif case SIOCIFCREATE: case SIOCIFCREATE2: error = priv_check(td, PRIV_NET_IFCREATE); ==== //depot/projects/vimage-commit2/src/sys/net/if_var.h#22 (text+ko) ==== @@ -169,6 +169,8 @@ (struct ifnet *); int (*if_transmit) /* initiate output routine */ (struct ifnet *, struct mbuf *); + void (*if_reassign) /* reassign to vnet routine */ + (struct ifnet *, struct vnet *, char *); struct ifaddr *if_addr; /* pointer to link-level address */ void *if_llsoftc; /* link layer softc */ int if_drv_flags; /* driver-managed status flags */ @@ -194,6 +196,8 @@ void *if_lagg; /* lagg glue */ u_char if_alloctype; /* if_type at time of allocation */ + struct vnet *if_home_vnet; /* where this ifnet originates from */ + /* * Spare fields are added so that we can modify sensitive data * structures without changing the kernel binary interface, and must ==== //depot/projects/vimage-commit2/src/sys/sys/sockio.h#3 (text+ko) ==== @@ -108,6 +108,10 @@ #define SIOCGPRIVATE_0 _IOWR('i', 80, struct ifreq) /* device private 0 */ #define SIOCGPRIVATE_1 _IOWR('i', 81, struct ifreq) /* device private 1 */ +#define SIOCSPVIMAGE _IOW('i', 101, struct vi_req) /* set proc vimage */ +#define SIOCGPVIMAGE _IOWR('i', 102, struct vi_req) /* get proc vimage */ +#define SIOCSIFVIMAGE _IOWR('i', 103, struct vi_req) /* set ifc vi/net */ + #define SIOCSDRVSPEC _IOW('i', 123, struct ifdrv) /* set driver-specific parameters */ #define SIOCGDRVSPEC _IOWR('i', 123, struct ifdrv) /* get driver-specific ==== //depot/projects/vimage-commit2/src/sys/sys/vimage.h#55 (text+ko) ==== @@ -36,6 +36,33 @@ #include <sys/proc.h> #include <sys/queue.h> +/* Interim userspace API. */ +struct vi_req { + int vi_api_cookie; /* Catch API mismatch. */ + int vi_req_action; /* What to do with this reqest? */ + u_short vi_proc_count; /* Current number of processes. */ + u_short vi_child_count; /* Current number of child vimages. */ + int vi_if_count; /* Current number network interfaces. */ + int vi_sock_count; + char vi_name[MAXPATHLEN]; + char vi_if_xname[MAXPATHLEN]; /* XXX should be IFNAMSIZ */ +}; + +#define VI_CREATE 0x00000001 +#define VI_DESTROY 0x00000002 +#define VI_SWITCHTO 0x00000008 +#define VI_IFACE 0x00000010 +#define VI_GET 0x00000100 +#define VI_GETNEXT 0x00000200 +#define VI_GETNEXT_RECURSE 0x00000300 +#define VI_SET_NAME 0x00100000 + +#define VI_API_VERSION 1 /* Bump on struct changes. */ + +#define VI_API_COOKIE ((sizeof(struct vi_req) << 16) | VI_API_VERSION) + +#ifdef _KERNEL + #if defined(VIMAGE) && defined(VIMAGE_GLOBALS) #error "You cannot have both option VIMAGE and option VIMAGE_GLOBALS!" #endif @@ -46,13 +73,14 @@ struct vprocg; struct vnet; +struct vi_req; +struct ifnet; struct kld_sym_lookup; typedef int vnet_attach_fn(const void *); typedef int vnet_detach_fn(const void *); #ifndef VIMAGE_GLOBALS - struct vnet_symmap { char *name; size_t offset; @@ -128,6 +156,9 @@ #define V_MOD_vprocg 0 /* no minor module ids like in vnet */ int vi_symlookup(struct kld_sym_lookup *, char *); +int vi_td_ioctl(u_long, struct vi_req *, struct thread *); +int vi_if_move(struct vi_req *, struct ifnet *, struct vimage *); +void if_reassign_common(struct ifnet *, struct vnet *, const char *); void vnet_mod_register(const struct vnet_modinfo *); void vnet_mod_register_multi(const struct vnet_modinfo *, void *, char *); void vnet_mod_deregister(const struct vnet_modinfo *); @@ -460,4 +491,6 @@ #define VIMAGE_CTASSERT(x, y) struct __hack #endif +#endif /* _KERNEL */ + #endif /* !_SYS_VIMAGE_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905072139.n47LdeGN099635>
