From: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
To: jeff@garzik.org, davem@davemloft.net
Cc: netdev@vger.kernel.org
Subject: [PATCH 1/3] [NET-NEXT]: Add DCB netlink interface definition
Date: Tue, 27 May 2008 07:13:46 -0700 [thread overview]
Message-ID: <20080527141346.12851.2280.stgit@localhost.localdomain> (raw)
In-Reply-To: <20080527141339.12851.98781.stgit@localhost.localdomain>
This patch adds the netlink interface definition for Data Center Bridging.
This technology uses 802.1Qaz and 801.1Qbb for extending ethernet to
converge different traffic types on a single link. E.g. Fibre Channel
over Ethernet and regular LAN traffic. The goal is to use priority flow
control to pause individual flows at the MAC/network level, without
impacting other network flows.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
include/linux/dcbnl.h | 241 +++++++++++++++
include/linux/netdevice.h | 8
net/Kconfig | 1
net/Makefile | 3
net/dcb/Kconfig | 12 +
net/dcb/Makefile | 1
net/dcb/dcbnl.c | 722 +++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 988 insertions(+), 0 deletions(-)
diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h
new file mode 100644
index 0000000..db50f6c
--- /dev/null
+++ b/include/linux/dcbnl.h
@@ -0,0 +1,241 @@
+#ifndef __LINUX_DCBNL_H__
+#define __LINUX_DCBNL_H__
+/*
+ * Data Center Bridging (DCB) netlink header
+ *
+ * Copyright 2008, Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com>
+ */
+
+#define DCB_PROTO_VERSION 1
+
+/**
+ * enum dcbnl_commands - supported DCB commands
+ *
+ * @DCB_CMD_UNDEFINED: unspecified command to catch errors
+ * @DCB_CMD_GSTATE: request the state of DCB in the device
+ * @DCB_CMD_SSTATE: set the state of DCB in the device
+ * @DCB_CMD_PGTX_GCFG: request the priority group configuration for Tx
+ * @DCB_CMD_PGTX_SCFG: set the priority group configuration for Tx
+ * @DCB_CMD_PGRX_GCFG: request the priority group configuration for Rx
+ * @DCB_CMD_PGRX_SCFG: set the priority group configuration for Rx
+ * @DCB_CMD_PFC_GCFG: request the priority flow control configuration
+ * @DCB_CMD_PFC_SCFG: set the priority flow control configuration
+ * @DCB_CMD_SET_ALL: apply all changes to the underlying device
+ * @DCB_CMD_GPERM_HWADDR: get the permanent MAC address of the underlying
+ * device. Only useful when using bonding.
+ */
+enum dcbnl_commands {
+ DCB_CMD_UNDEFINED,
+
+ DCB_CMD_GSTATE,
+ DCB_CMD_SSTATE,
+
+ DCB_CMD_PGTX_GCFG,
+ DCB_CMD_PGTX_SCFG,
+ DCB_CMD_PGRX_GCFG,
+ DCB_CMD_PGRX_SCFG,
+
+ DCB_CMD_PFC_GCFG,
+ DCB_CMD_PFC_SCFG,
+
+ DCB_CMD_SET_ALL,
+ DCB_CMD_GPERM_HWADDR,
+
+ __DCB_CMD_ENUM_MAX,
+ DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1,
+};
+
+
+/**
+ * enum dcbnl_attrs - DCB top-level netlink attributes
+ *
+ * @DCB_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_ATTR_IFNAME: interface name of the underlying device (NLA_STRING)
+ * @DCB_ATTR_STATE: state of the DCB state machine in the device (NLA_U8)
+ * @DCB_ATTR_PFC_CFG: priority flow control configuration (NLA_NESTED)
+ * @DCB_ATTR_PG_CFG: priority group configuration (NLA_NESTED)
+ * @DCB_ATTR_SET_ALL: bool to commit changes to hardware or not (NLA_U8)
+ * @DCB_ATTR_PERM_HWADDR: MAC address of the physical device (NLA_NESTED)
+ */
+enum dcbnl_attrs {
+ DCB_ATTR_UNDEFINED,
+
+ DCB_ATTR_IFNAME,
+ DCB_ATTR_STATE,
+ DCB_ATTR_PFC_CFG,
+ DCB_ATTR_PG_CFG,
+ DCB_ATTR_SET_ALL,
+ DCB_ATTR_PERM_HWADDR,
+
+ __DCB_ATTR_ENUM_MAX,
+ DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1,
+};
+
+
+/**
+ * enum dcbnl_perm_hwaddr_attrs - DCB Permanent HW Address nested attributes
+ *
+ * @DCB_PERM_HW_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_PERM_HW_ATTR_0: MAC address from receive address 0 (NLA_U8)
+ * @DCB_PERM_HW_ATTR_1: MAC address from receive address 1 (NLA_U8)
+ * @DCB_PERM_HW_ATTR_2: MAC address from receive address 2 (NLA_U8)
+ * @DCB_PERM_HW_ATTR_3: MAC address from receive address 3 (NLA_U8)
+ * @DCB_PERM_HW_ATTR_4: MAC address from receive address 4 (NLA_U8)
+ * @DCB_PERM_HW_ATTR_5: MAC address from receive address 5 (NLA_U8)
+ * @DCB_PERM_HW_ATTR_ALL: apply to all MAC addresses (NLA_FLAG)
+ *
+ * These attributes are used when bonding DCB interfaces together.
+ *
+ */
+enum dcbnl_perm_hwaddr_attrs {
+ DCB_PERM_HW_ATTR_UNDEFINED,
+
+ DCB_PERM_HW_ATTR_0,
+ DCB_PERM_HW_ATTR_1,
+ DCB_PERM_HW_ATTR_2,
+ DCB_PERM_HW_ATTR_3,
+ DCB_PERM_HW_ATTR_4,
+ DCB_PERM_HW_ATTR_5,
+ DCB_PERM_HW_ATTR_ALL,
+
+ __DCB_PERM_HW_ATTR_ENUM_MAX,
+ DCB_PERM_HW_ATTR_MAX = __DCB_PERM_HW_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_pfc_attrs - DCB Priority Flow Control user-priority nested attrs
+ *
+ * @DCB_PFC_UP_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_PFC_UP_ATTR_0: Priority Flow Control value for User Priority 0 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_1: Priority Flow Control value for User Priority 1 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_2: Priority Flow Control value for User Priority 2 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_3: Priority Flow Control value for User Priority 3 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_4: Priority Flow Control value for User Priority 4 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_5: Priority Flow Control value for User Priority 5 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_6: Priority Flow Control value for User Priority 6 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_7: Priority Flow Control value for User Priority 7 (NLA_U8)
+ * @DCB_PFC_UP_ATTR_MAX: highest attribute number currently defined
+ * @DCB_PFC_UP_ATTR_ALL: apply to all priority flow control attrs (NLA_FLAG)
+ *
+ */
+enum dcbnl_pfc_up_attrs {
+ DCB_PFC_UP_ATTR_UNDEFINED,
+
+ DCB_PFC_UP_ATTR_0,
+ DCB_PFC_UP_ATTR_1,
+ DCB_PFC_UP_ATTR_2,
+ DCB_PFC_UP_ATTR_3,
+ DCB_PFC_UP_ATTR_4,
+ DCB_PFC_UP_ATTR_5,
+ DCB_PFC_UP_ATTR_6,
+ DCB_PFC_UP_ATTR_7,
+ DCB_PFC_UP_ATTR_ALL,
+
+ __DCB_PFC_UP_ATTR_ENUM_MAX,
+ DCB_PFC_UP_ATTR_MAX = __DCB_PFC_UP_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_pg_attrs - DCB Priority Group attributes
+ *
+ * @DCB_PG_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_PG_ATTR_TC_0: Priority Group Traffic Class 0 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_1: Priority Group Traffic Class 1 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_2: Priority Group Traffic Class 2 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_3: Priority Group Traffic Class 3 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_4: Priority Group Traffic Class 4 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_5: Priority Group Traffic Class 5 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_6: Priority Group Traffic Class 6 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_7: Priority Group Traffic Class 7 configuration (NLA_NESTED)
+ * @DCB_PG_ATTR_TC_MAX: highest attribute number currently defined
+ * @DCB_PG_ATTR_TC_ALL: apply to all traffic classes (NLA_NESTED)
+ * @DCB_PG_ATTR_BWG_0: Bandwidth group 0 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_1: Bandwidth group 1 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_2: Bandwidth group 2 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_3: Bandwidth group 3 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_4: Bandwidth group 4 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_5: Bandwidth group 5 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_6: Bandwidth group 6 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_7: Bandwidth group 7 configuration (NLA_U8)
+ * @DCB_PG_ATTR_BWG_MAX: highest attribute number currently defined
+ * @DCB_PG_ATTR_BWG_ALL: apply to all bandwidth groups (NLA_FLAG)
+ *
+ */
+enum dcbnl_pg_attrs {
+ DCB_PG_ATTR_UNDEFINED,
+
+ DCB_PG_ATTR_TC_0,
+ DCB_PG_ATTR_TC_1,
+ DCB_PG_ATTR_TC_2,
+ DCB_PG_ATTR_TC_3,
+ DCB_PG_ATTR_TC_4,
+ DCB_PG_ATTR_TC_5,
+ DCB_PG_ATTR_TC_6,
+ DCB_PG_ATTR_TC_7,
+ DCB_PG_ATTR_TC_MAX,
+ DCB_PG_ATTR_TC_ALL,
+
+ DCB_PG_ATTR_BWG_0,
+ DCB_PG_ATTR_BWG_1,
+ DCB_PG_ATTR_BWG_2,
+ DCB_PG_ATTR_BWG_3,
+ DCB_PG_ATTR_BWG_4,
+ DCB_PG_ATTR_BWG_5,
+ DCB_PG_ATTR_BWG_6,
+ DCB_PG_ATTR_BWG_7,
+ DCB_PG_ATTR_BWG_MAX,
+ DCB_PG_ATTR_BWG_ALL,
+
+ __DCB_PG_ATTR_ENUM_MAX,
+ DCB_PG_ATTR_MAX = __DCB_PG_ATTR_ENUM_MAX - 1,
+};
+
+/**
+ * enum dcbnl_tc_attrs - DCB Traffic Class attributes
+ *
+ * @DCB_TC_ATTR_PARAM_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_TC_ATTR_PARAM_STRICT_PRIO: Type of strict bandwidth aggregration (link
+ * strict or group strict) (NLA_U8)
+ * @DCB_TC_ATTR_PARAM_BW_GROUP_ID: Bandwidth group this traffic class belongs to
+ * (NLA_U8)
+ * @DCB_TC_ATTR_PARAM_BW_PCT: Percentage of bandwidth in the bandwidth group
+ * this traffic class has (NLA_U8)
+ * @DCB_TC_ATTR_PARAM_UP_MAPPING: Traffic class to user priority map (NLA_U8)
+ * @DCB_TC_ATTR_PARAM_ALL: apply to all traffic class parameters (NLA_FLAG)
+ *
+ */
+enum dcbnl_tc_attrs {
+ DCB_TC_ATTR_PARAM_UNDEFINED,
+
+ DCB_TC_ATTR_PARAM_STRICT_PRIO,
+ DCB_TC_ATTR_PARAM_BW_GROUP_ID,
+ DCB_TC_ATTR_PARAM_BW_PCT,
+ DCB_TC_ATTR_PARAM_UP_MAPPING,
+ DCB_TC_ATTR_PARAM_ALL,
+
+ __DCB_TC_ATTR_PARAM_ENUM_MAX,
+ DCB_TC_ATTR_PARAM_MAX = __DCB_TC_ATTR_PARAM_ENUM_MAX - 1,
+};
+
+/*
+ * Ops struct for the netlink callbacks. Used by DCB-enabled drivers through
+ * the netdevice struct.
+ */
+struct dcbnl_genl_ops {
+ u8 (*getstate)(struct net_device *);
+ void (*setstate)(struct net_device *, u8);
+ void (*getpermhwaddr)(struct net_device *, u8 *);
+ void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8);
+ void (*setpgbwgcfgtx)(struct net_device *, int, u8);
+ void (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8);
+ void (*setpgbwgcfgrx)(struct net_device *, int, u8);
+ void (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *);
+ void (*getpgbwgcfgtx)(struct net_device *, int, u8 *);
+ void (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *);
+ void (*getpgbwgcfgrx)(struct net_device *, int, u8 *);
+ void (*setpfccfg)(struct net_device *, int, u8);
+ void (*getpfccfg)(struct net_device *, int, u8 *);
+ u8 (*setall)(struct net_device *);
+};
+
+#endif /* __LINUX_DCBNL_H__ */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f27fd20..f28a1fa 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -42,6 +42,9 @@
#include <linux/workqueue.h>
#include <net/net_namespace.h>
+#ifdef CONFIG_DCBNL
+#include <linux/dcbnl.h>
+#endif
struct vlan_group;
struct ethtool_ops;
@@ -752,6 +755,11 @@ struct net_device
#define GSO_MAX_SIZE 65536
unsigned int gso_max_size;
+#ifdef CONFIG_DCBNL
+ /* Data Center Bridging netlink ops */
+ struct dcbnl_genl_ops *dcbnl_ops;
+#endif
+
/* The TX queue control structures */
unsigned int egress_subqueue_count;
struct net_device_subqueue egress_subqueue[1];
diff --git a/net/Kconfig b/net/Kconfig
index acbf7c6..fc6b832 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -192,6 +192,7 @@ source "net/lapb/Kconfig"
source "net/econet/Kconfig"
source "net/wanrouter/Kconfig"
source "net/sched/Kconfig"
+source "net/dcb/Kconfig"
menu "Network testing"
diff --git a/net/Makefile b/net/Makefile
index b7a1364..bc43e77 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -53,6 +53,9 @@ obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
obj-$(CONFIG_RFKILL) += rfkill/
obj-$(CONFIG_NET_9P) += 9p/
+ifeq ($(CONFIG_DCBNL),y)
+obj-$(CONFIG_DCB) += dcb/
+endif
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/dcb/Kconfig b/net/dcb/Kconfig
new file mode 100644
index 0000000..bdf3880
--- /dev/null
+++ b/net/dcb/Kconfig
@@ -0,0 +1,12 @@
+config DCB
+ tristate "Data Center Bridging support"
+
+config DCBNL
+ bool "Data Center Bridging netlink interface support"
+ depends on DCB
+ default n
+ ---help---
+ This option turns on the netlink interface
+ (dcbnl) for Data Center Bridging capable devices.
+
+ If unsure, say N.
diff --git a/net/dcb/Makefile b/net/dcb/Makefile
new file mode 100644
index 0000000..9930f4c
--- /dev/null
+++ b/net/dcb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DCB) += dcbnl.o
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
new file mode 100644
index 0000000..f5f4c31
--- /dev/null
+++ b/net/dcb/dcbnl.c
@@ -0,0 +1,722 @@
+/*
+ * This is the Data Center Bridging configuration interface.
+ *
+ * Copyright 2008, Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com>
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <net/genetlink.h>
+#include <linux/dcbnl.h>
+
+MODULE_AUTHOR("Peter P Waskiewicz Jr, <peter.p.waskiewicz.jr@intel.com>");
+MODULE_DESCRIPTION("Data Center Bridging generic netlink interface");
+MODULE_LICENSE("GPL");
+
+/* The family */
+static struct genl_family dcbnl_family = {
+ .id = GENL_ID_GENERATE,
+ .hdrsize = 0,
+ .name = "dcbnl",
+ .version = DCB_PROTO_VERSION,
+ .maxattr = DCB_ATTR_MAX,
+};
+
+/* DCB netlink attributes policy */
+static struct nla_policy dcbnl_genl_policy[DCB_ATTR_MAX + 1] = {
+ [DCB_ATTR_IFNAME] = {.type = NLA_STRING, .len = IFNAMSIZ - 1},
+ [DCB_ATTR_STATE] = {.type = NLA_U8},
+ [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED},
+ [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED},
+ [DCB_ATTR_SET_ALL] = {.type = NLA_U8},
+ [DCB_ATTR_PERM_HWADDR] = {.type = NLA_NESTED},
+};
+
+/* DCB permanent hardware address nested attributes */
+static struct nla_policy dcbnl_perm_hwaddr_nest[DCB_PERM_HW_ATTR_MAX + 1] = {
+ [DCB_PERM_HW_ATTR_0] = {.type = NLA_U8},
+ [DCB_PERM_HW_ATTR_1] = {.type = NLA_U8},
+ [DCB_PERM_HW_ATTR_2] = {.type = NLA_U8},
+ [DCB_PERM_HW_ATTR_3] = {.type = NLA_U8},
+ [DCB_PERM_HW_ATTR_4] = {.type = NLA_U8},
+ [DCB_PERM_HW_ATTR_5] = {.type = NLA_U8},
+ [DCB_PERM_HW_ATTR_ALL] = {.type = NLA_FLAG},
+};
+
+/* DCB priority flow control to User Priority nested attributes */
+static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
+ [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8},
+ [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG},
+};
+
+/* DCB priority grouping nested attributes */
+static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
+ [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED},
+ [DCB_PG_ATTR_BWG_0] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_1] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_2] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_3] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_4] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_5] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_6] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_7] = {.type = NLA_U8},
+ [DCB_PG_ATTR_BWG_ALL]= {.type = NLA_FLAG},
+};
+
+/* DCB traffic class nested attributes. */
+static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
+ [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
+ [DCB_TC_ATTR_PARAM_BW_GROUP_ID] = {.type = NLA_U8},
+ [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8},
+ [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
+ [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
+};
+
+/* standard netlink reply call */
+static int dcbnl_reply(u8 value, u8 cmd, u8 attr, struct genl_info *info)
+{
+ struct sk_buff *dcbnl_skb;
+ void *data;
+ int ret = -EINVAL;
+
+ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!dcbnl_skb)
+ return ret;
+
+ data = genlmsg_put_reply(dcbnl_skb, info, &dcbnl_family, 0, cmd);
+ if (!data)
+ goto err;
+
+ ret = nla_put_u8(dcbnl_skb, attr, value);
+ if (ret)
+ goto err;
+
+ /* end the message, assign the nlmsg_len. */
+ genlmsg_end(dcbnl_skb, data);
+ ret = genlmsg_reply(dcbnl_skb, info);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ kfree(dcbnl_skb);
+ return ret;
+}
+
+static int dcbnl_getstate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net_device *netdev;
+ int ret = -EINVAL;
+
+ if (!info->attrs[DCB_ATTR_IFNAME])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops || !netdev->dcbnl_ops->getstate)
+ goto err;
+
+ ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev),
+ DCB_CMD_GSTATE, DCB_ATTR_STATE, info);
+err:
+ dev_put(netdev);
+ return ret;
+}
+
+static int dcbnl_setstate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net_device *netdev;
+ int ret = -EINVAL;
+ u8 value;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_STATE])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops || !netdev->dcbnl_ops->setstate)
+ goto err;
+
+ value = nla_get_u8(info->attrs[DCB_ATTR_STATE]);
+
+ netdev->dcbnl_ops->setstate(netdev, value);
+
+ ret = dcbnl_reply(0, DCB_CMD_SSTATE, DCB_ATTR_STATE, info);
+err:
+ dev_put(netdev);
+ return ret;
+}
+
+static int dcbnl_getperm_hwaddr(struct sk_buff *skb, struct genl_info *info)
+{
+ void *data;
+ struct sk_buff *dcbnl_skb;
+ struct nlattr *tb[DCB_PERM_HW_ATTR_MAX + 1], *nest;
+ struct net_device *netdev;
+ u8 perm_addr[MAX_ADDR_LEN];
+ int ret = -EINVAL;
+ int i;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_PERM_HWADDR])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops || !netdev->dcbnl_ops->getpermhwaddr)
+ goto err_out;
+
+ ret = nla_parse_nested(tb, DCB_PERM_HW_ATTR_MAX,
+ info->attrs[DCB_ATTR_PERM_HWADDR],
+ dcbnl_perm_hwaddr_nest);
+ if (ret)
+ goto err_out;
+
+ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!dcbnl_skb)
+ goto err_out;
+
+ data = genlmsg_put_reply(dcbnl_skb, info, &dcbnl_family, 0,
+ DCB_CMD_GPERM_HWADDR);
+ if (!data)
+ goto err;
+
+ nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PERM_HWADDR);
+ if (!nest)
+ goto err;
+
+ netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr);
+ for (i = 0; i < netdev->addr_len; i++) {
+ ret = nla_put_u8(dcbnl_skb, DCB_ATTR_PERM_HWADDR,
+ perm_addr[i]);
+
+ if (ret) {
+ nla_nest_cancel(dcbnl_skb, nest);
+ goto err;
+ }
+ }
+
+ nla_nest_end(dcbnl_skb, nest);
+
+ genlmsg_end(dcbnl_skb, data);
+
+ ret = genlmsg_reply(dcbnl_skb, info);
+ if (ret)
+ goto err_out;
+
+ dev_put(netdev);
+ return 0;
+err:
+ kfree(dcbnl_skb);
+err_out:
+ dev_put(netdev);
+ return ret;
+}
+
+static int __dcbnl_pg_setcfg(struct genl_info *info, int dir)
+{
+ struct net_device *netdev = NULL;
+ struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
+ struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
+ int ret = -EINVAL;
+ int i;
+ u8 prio = 0, bwg_id = 0, bw_pct = 0, up_map = 0;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_PG_CFG])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops ||
+ !netdev->dcbnl_ops->setpgtccfgtx ||
+ !netdev->dcbnl_ops->setpgtccfgrx ||
+ !netdev->dcbnl_ops->setpgbwgcfgtx ||
+ !netdev->dcbnl_ops->setpgbwgcfgrx)
+ goto err;
+
+ ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
+ info->attrs[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
+ if (ret)
+ goto err;
+
+ for (i = DCB_PG_ATTR_TC_0; i < DCB_PG_ATTR_TC_MAX; i++) {
+ if (!pg_tb[i])
+ continue;
+
+ ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
+ pg_tb[i], dcbnl_tc_param_nest);
+ if (ret)
+ goto err;
+
+ if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO])
+ prio =
+ nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]);
+
+ if (param_tb[DCB_TC_ATTR_PARAM_BW_GROUP_ID])
+ bwg_id =
+ nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_GROUP_ID]);
+
+ if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT])
+ bw_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]);
+
+ if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING])
+ up_map =
+ nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]);
+
+ /* dir: Tx = 0, Rx = 1 */
+ if (dir) {
+ /* Rx */
+ netdev->dcbnl_ops->setpgtccfgrx(netdev,
+ i - DCB_PG_ATTR_TC_0,
+ prio, bwg_id, bw_pct, up_map);
+ } else {
+ /* Tx */
+ netdev->dcbnl_ops->setpgtccfgtx(netdev,
+ i - DCB_PG_ATTR_TC_0,
+ prio, bwg_id, bw_pct, up_map);
+ }
+ }
+
+ for (i = DCB_PG_ATTR_BWG_0; i < DCB_PG_ATTR_BWG_MAX; i++) {
+ if (!pg_tb[i])
+ continue;
+
+ bw_pct = nla_get_u8(pg_tb[i]);
+
+ /* dir: Tx = 0, Rx = 1 */
+ if (dir) {
+ /* Rx */
+ netdev->dcbnl_ops->setpgbwgcfgrx(netdev,
+ i - DCB_PG_ATTR_BWG_0, bw_pct);
+ } else {
+ /* Tx */
+ netdev->dcbnl_ops->setpgbwgcfgtx(netdev,
+ i - DCB_PG_ATTR_BWG_0, bw_pct);
+ }
+ }
+
+ ret = dcbnl_reply(0, (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG),
+ DCB_ATTR_PG_CFG, info);
+
+err:
+ dev_put(netdev);
+ return ret;
+}
+
+static int dcbnl_pgtx_setcfg(struct sk_buff *skb, struct genl_info *info)
+{
+ return __dcbnl_pg_setcfg(info, 0);
+}
+
+static int dcbnl_pgrx_setcfg(struct sk_buff *skb, struct genl_info *info)
+{
+ return __dcbnl_pg_setcfg(info, 1);
+}
+
+static int __dcbnl_pg_getcfg(struct genl_info *info, int dir)
+{
+ void *data;
+ struct sk_buff *dcbnl_skb;
+ struct nlattr *pg_nest, *param_nest, *tb;
+ struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1];
+ struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1];
+ struct net_device *netdev;
+ u8 prio, bwg_id, bw_pct, up_map;
+ int ret = -EINVAL;
+ int i;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_PG_CFG])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops ||
+ !netdev->dcbnl_ops->getpgtccfgtx ||
+ !netdev->dcbnl_ops->getpgtccfgrx ||
+ !netdev->dcbnl_ops->getpgbwgcfgtx ||
+ !netdev->dcbnl_ops->getpgbwgcfgrx)
+ goto err_out;
+
+ ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX,
+ info->attrs[DCB_ATTR_PG_CFG], dcbnl_pg_nest);
+ if (ret)
+ goto err_out;
+
+ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!dcbnl_skb)
+ goto err_out;
+
+ data = genlmsg_put_reply(dcbnl_skb, info, &dcbnl_family, 0,
+ (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG);
+
+ if (!data)
+ goto err;
+
+ pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG);
+ if (!pg_nest)
+ goto err;
+
+ for (i = DCB_PG_ATTR_TC_0; i < DCB_PG_ATTR_TC_MAX; i++) {
+ if (pg_tb[DCB_PG_ATTR_TC_ALL])
+ tb = pg_tb[DCB_PG_ATTR_TC_ALL];
+ else
+ tb = pg_tb[i];
+ ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX,
+ tb, dcbnl_tc_param_nest);
+ if (ret)
+ goto err_pg;
+
+ param_nest = nla_nest_start(dcbnl_skb, i);
+ if (!param_nest)
+ goto err_pg;
+
+ if (dir) {
+ /* Rx */
+ netdev->dcbnl_ops->getpgtccfgrx(netdev,
+ i - DCB_PG_ATTR_TC_0, &prio,
+ &bwg_id, &bw_pct, &up_map);
+ } else {
+ /* Tx */
+ netdev->dcbnl_ops->getpgtccfgtx(netdev,
+ i - DCB_PG_ATTR_TC_0, &prio,
+ &bwg_id, &bw_pct, &up_map);
+ }
+
+ if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] ||
+ param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+ ret = nla_put_u8(dcbnl_skb,
+ DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
+ if (ret)
+ goto err_param;
+ }
+ if (param_tb[DCB_TC_ATTR_PARAM_BW_GROUP_ID] ||
+ param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+ ret = nla_put_u8(dcbnl_skb,
+ DCB_TC_ATTR_PARAM_BW_GROUP_ID, bwg_id);
+ if (ret)
+ goto err_param;
+ }
+ if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] ||
+ param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+ ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT,
+ bw_pct);
+ if (ret)
+ goto err_param;
+ }
+ if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] ||
+ param_tb[DCB_TC_ATTR_PARAM_ALL]) {
+ ret = nla_put_u8(dcbnl_skb,
+ DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
+ if (ret)
+ goto err_param;
+ }
+ nla_nest_end(dcbnl_skb, param_nest);
+ }
+
+ for (i = DCB_PG_ATTR_BWG_0; i < DCB_PG_ATTR_BWG_MAX; i++) {
+ if (dir) {
+ /* Rx */
+ netdev->dcbnl_ops->getpgbwgcfgrx(netdev,
+ i - DCB_PG_ATTR_BWG_0, &bw_pct);
+ } else {
+ /* Tx */
+ netdev->dcbnl_ops->getpgbwgcfgtx(netdev,
+ i - DCB_PG_ATTR_BWG_0, &bw_pct);
+ }
+ ret = nla_put_u8(dcbnl_skb, i, bw_pct);
+
+ if (ret)
+ goto err_pg;
+ }
+
+ nla_nest_end(dcbnl_skb, pg_nest);
+
+ genlmsg_end(dcbnl_skb, data);
+ ret = genlmsg_reply(dcbnl_skb, info);
+ if (ret)
+ goto err;
+
+ dev_put(netdev);
+ return 0;
+
+err_param:
+ nla_nest_cancel(dcbnl_skb, param_nest);
+err_pg:
+ nla_nest_cancel(dcbnl_skb, pg_nest);
+err:
+ kfree(dcbnl_skb);
+err_out:
+ dev_put(netdev);
+ return ret;
+}
+
+static int dcbnl_pgtx_getcfg(struct sk_buff *skb, struct genl_info *info)
+{
+ return __dcbnl_pg_getcfg(info, 0);
+}
+
+static int dcbnl_pgrx_getcfg(struct sk_buff *skb, struct genl_info *info)
+{
+ return __dcbnl_pg_getcfg(info, 1);
+}
+
+static int dcbnl_setpfccfg(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nlattr *tb[DCB_PFC_UP_ATTR_MAX + 1];
+ struct net_device *netdev;
+ int i;
+ int ret = -EINVAL;
+ u8 value;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_PFC_CFG])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops || !netdev->dcbnl_ops->setpfccfg)
+ goto err;
+
+ ret = nla_parse_nested(tb, DCB_PFC_UP_ATTR_MAX,
+ info->attrs[DCB_ATTR_PFC_CFG],
+ dcbnl_pfc_up_nest);
+ if (ret)
+ goto err;
+
+ for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) {
+ value = nla_get_u8(tb[i]);
+ netdev->dcbnl_ops->setpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
+ value);
+ }
+
+ ret = dcbnl_reply(0, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, info);
+err:
+ dev_put(netdev);
+ return ret;
+}
+
+static int dcbnl_getpfccfg(struct sk_buff *skb, struct genl_info *info)
+{
+ void *data;
+ struct sk_buff *dcbnl_skb;
+ struct nlattr *tb[DCB_PFC_UP_ATTR_MAX + 1], *nest;
+ struct net_device *netdev;
+ u8 value;
+ int ret = -EINVAL;
+ int i;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_PFC_CFG])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops || !netdev->dcbnl_ops->getpfccfg)
+ goto err_out;
+
+ ret = nla_parse_nested(tb, DCB_PFC_UP_ATTR_MAX,
+ info->attrs[DCB_ATTR_PFC_CFG],
+ dcbnl_pfc_up_nest);
+ if (ret)
+ goto err_out;
+
+ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!dcbnl_skb)
+ goto err_out;
+
+ data = genlmsg_put_reply(dcbnl_skb, info, &dcbnl_family, 0,
+ DCB_CMD_PFC_GCFG);
+ if (!data)
+ goto err;
+
+ nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG);
+ if (!nest)
+ goto err;
+
+ for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) {
+ netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0,
+ &value);
+ ret = nla_put_u8(dcbnl_skb, i, value);
+
+ if (ret) {
+ nla_nest_cancel(dcbnl_skb, nest);
+ goto err;
+ }
+ }
+ nla_nest_end(dcbnl_skb, nest);
+
+ genlmsg_end(dcbnl_skb, data);
+
+ ret = genlmsg_reply(dcbnl_skb, info);
+ if (ret)
+ goto err;
+
+ dev_put(netdev);
+ return 0;
+
+err:
+ kfree(dcbnl_skb);
+err_out:
+ dev_put(netdev);
+ return ret;
+}
+
+static int dcbnl_setall(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net_device *netdev;
+ int ret = -EINVAL;
+
+ if (!info->attrs[DCB_ATTR_IFNAME] || !info->attrs[DCB_ATTR_SET_ALL])
+ return ret;
+
+ netdev = dev_get_by_name(&init_net,
+ nla_data(info->attrs[DCB_ATTR_IFNAME]));
+ if (!netdev)
+ return ret;
+
+ if (!netdev->dcbnl_ops || !netdev->dcbnl_ops->setall)
+ return ret;
+
+ ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), DCB_CMD_SET_ALL,
+ DCB_ATTR_SET_ALL, info);
+
+ dev_put(netdev);
+ return ret;
+}
+
+static struct genl_ops dcbnl_ops[] = {
+ {
+ .cmd = DCB_CMD_GSTATE,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_getstate,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_SSTATE,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_setstate,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_PGTX_SCFG,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_pgtx_setcfg,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_PGRX_SCFG,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_pgrx_setcfg,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_PFC_SCFG,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_setpfccfg,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_PGTX_GCFG,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_pgtx_getcfg,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_PGRX_GCFG,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_pgrx_getcfg,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_PFC_GCFG,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_getpfccfg,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_SET_ALL,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_setall,
+ .dumpit = NULL,
+ },
+ {
+ .cmd = DCB_CMD_GPERM_HWADDR,
+ .flags = GENL_ADMIN_PERM,
+ .policy = dcbnl_genl_policy,
+ .doit = dcbnl_getperm_hwaddr,
+ .dumpit = NULL,
+ },
+};
+
+/* init and exit */
+static int __init dcbnl_init(void)
+{
+ int err, i;
+
+ err = genl_register_family(&dcbnl_family);
+ if (err)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(dcbnl_ops); i++) {
+ err = genl_register_ops(&dcbnl_family, &dcbnl_ops[i]);
+ if (err)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ genl_unregister_family(&dcbnl_family);
+ return err;
+}
+module_init(dcbnl_init);
+
+static void __exit dcbnl_exit(void)
+{
+ genl_unregister_family(&dcbnl_family);
+}
+module_exit(dcbnl_exit);
next prev parent reply other threads:[~2008-05-27 21:13 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-27 14:13 [PATCH] NET: DCB generic netlink interface PJ Waskiewicz
2008-05-27 14:13 ` PJ Waskiewicz [this message]
2008-05-28 9:41 ` [PATCH 1/3] [NET-NEXT]: Add DCB netlink interface definition Thomas Graf
2008-05-28 16:03 ` Waskiewicz Jr, Peter P
2008-05-28 22:37 ` Thomas Graf
2008-06-01 12:16 ` Waskiewicz Jr, Peter P
2008-06-05 13:17 ` Patrick McHardy
2008-06-09 22:11 ` Waskiewicz Jr, Peter P
2008-06-10 7:14 ` Patrick McHardy
2008-05-27 14:13 ` [PATCH 2/3] ixgbe: Add Data Center Bridging hardware initialization code PJ Waskiewicz
2008-05-27 14:13 ` [PATCH 3/3] ixgbe: Enable Data Center Bridging (DCB) support PJ Waskiewicz
2008-06-04 18:44 ` [PATCH] NET: DCB generic netlink interface David Miller
2008-06-05 6:23 ` Waskiewicz Jr, Peter P
2008-06-05 14:43 ` David Miller
2008-06-05 20:29 ` Thomas Graf
2008-06-10 19:55 ` Waskiewicz Jr, Peter P
2008-06-10 20:07 ` David Miller
2008-06-11 17:51 ` Thomas Graf
2008-06-11 17:50 ` Patrick McHardy
2008-06-11 21:28 ` Thomas Graf
2008-06-12 10:17 ` Patrick McHardy
2008-06-11 18:28 ` Waskiewicz Jr, Peter P
2008-06-11 21:26 ` Thomas Graf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080527141346.12851.2280.stgit@localhost.localdomain \
--to=peter.p.waskiewicz.jr@intel.com \
--cc=davem@davemloft.net \
--cc=jeff@garzik.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).