Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Nov 2007 19:01:31 GMT
From:      Marko Zec <zec@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 129833 for review
Message-ID:  <200711301901.lAUJ1VJJ070330@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=129833

Change 129833 by zec@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 *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200711301901.lAUJ1VJJ070330>