=== sys/netinet/in_pcb.c
==================================================================
--- sys/netinet/in_pcb.c	(revision 268358)
+++ sys/netinet/in_pcb.c	(local)
@@ -1173,6 +1173,100 @@
 }
 
 /*
+ * in_pcb_handle_ratectlreq - this function sets the hardware flow ID
+ * for a given IPv4 connection based on the input arguments.
+ *
+ * Return values:
+ * 0: Success
+ * Non-zero: Failure
+ */
+int
+in_pcb_handle_ratectlreq(struct ifnet *ifp, struct in_ratectlreq *req,
+    const struct in_flowid_methods *mtod, void *arg)
+{
+	struct inpcb *inp;
+	int error;
+
+	if (ifp == NULL || req == NULL || mtod == NULL ||
+	    mtod->inf_alloc == NULL || mtod->inf_rateset == NULL ||
+	    mtod->inf_free == NULL)
+		return (EINVAL);
+
+	inp = in_pcblookup(&V_tcbinfo,
+	    req->ifreq_dst.sin_addr, req->ifreq_dst.sin_port,
+	    req->ifreq_src.sin_addr, req->ifreq_src.sin_port,
+	    INPLOOKUP_WLOCKPCB, ifp);
+	if (inp == NULL)
+		return (ENOENT);
+
+	INP_WLOCK_ASSERT(inp);
+
+	if (inp->inp_flowid_mtod == NULL) {
+		error = mtod->inf_alloc(arg, &inp->inp_flowid);
+		if (error != 0)
+			goto done;
+		inp->inp_flowid_mtod = mtod;
+		inp->inp_flowid_arg = arg;
+		/* ensure that the flow ID is not overwritten */ 
+		inp->inp_flags |= INP_HW_FLOWID;
+		inp->inp_flags &= ~INP_SW_FLOWID;
+		inp->inp_flowtype = M_HASHTYPE_NONE;
+	}
+	error = inp->inp_flowid_mtod->inf_rateset(inp->inp_flowid_arg,
+	    inp->inp_flowid, req->ifreq_baudrate);
+done:
+	INP_WUNLOCK(inp);
+	return (error);
+}
+
+/*
+ * in6_pcb_handle_ratectlreq - this function sets the hardware flow ID
+ * for a given IPv6 connection based on the input arguments.
+ *
+ * Return values:
+ * 0: Success
+ * Non-zero: Failure
+ */
+int
+in6_pcb_handle_ratectlreq(struct ifnet *ifp, struct in6_ratectlreq *req,
+    const struct in_flowid_methods *mtod, void *arg)
+{
+	struct inpcb *inp;
+	int error;
+
+	if (ifp == NULL || req == NULL || mtod == NULL ||
+	    mtod->inf_alloc == NULL || mtod->inf_rateset == NULL ||
+	    mtod->inf_free == NULL)
+		return (EINVAL);
+
+	inp = in6_pcblookup(&V_tcbinfo,
+	    &req->ifreq_dst.sin6_addr, req->ifreq_dst.sin6_port,
+	    &req->ifreq_src.sin6_addr, req->ifreq_src.sin6_port,
+	    INPLOOKUP_WLOCKPCB, ifp);
+	if (inp == NULL)
+		return (ENOENT);
+
+	INP_WLOCK_ASSERT(inp);
+
+	if (inp->inp_flowid_mtod == NULL) {
+		error = mtod->inf_alloc(arg, &inp->inp_flowid);
+		if (error != 0)
+			goto done;
+		inp->inp_flowid_mtod = mtod;
+		inp->inp_flowid_arg = arg;
+		/* ensure that the flow ID is not overwritten */ 
+		inp->inp_flags |= INP_HW_FLOWID;
+		inp->inp_flags &= ~INP_SW_FLOWID;
+		inp->inp_flowtype = M_HASHTYPE_NONE;
+	}
+	error = inp->inp_flowid_mtod->inf_rateset(inp->inp_flowid_arg,
+	    inp->inp_flowid, req->ifreq_baudrate);
+done:
+	INP_WUNLOCK(inp);
+	return (error);
+}
+
+/*
  * Unconditionally schedule an inpcb to be freed by decrementing its
  * reference count, which should occur only after the inpcb has been detached
  * from its socket.  If another thread holds a temporary reference (acquired
@@ -1192,6 +1286,12 @@
 	INP_WLOCK_ASSERT(inp);
 
 	/* XXXRW: Do as much as possible here. */
+
+	/* Release flow ID, if any */
+	if (inp->inp_flowid_mtod != NULL) {
+		inp->inp_flowid_mtod->inf_free(
+		    inp->inp_flowid_arg, inp->inp_flowid);
+	}
 #ifdef IPSEC
 	if (inp->inp_sp != NULL)
 		ipsec_delete_pcbpolicy(inp);
=== sys/netinet/in_pcb.h
==================================================================
--- sys/netinet/in_pcb.h	(revision 268358)
+++ sys/netinet/in_pcb.h	(local)
@@ -39,6 +39,7 @@
 #define _NETINET_IN_PCB_H_
 
 #include <sys/queue.h>
+#include <sys/mbuf.h>
 #include <sys/_lock.h>
 #include <sys/_mutex.h>
 #include <sys/_rwlock.h>
@@ -127,6 +128,23 @@
 
 struct	icmp6_filter;
 
+/*
+ * The following functions must be non-blocking, because they are
+ * executing in the fast-path:
+ */
+typedef int (in_flowid_alloc_t)(void *, m_flowid_t *);
+typedef int (in_flowid_rateset_t)(void *, m_flowid_t, uint64_t);
+typedef void (in_flowid_free_t)(void *, m_flowid_t);
+
+struct in_ratectlreq;
+struct in6_ratectlreq;
+
+struct in_flowid_methods {
+	in_flowid_alloc_t *inf_alloc;
+	in_flowid_rateset_t *inf_rateset;
+	in_flowid_free_t *inf_free;
+};
+
 /*-
  * struct inpcb captures the network layer state for TCP, UDP, and raw IPv4
  * and IPv6 sockets.  In the case of TCP, further per-connection state is
@@ -177,7 +195,9 @@
 	u_char	inp_ip_ttl;		/* (i) time to live proto */
 	u_char	inp_ip_p;		/* (c) protocol proto */
 	u_char	inp_ip_minttl;		/* (i) minimum TTL or drop */
-	uint32_t inp_flowid;		/* (x) flow id / queue id */
+	m_flowid_t inp_flowid;		/* (x) flow ID / queue ID */
+	const struct in_flowid_methods *inp_flowid_mtod; /* (x) flow ID callback methods */
+	void	*inp_flowid_arg;	/* (x) argument for flow ID methods */
 	u_int	inp_refcount;		/* (i) refcount */
 	void	*inp_pspare[5];		/* (x) route caching / general use */
 	uint32_t inp_flowtype;		/* (x) M_HASHTYPE value */
@@ -635,6 +655,10 @@
 void	in_pcbdisconnect(struct inpcb *);
 void	in_pcbdrop(struct inpcb *);
 void	in_pcbfree(struct inpcb *);
+int	in_pcb_handle_ratectlreq(struct ifnet *, struct in_ratectlreq *,
+	    const struct in_flowid_methods *, void *);
+int	in6_pcb_handle_ratectlreq(struct ifnet *, struct in6_ratectlreq *,
+	    const struct in_flowid_methods *, void *);
 int	in_pcbinshash(struct inpcb *);
 int	in_pcbinshash_nopcbgroup(struct inpcb *);
 int	in_pcbladdr(struct inpcb *, struct in_addr *, struct in_addr *,
=== sys/netinet/in_var.h
==================================================================
--- sys/netinet/in_var.h	(revision 268358)
+++ sys/netinet/in_var.h	(local)
@@ -81,6 +81,14 @@
 	struct	sockaddr_in ifra_mask;
 	int	ifra_vhid;
 };
+
+struct in_ratectlreq {
+	char	ifreq_name[IFNAMSIZ];
+	struct sockaddr_in ifreq_dst;
+	struct sockaddr_in ifreq_src;
+	uint64_t ifreq_baudrate;	/* bits per second */
+};
+
 /*
  * Given a pointer to an in_ifaddr (ifaddr),
  * return a pointer to the addr as a sockaddr_in.
=== sys/netinet6/in6_var.h
==================================================================
--- sys/netinet6/in6_var.h	(revision 268358)
+++ sys/netinet6/in6_var.h	(local)
@@ -307,6 +307,13 @@
 	struct in6_addrlifetime ifra_lifetime;
 };
 
+struct in6_ratectlreq {
+	char	ifreq_name[IFNAMSIZ];
+	struct sockaddr_in6 ifreq_dst;
+	struct sockaddr_in6 ifreq_src;
+	uint64_t ifreq_baudrate;	/* bits per second */
+};
+
 /* prefix type macro */
 #define IN6_PREFIX_ND	1
 #define IN6_PREFIX_RR	2
@@ -435,6 +442,7 @@
 #define SIOCDIFADDR_IN6		 _IOW('i', 25, struct in6_ifreq)
 #define OSIOCAIFADDR_IN6	 _IOW('i', 26, struct oin6_aliasreq)
 #define SIOCAIFADDR_IN6		 _IOW('i', 27, struct in6_aliasreq)
+#define	SIOCSRATECTL_IN6	 _IOW('i',110, struct in6_ratectlreq)
 
 #define SIOCSIFPHYADDR_IN6       _IOW('i', 70, struct in6_aliasreq)
 #define	SIOCGIFPSRCADDR_IN6	_IOWR('i', 71, struct in6_ifreq)
=== sys/sys/mbuf.h
==================================================================
--- sys/sys/mbuf.h	(revision 268358)
+++ sys/sys/mbuf.h	(local)
@@ -114,6 +114,8 @@
 	void			(*m_tag_free)(struct m_tag *);
 };
 
+typedef uint32_t m_flowid_t;
+
 /*
  * Record/packet header in first mbuf of chain; valid only if M_PKTHDR is set.
  * Size ILP32: 48
@@ -125,7 +127,7 @@
 	int32_t		 len;		/* total packet length */
 
 	/* Layer crossing persistent information. */
-	uint32_t	 flowid;	/* packet's 4-tuple system */
+	m_flowid_t	 flowid;	/* packet's 4-tuple system */
 	uint64_t	 csum_flags;	/* checksum and offload features */
 	uint16_t	 fibnum;	/* this packet should use this fib */
 	uint8_t		 cosqos;	/* class/quality of service */
=== sys/sys/sockio.h
==================================================================
--- sys/sys/sockio.h	(revision 268358)
+++ sys/sys/sockio.h	(local)
@@ -128,4 +128,6 @@
 #define	SIOCDIFGROUP	 _IOW('i', 137, struct ifgroupreq) /* delete ifgroup */
 #define	SIOCGIFGMEMB	_IOWR('i', 138, struct ifgroupreq) /* get members */
 
+#define	SIOCSRATECTL	 _IOW('i', 139, struct in_ratectlreq)
+
 #endif /* !_SYS_SOCKIO_H_ */
