aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2017-01-18 13:31:17 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2017-01-18 13:31:17 +0000
commitf3e7afe2d7b262ab55ab818445d4dfdb6e0c70a9 (patch)
treef99cc015b93fe941bf2c9800511d277156c375d9 /sys/net
parentae69172343e8e6940510bf3cf7512fceaa479929 (diff)
Notes
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/ieee8023ad_lacp.c31
-rw-r--r--sys/net/ieee8023ad_lacp.h3
-rw-r--r--sys/net/if.h1
-rw-r--r--sys/net/if_dead.c28
-rw-r--r--sys/net/if_lagg.c57
-rw-r--r--sys/net/if_var.h54
-rw-r--r--sys/net/if_vlan.c33
7 files changed, 205 insertions, 2 deletions
diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c
index 4863ac98035b..bf73a5c75e2b 100644
--- a/sys/net/ieee8023ad_lacp.c
+++ b/sys/net/ieee8023ad_lacp.c
@@ -30,6 +30,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_ratelimit.h"
+
#include <sys/param.h>
#include <sys/callout.h>
#include <sys/eventhandler.h>
@@ -853,6 +855,35 @@ lacp_select_tx_port(struct lagg_softc *sc, struct mbuf *m)
return (lp->lp_lagg);
}
+
+#ifdef RATELIMIT
+struct lagg_port *
+lacp_select_tx_port_by_hash(struct lagg_softc *sc, uint32_t flowid)
+{
+ struct lacp_softc *lsc = LACP_SOFTC(sc);
+ struct lacp_portmap *pm;
+ struct lacp_port *lp;
+ uint32_t hash;
+
+ if (__predict_false(lsc->lsc_suppress_distributing)) {
+ LACP_DPRINTF((NULL, "%s: waiting transit\n", __func__));
+ return (NULL);
+ }
+
+ pm = &lsc->lsc_pmap[lsc->lsc_activemap];
+ if (pm->pm_count == 0) {
+ LACP_DPRINTF((NULL, "%s: no active aggregator\n", __func__));
+ return (NULL);
+ }
+
+ hash = flowid >> sc->flowid_shift;
+ hash %= pm->pm_count;
+ lp = pm->pm_map[hash];
+
+ return (lp->lp_lagg);
+}
+#endif
+
/*
* lacp_suppress_distributing: drop transmit packets for a while
* to preserve packet ordering.
diff --git a/sys/net/ieee8023ad_lacp.h b/sys/net/ieee8023ad_lacp.h
index 8f0f51a71c48..b26e2c9251f2 100644
--- a/sys/net/ieee8023ad_lacp.h
+++ b/sys/net/ieee8023ad_lacp.h
@@ -284,6 +284,9 @@ struct lacp_softc {
struct mbuf *lacp_input(struct lagg_port *, struct mbuf *);
struct lagg_port *lacp_select_tx_port(struct lagg_softc *, struct mbuf *);
+#ifdef RATELIMIT
+struct lagg_port *lacp_select_tx_port_by_hash(struct lagg_softc *, uint32_t);
+#endif
void lacp_attach(struct lagg_softc *);
void lacp_detach(void *);
void lacp_init(struct lagg_softc *);
diff --git a/sys/net/if.h b/sys/net/if.h
index 98ae0a823cd3..26f078700100 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -239,6 +239,7 @@ struct if_data {
#define IFCAP_RXCSUM_IPV6 0x200000 /* can offload checksum on IPv6 RX */
#define IFCAP_TXCSUM_IPV6 0x400000 /* can offload checksum on IPv6 TX */
#define IFCAP_HWSTATS 0x800000 /* manages counters internally */
+#define IFCAP_TXRTLMT 0x1000000 /* hardware supports TX rate limiting */
#define IFCAP_HWCSUM_IPV6 (IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6)
diff --git a/sys/net/if_dead.c b/sys/net/if_dead.c
index 8b36ab348628..0e32dcf29116 100644
--- a/sys/net/if_dead.c
+++ b/sys/net/if_dead.c
@@ -100,6 +100,30 @@ ifdead_get_counter(struct ifnet *ifp, ift_counter cnt)
return (0);
}
+static int
+ifdead_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
+ struct m_snd_tag **ppmt)
+{
+ return (EOPNOTSUPP);
+}
+
+static int
+ifdead_snd_tag_modify(struct m_snd_tag *pmt, union if_snd_tag_modify_params *params)
+{
+ return (EOPNOTSUPP);
+}
+
+static int
+ifdead_snd_tag_query(struct m_snd_tag *pmt, union if_snd_tag_query_params *params)
+{
+ return (EOPNOTSUPP);
+}
+
+static void
+ifdead_snd_tag_free(struct m_snd_tag *pmt)
+{
+}
+
void
if_dead(struct ifnet *ifp)
{
@@ -112,4 +136,8 @@ if_dead(struct ifnet *ifp)
ifp->if_qflush = ifdead_qflush;
ifp->if_transmit = ifdead_transmit;
ifp->if_get_counter = ifdead_get_counter;
+ ifp->if_snd_tag_alloc = ifdead_snd_tag_alloc;
+ ifp->if_snd_tag_modify = ifdead_snd_tag_modify;
+ ifp->if_snd_tag_query = ifdead_snd_tag_query;
+ ifp->if_snd_tag_free = ifdead_snd_tag_free;
}
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 0a5fc159e57b..b44fdc6e6c9c 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -23,6 +23,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_inet6.h"
+#include "opt_ratelimit.h"
#include <sys/param.h>
#include <sys/kernel.h>
@@ -118,6 +119,11 @@ static void lagg_port2req(struct lagg_port *, struct lagg_reqport *);
static void lagg_init(void *);
static void lagg_stop(struct lagg_softc *);
static int lagg_ioctl(struct ifnet *, u_long, caddr_t);
+#ifdef RATELIMIT
+static int lagg_snd_tag_alloc(struct ifnet *,
+ union if_snd_tag_alloc_params *,
+ struct m_snd_tag **);
+#endif
static int lagg_ether_setmulti(struct lagg_softc *);
static int lagg_ether_cmdmulti(struct lagg_port *, int);
static int lagg_setflag(struct lagg_port *, int, int,
@@ -503,7 +509,12 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
ifp->if_ioctl = lagg_ioctl;
ifp->if_get_counter = lagg_get_counter;
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
+#ifdef RATELIMIT
+ ifp->if_snd_tag_alloc = lagg_snd_tag_alloc;
+ ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS | IFCAP_TXRTLMT;
+#else
ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS;
+#endif
/*
* Attach as an ordinary ethernet device, children will be attached
@@ -1549,6 +1560,52 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return (error);
}
+#ifdef RATELIMIT
+static int
+lagg_snd_tag_alloc(struct ifnet *ifp,
+ union if_snd_tag_alloc_params *params,
+ struct m_snd_tag **ppmt)
+{
+ struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
+ struct lagg_port *lp;
+ struct lagg_lb *lb;
+ uint32_t p;
+
+ switch (sc->sc_proto) {
+ case LAGG_PROTO_FAILOVER:
+ lp = lagg_link_active(sc, sc->sc_primary);
+ break;
+ case LAGG_PROTO_LOADBALANCE:
+ if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) == 0 ||
+ params->hdr.flowtype == M_HASHTYPE_NONE)
+ return (EOPNOTSUPP);
+ p = params->hdr.flowid >> sc->flowid_shift;
+ p %= sc->sc_count;
+ lb = (struct lagg_lb *)sc->sc_psc;
+ lp = lb->lb_ports[p];
+ lp = lagg_link_active(sc, lp);
+ break;
+ case LAGG_PROTO_LACP:
+ if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) == 0 ||
+ params->hdr.flowtype == M_HASHTYPE_NONE)
+ return (EOPNOTSUPP);
+ lp = lacp_select_tx_port_by_hash(sc, params->hdr.flowid);
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ if (lp == NULL)
+ return (EOPNOTSUPP);
+ ifp = lp->lp_ifp;
+ if (ifp == NULL || ifp->if_snd_tag_alloc == NULL ||
+ (ifp->if_capenable & IFCAP_TXRTLMT) == 0)
+ return (EOPNOTSUPP);
+
+ /* forward allocation request */
+ return (ifp->if_snd_tag_alloc(ifp, params, ppmt));
+}
+#endif
+
static int
lagg_ether_setmulti(struct lagg_softc *sc)
{
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 62c4bfdd33fb..7c8fd7ec80a4 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -175,6 +175,49 @@ struct if_encap_req {
#define IFENCAP_FLAG_BROADCAST 0x02 /* Destination is broadcast */
+/*
+ * Network interface send tag support. The storage of "struct
+ * m_snd_tag" comes from the network driver and it is free to allocate
+ * as much additional space as it wants for its own use.
+ */
+struct m_snd_tag;
+
+#define IF_SND_TAG_TYPE_RATE_LIMIT 0
+#define IF_SND_TAG_TYPE_MAX 1
+
+struct if_snd_tag_alloc_header {
+ uint32_t type; /* send tag type, see IF_SND_TAG_XXX */
+ uint32_t flowid; /* mbuf hash value */
+ uint32_t flowtype; /* mbuf hash type */
+};
+
+struct if_snd_tag_alloc_rate_limit {
+ struct if_snd_tag_alloc_header hdr;
+ uint64_t max_rate; /* in bytes/s */
+};
+
+struct if_snd_tag_rate_limit_params {
+ uint64_t max_rate; /* in bytes/s */
+};
+
+union if_snd_tag_alloc_params {
+ struct if_snd_tag_alloc_header hdr;
+ struct if_snd_tag_alloc_rate_limit rate_limit;
+};
+
+union if_snd_tag_modify_params {
+ struct if_snd_tag_rate_limit_params rate_limit;
+};
+
+union if_snd_tag_query_params {
+ struct if_snd_tag_rate_limit_params rate_limit;
+};
+
+typedef int (if_snd_tag_alloc_t)(struct ifnet *, union if_snd_tag_alloc_params *,
+ struct m_snd_tag **);
+typedef int (if_snd_tag_modify_t)(struct m_snd_tag *, union if_snd_tag_modify_params *);
+typedef int (if_snd_tag_query_t)(struct m_snd_tag *, union if_snd_tag_query_params *);
+typedef void (if_snd_tag_free_t)(struct m_snd_tag *);
/*
* Structure defining a network interface.
@@ -304,12 +347,19 @@ struct ifnet {
u_int if_hw_tsomaxsegsize; /* TSO maximum segment size in bytes */
/*
+ * Network adapter send tag support:
+ */
+ if_snd_tag_alloc_t *if_snd_tag_alloc;
+ if_snd_tag_modify_t *if_snd_tag_modify;
+ if_snd_tag_query_t *if_snd_tag_query;
+ if_snd_tag_free_t *if_snd_tag_free;
+
+ /*
* Spare fields to be added before branching a stable branch, so
* that structure can be enhanced without changing the kernel
* binary interface.
*/
- void *if_pspare[4]; /* packet pacing / general use */
- int if_ispare[4]; /* packet pacing / general use */
+ int if_ispare[4]; /* general use */
};
/* for compatibility with other BSDs */
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 73470dc80e3f..608826a6dc92 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_vlan.h"
+#include "opt_ratelimit.h"
#include <sys/param.h>
#include <sys/eventhandler.h>
@@ -212,6 +213,10 @@ static void trunk_destroy(struct ifvlantrunk *trunk);
static void vlan_init(void *foo);
static void vlan_input(struct ifnet *ifp, struct mbuf *m);
static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
+#ifdef RATELIMIT
+static int vlan_snd_tag_alloc(struct ifnet *,
+ union if_snd_tag_alloc_params *, struct m_snd_tag **);
+#endif
static void vlan_qflush(struct ifnet *ifp);
static int vlan_setflag(struct ifnet *ifp, int flag, int status,
int (*func)(struct ifnet *, int));
@@ -971,6 +976,9 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
ifp->if_transmit = vlan_transmit;
ifp->if_qflush = vlan_qflush;
ifp->if_ioctl = vlan_ioctl;
+#ifdef RATELIMIT
+ ifp->if_snd_tag_alloc = vlan_snd_tag_alloc;
+#endif
ifp->if_flags = VLAN_IFFLAGS;
ether_ifattach(ifp, eaddr);
/* Now undo some of the damage... */
@@ -1591,6 +1599,15 @@ vlan_capabilities(struct ifvlan *ifv)
TOEDEV(ifp) = TOEDEV(p);
ifp->if_capenable |= p->if_capenable & IFCAP_TOE;
}
+
+#ifdef RATELIMIT
+ /*
+ * If the parent interface supports ratelimiting, so does the
+ * VLAN interface.
+ */
+ ifp->if_capabilities |= (p->if_capabilities & IFCAP_TXRTLMT);
+ ifp->if_capenable |= (p->if_capenable & IFCAP_TXRTLMT);
+#endif
}
static void
@@ -1801,3 +1818,19 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return (error);
}
+
+#ifdef RATELIMIT
+static int
+vlan_snd_tag_alloc(struct ifnet *ifp,
+ union if_snd_tag_alloc_params *params,
+ struct m_snd_tag **ppmt)
+{
+
+ /* get trunk device */
+ ifp = vlan_trunkdev(ifp);
+ if (ifp == NULL || (ifp->if_capenable & IFCAP_TXRTLMT) == 0)
+ return (EOPNOTSUPP);
+ /* forward allocation request */
+ return (ifp->if_snd_tag_alloc(ifp, params, ppmt));
+}
+#endif