PERFORCE change 129833 for review
Marko Zec
zec at FreeBSD.org
Fri Nov 30 11:01:32 PST 2007
http://perforce.freebsd.org/chv.cgi?CH=129833
Change 129833 by zec at zec_tpx32 on 2007/11/30 19:00:38
Introduce a new driver-specific ifnet method if_reassign()
which should handle requests for reassigning an ifnet from
one vnet to another. ether_redesign() is the first
if_redesign() implementation, with more to follow.
Requests for reassigning ifnets with no registered
if_reassign() method will be denied, which solves the issue
of kernel panics on attempts to reassign non-ethernet ifnets.
Affected files ...
.. //depot/projects/vimage/src/sys/kern/kern_vimage.c#56 edit
.. //depot/projects/vimage/src/sys/net/if_ethersubr.c#17 edit
.. //depot/projects/vimage/src/sys/net/if_var.h#10 edit
.. //depot/projects/vimage/src/sys/net80211/ieee80211.c#7 edit
.. //depot/projects/vimage/src/sys/sys/vimage.h#51 edit
Differences ...
==== //depot/projects/vimage/src/sys/kern/kern_vimage.c#56 (text+ko) ====
@@ -278,76 +278,22 @@
return (0);
}
-
/*
- * Move the interface to another vnet. The interface can be specified either
- * by ifp argument, or by name contained in vi_req->vi_chroot 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.
+ * 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!
*/
-int
-vi_if_move(vi_req, ifp, vip)
- struct vi_req *vi_req;
- struct ifnet *ifp;
- struct vimage *vip;
+void
+if_reassign_common(struct ifnet *ifp, struct vnet *new_vnet, const char *dname)
{
- struct vimage *new_vip;
- struct vnet *new_vnet = NULL;
- u_char eaddr[6];
-
- 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_chroot);
- if (ifp == NULL)
- return (ENXIO);
-
- 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);
- }
-
- /* Loopback interfaces cannot be moved across network stacks */
- if (ifp->if_flags & IFF_LOOPBACK)
- return (EPERM);
-
- /*
- * This is tricky. First we have to detach the interface,
- * and then reattach it to the target vnet. Before doing
- * that, we reassing the interface unit number to look nice
- * in the target vnet.
- */
- switch (ifp->if_type) {
- case IFT_ETHER:
- case IFT_L2VLAN:
- bcopy(IF_LLADDR(ifp), eaddr, 6);
- ether_ifdetach(ifp);
- break;
- case IFT_PROPVIRTUAL: /* XXX ng_eiface */
- if_detach(ifp);
- break;
- default:
- panic("don't know yet how to handle iftype %d", ifp->if_type);
- /* if_detach(ifp); */
- }
- ifp->if_bpf = NULL;
/* do/while construct needed to confine scope of INIT_VNET_NET() */
do {
INIT_VNET_NET(curvnet);
@@ -386,54 +332,78 @@
snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ifp->if_dname,
ifp->if_dunit);
} else {
- if (vi_req && strlen(vi_req->vi_if_xname) > 0) {
- snprintf(ifp->if_xname, IFNAMSIZ, "%s",
- vi_req->vi_if_xname);
- } else {
- int unit = 0;
- struct ifnet *iter;
+ 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();
+}
-#define FINDFREEUNIT(dname) \
- 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);
+/*
+ * Move the interface to another vnet. The interface can be specified either
+ * by ifp argument, or by name contained in vi_req->vi_chroot 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(vi_req, ifp, vip)
+ struct vi_req *vi_req;
+ struct ifnet *ifp;
+ struct vimage *vip;
+{
+ struct vimage *new_vip;
+ struct vnet *new_vnet = NULL;
- switch (ifp->if_type) {
- case IFT_ETHER:
- case IFT_L2VLAN:
- FINDFREEUNIT("eth");
- break;
- case IFT_PROPVIRTUAL:
- FINDFREEUNIT("ser");
- break;
- default:
- break;
- }
- }
+ 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;
}
- switch (ifp->if_type) {
- case IFT_ETHER:
- case IFT_L2VLAN:
- ether_ifattach(ifp, eaddr);
- break;
- case IFT_PROPVIRTUAL: /* XXX ng_eiface */
- if_attach(ifp);
- break;
- default:
- panic("don't know yet how to handle iftype %d", ifp->if_type);
- /* if_attach(ifp); */
+ if (ifp == NULL)
+ ifp = ifunit(vi_req->vi_chroot);
+ 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_chroot, "%s", ifp->if_xname);
- CURVNET_RESTORE();
return (0);
}
==== //depot/projects/vimage/src/sys/net/if_ethersubr.c#17 (text+ko) ====
@@ -886,6 +886,25 @@
return (etherbuf);
}
+#ifdef VIMAGE
+static void
+ether_reassign(struct ifnet *ifp, struct vnet *vnet, char *dname)
+{
+ u_char eaddr[6];
+
+ bcopy(IF_LLADDR(ifp), eaddr, 6);
+ ether_ifdetach(ifp);
+ ifp->if_bpf = NULL;
+ if_reassign_common(ifp, vnet, "eth");
+ if (dname)
+ snprintf(ifp->if_xname, IFNAMSIZ, "%s", dname);
+
+ CURVNET_SET_QUIET(vnet);
+ ether_ifattach(ifp, eaddr);
+ CURVNET_RESTORE();
+}
+#endif
+
/*
* Perform common duties while attaching to interface list
*/
@@ -906,6 +925,9 @@
ifp->if_output = ether_output;
ifp->if_input = ether_input;
ifp->if_resolvemulti = ether_resolvemulti;
+#ifdef VIMAGE
+ ifp->if_reassign = ether_reassign;
+#endif
if (ifp->if_baudrate == 0)
ifp->if_baudrate = IF_Mbps(10); /* just a default */
ifp->if_broadcastaddr = etherbroadcastaddr;
==== //depot/projects/vimage/src/sys/net/if_var.h#10 (text+ko) ====
@@ -130,6 +130,7 @@
* field is deprecated. Use if_addr or ifaddr_byindex() instead.
*/
struct knlist if_klist; /* events attached to this if */
+ struct vnet *if_vnet; /* network stack instance */
int if_pcount; /* number of promiscuous listeners */
struct carp_if *if_carp; /* carp interface structure */
struct bpf_if *if_bpf; /* packet filter structure */
@@ -160,6 +161,9 @@
(void *);
int (*if_resolvemulti) /* validate/resolve multicast */
(struct ifnet *, struct sockaddr **, struct sockaddr *);
+ void (*if_reassign) /* reassign to vnet routine */
+ (struct ifnet *, struct vnet *, char *);
+ struct vnet *if_home_vnet; /* where this ifnet originates from */
struct ifaddr *if_addr; /* pointer to link-level address */
void *if_spare2; /* spare pointer 2 */
void *if_spare3; /* spare pointer 3 */
@@ -187,9 +191,6 @@
/* protected by if_addr_mtx */
void *if_pf_kif;
void *if_lagg; /* lagg glue */
-
- struct vnet *if_vnet; /* network stack instance */
- struct vnet *if_home_vnet; /* where this ifnet originates from */
};
typedef void if_init_f_t(void *);
==== //depot/projects/vimage/src/sys/net80211/ieee80211.c#7 (text+ko) ====
@@ -31,6 +31,8 @@
* IEEE 802.11 generic handler
*/
+#include "opt_vimage.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -213,6 +215,10 @@
ether_ifattach(ifp, ic->ic_myaddr);
ifp->if_output = ieee80211_output;
+#ifdef VIMAGE
+ /* Override ether_reassign() */
+ ifp->if_reassign = NULL; /* XXX not implemented yet */
+#endif
bpfattach2(ifp, DLT_IEEE802_11,
sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
==== //depot/projects/vimage/src/sys/sys/vimage.h#51 (text+ko) ====
@@ -342,6 +342,8 @@
void vi_cpu_acct(void *);
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 *);
+
int vi_symlookup(struct kld_sym_lookup *, char *);
struct vimage *vnet2vimage(struct vnet *);
struct vimage *vimage_by_name(struct vimage *, char *);
More information about the p4-projects
mailing list