* [PATCH v1 10/10] IB/ucm: Add partial support for network namespaces
From: Shachar Raindel @ 2015-02-11 15:06 UTC (permalink / raw)
To: roland, sean.hefty
Cc: linux-rdma, netdev, liranl, guysh, haggaie, yotamke, raindel
In-Reply-To: <1423667204-8807-1-git-send-email-raindel@mellanox.com>
It is impossible to completely support network namespaces for UCM, as
we cannot identify the target IPoIB device. However, we add support
which will work if the user is following the IB-Spec Annex 11 (RDMA IP
CM Services) with the service ID and private data formatting.
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Yotam Kenneth <yotamke@mellanox.com>
Signed-off-by: Shachar Raindel <raindel@mellanox.com>
Signed-off-by: Guy Shapiro <guysh@mellanox.com>
---
drivers/infiniband/core/ucm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index 9604ab0..4244210 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -45,6 +45,7 @@
#include <linux/idr.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/nsproxy.h>
#include <asm/uaccess.h>
@@ -490,7 +491,7 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file,
ctx->uid = cmd.uid;
ctx->cm_id = ib_create_cm_id(file->device->ib_dev,
ib_ucm_event_handler, ctx,
- &init_net);
+ current->nsproxy->net_ns);
if (IS_ERR(ctx->cm_id)) {
result = PTR_ERR(ctx->cm_id);
goto err1;
--
1.7.11.2
^ permalink raw reply related
* [PATCH v1 05/10] IB/cm,cma: Move RDMA IP CM private-data parsing code from ib_cma to ib_cm
From: Shachar Raindel @ 2015-02-11 15:06 UTC (permalink / raw)
To: roland, sean.hefty
Cc: linux-rdma, netdev, liranl, guysh, haggaie, yotamke, raindel
In-Reply-To: <1423667204-8807-1-git-send-email-raindel@mellanox.com>
From: Guy Shapiro <guysh@mellanox.com>
When receiving a connection request, ib_cm needs to associate the request with
a network namespace. To do this, it needs to know the request's destination
IP. For this the RDMA IP CM packet formatting functionality needs to be
exposed to ib_cm.
This patch merely moves the RDMA IP CM data formatting and parsing functions
to be part of ib_cm. The following patch will utilize the new knowledge to
look-up the appropriate namespace. Each namespace maintains an independent
table of RDMA CM service IDs, allowing isolation and separation between the
network namespaces.
When creating a new incoming connection ID, the code in cm_save_ip_info can no
longer rely on the listener's private data to find the port number, so it
reads it from the requested service ID. This required saving the service ID in
cm_format_paths_from_req.
Signed-off-by: Guy Shapiro <guysh@mellanox.com>
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Yotam Kenneth <yotamke@mellanox.com>
Signed-off-by: Shachar Raindel <raindel@mellanox.com>
---
drivers/infiniband/core/cm.c | 156 +++++++++++++++++++++++++++++++++++++++
drivers/infiniband/core/cma.c | 166 +++++-------------------------------------
include/rdma/ib_cm.h | 56 ++++++++++++++
3 files changed, 230 insertions(+), 148 deletions(-)
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 5a45cb7..efc5cff 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -51,6 +51,7 @@
#include <rdma/ib_cache.h>
#include <rdma/ib_cm.h>
+#include <rdma/ib.h>
#include "cm_msgs.h"
MODULE_AUTHOR("Sean Hefty");
@@ -701,6 +702,159 @@ static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv,
ib_send_cm_sidr_rep(&cm_id_priv->id, ¶m);
}
+int cm_format_hdr(void *hdr, int family,
+ struct sockaddr *src_addr,
+ struct sockaddr *dst_addr)
+{
+ struct cm_hdr *cm_hdr;
+
+ cm_hdr = hdr;
+ cm_hdr->cm_version = RDMA_IP_CM_VERSION;
+ if (family == AF_INET) {
+ struct sockaddr_in *src4, *dst4;
+
+ src4 = (struct sockaddr_in *)src_addr;
+ dst4 = (struct sockaddr_in *)dst_addr;
+
+ cm_set_ip_ver(cm_hdr, 4);
+ cm_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+ cm_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+ cm_hdr->port = src4->sin_port;
+ } else if (family == AF_INET6) {
+ struct sockaddr_in6 *src6, *dst6;
+
+ src6 = (struct sockaddr_in6 *)src_addr;
+ dst6 = (struct sockaddr_in6 *)dst_addr;
+
+ cm_set_ip_ver(cm_hdr, 6);
+ cm_hdr->src_addr.ip6 = src6->sin6_addr;
+ cm_hdr->dst_addr.ip6 = dst6->sin6_addr;
+ cm_hdr->port = src6->sin6_port;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cm_format_hdr);
+
+static void cm_save_ib_info(struct sockaddr *src_addr,
+ struct sockaddr *dst_addr,
+ struct ib_sa_path_rec *path)
+{
+ struct sockaddr_ib *ib;
+
+ if (src_addr) {
+ ib = (struct sockaddr_ib *)src_addr;
+ ib->sib_family = AF_IB;
+ ib->sib_pkey = path->pkey;
+ ib->sib_flowinfo = path->flow_label;
+ memcpy(&ib->sib_addr, &path->sgid, 16);
+ ib->sib_sid = path->service_id;
+ ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
+ ib->sib_scope_id = 0;
+ }
+ if (dst_addr) {
+ ib = (struct sockaddr_ib *)dst_addr;
+ ib->sib_family = AF_IB;
+ ib->sib_pkey = path->pkey;
+ ib->sib_flowinfo = path->flow_label;
+ memcpy(&ib->sib_addr, &path->dgid, 16);
+ }
+}
+
+static void cm_save_ip6_info(struct sockaddr *src_addr,
+ struct sockaddr *dst_addr,
+ struct cm_hdr *hdr,
+ __be16 local_port)
+{
+ struct sockaddr_in6 *ip6;
+
+ if (src_addr) {
+ ip6 = (struct sockaddr_in6 *)src_addr;
+ ip6->sin6_family = AF_INET6;
+ ip6->sin6_addr = hdr->dst_addr.ip6;
+ ip6->sin6_port = local_port;
+ }
+
+ if (dst_addr) {
+ ip6 = (struct sockaddr_in6 *)dst_addr;
+ ip6->sin6_family = AF_INET6;
+ ip6->sin6_addr = hdr->src_addr.ip6;
+ ip6->sin6_port = hdr->port;
+ }
+}
+
+static void cm_save_ip4_info(struct sockaddr *src_addr,
+ struct sockaddr *dst_addr,
+ struct cm_hdr *hdr,
+ __be16 local_port)
+{
+ struct sockaddr_in *ip4;
+
+ if (src_addr) {
+ ip4 = (struct sockaddr_in *)src_addr;
+ ip4->sin_family = AF_INET;
+ ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
+ ip4->sin_port = local_port;
+ }
+
+ if (dst_addr) {
+ ip4 = (struct sockaddr_in *)dst_addr;
+ ip4->sin_family = AF_INET;
+ ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
+ ip4->sin_port = hdr->port;
+ }
+}
+
+static __be16 cm_port_from_service_id(__be64 service_id)
+{
+ return htons(be64_to_cpu(service_id));
+}
+
+static int cm_save_ip_info(struct sockaddr *src_addr,
+ struct sockaddr *dst_addr,
+ struct cm_work *work)
+{
+ struct cm_hdr *hdr;
+ __be16 port;
+
+ hdr = work->cm_event.private_data;
+ if (hdr->cm_version != RDMA_IP_CM_VERSION)
+ return -EINVAL;
+
+ port = cm_port_from_service_id(work->path->service_id);
+
+ switch (cm_get_ip_ver(hdr)) {
+ case 4:
+ cm_save_ip4_info(src_addr, dst_addr, hdr, port);
+ break;
+ case 6:
+ cm_save_ip6_info(src_addr, dst_addr, hdr, port);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int cm_save_net_info(struct sockaddr *src_addr,
+ struct sockaddr *dst_addr,
+ struct ib_cm_event *ib_event)
+{
+ struct cm_work *work = container_of(ib_event, struct cm_work, cm_event);
+
+ if ((rdma_port_get_link_layer(work->port->cm_dev->ib_device,
+ work->port->port_num) ==
+ IB_LINK_LAYER_INFINIBAND) &&
+ (ib_event->event == IB_CM_REQ_RECEIVED)) {
+ cm_save_ib_info(src_addr, dst_addr,
+ ib_event->param.req_rcvd.primary_path);
+ return 0;
+ }
+
+ return cm_save_ip_info(src_addr, dst_addr, work);
+}
+EXPORT_SYMBOL(cm_save_net_info);
+
struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
ib_cm_handler cm_handler,
void *context)
@@ -1260,6 +1414,7 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
primary_path->packet_life_time =
cm_req_get_primary_local_ack_timeout(req_msg);
primary_path->packet_life_time -= (primary_path->packet_life_time > 0);
+ primary_path->service_id = req_msg->service_id;
if (req_msg->alt_local_lid) {
memset(alt_path, 0, sizeof *alt_path);
@@ -1281,6 +1436,7 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
alt_path->packet_life_time =
cm_req_get_alt_local_ack_timeout(req_msg);
alt_path->packet_life_time -= (alt_path->packet_life_time > 0);
+ alt_path->service_id = req_msg->service_id;
}
}
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index aeb2417..9f6faeb 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -179,23 +179,8 @@ struct iboe_mcast_work {
struct cma_multicast *mc;
};
-union cma_ip_addr {
- struct in6_addr ip6;
- struct {
- __be32 pad[3];
- __be32 addr;
- } ip4;
-};
-struct cma_hdr {
- u8 cma_version;
- u8 ip_version; /* IP version: 7:4 */
- __be16 port;
- union cma_ip_addr src_addr;
- union cma_ip_addr dst_addr;
-};
-#define CMA_VERSION 0x00
static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
{
@@ -234,16 +219,6 @@ static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
return old;
}
-static inline u8 cma_get_ip_ver(struct cma_hdr *hdr)
-{
- return hdr->ip_version >> 4;
-}
-
-static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
-{
- hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
-}
-
static void cma_attach_to_dev(struct rdma_id_private *id_priv,
struct cma_device *cma_dev)
{
@@ -839,93 +814,9 @@ static inline int cma_any_port(struct sockaddr *addr)
return !cma_port(addr);
}
-static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
- struct ib_sa_path_rec *path)
-{
- struct sockaddr_ib *listen_ib, *ib;
-
- listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr;
- ib = (struct sockaddr_ib *) &id->route.addr.src_addr;
- ib->sib_family = listen_ib->sib_family;
- ib->sib_pkey = path->pkey;
- ib->sib_flowinfo = path->flow_label;
- memcpy(&ib->sib_addr, &path->sgid, 16);
- ib->sib_sid = listen_ib->sib_sid;
- ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
- ib->sib_scope_id = listen_ib->sib_scope_id;
-
- ib = (struct sockaddr_ib *) &id->route.addr.dst_addr;
- ib->sib_family = listen_ib->sib_family;
- ib->sib_pkey = path->pkey;
- ib->sib_flowinfo = path->flow_label;
- memcpy(&ib->sib_addr, &path->dgid, 16);
-}
-
-static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
- struct cma_hdr *hdr)
-{
- struct sockaddr_in *listen4, *ip4;
-
- listen4 = (struct sockaddr_in *) &listen_id->route.addr.src_addr;
- ip4 = (struct sockaddr_in *) &id->route.addr.src_addr;
- ip4->sin_family = AF_INET;
- ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
- ip4->sin_port = listen4->sin_port;
-
- ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr;
- ip4->sin_family = AF_INET;
- ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
- ip4->sin_port = hdr->port;
-}
-
-static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
- struct cma_hdr *hdr)
-{
- struct sockaddr_in6 *listen6, *ip6;
-
- listen6 = (struct sockaddr_in6 *) &listen_id->route.addr.src_addr;
- ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr;
- ip6->sin6_family = AF_INET6;
- ip6->sin6_addr = hdr->dst_addr.ip6;
- ip6->sin6_port = listen6->sin6_port;
-
- ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr;
- ip6->sin6_family = AF_INET6;
- ip6->sin6_addr = hdr->src_addr.ip6;
- ip6->sin6_port = hdr->port;
-}
-
-static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id,
- struct ib_cm_event *ib_event)
-{
- struct cma_hdr *hdr;
-
- if ((listen_id->route.addr.src_addr.ss_family == AF_IB) &&
- (ib_event->event == IB_CM_REQ_RECEIVED)) {
- cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
- return 0;
- }
-
- hdr = ib_event->private_data;
- if (hdr->cma_version != CMA_VERSION)
- return -EINVAL;
-
- switch (cma_get_ip_ver(hdr)) {
- case 4:
- cma_save_ip4_info(id, listen_id, hdr);
- break;
- case 6:
- cma_save_ip6_info(id, listen_id, hdr);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static inline int cma_user_data_offset(struct rdma_id_private *id_priv)
{
- return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
+ return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cm_hdr);
}
static void cma_cancel_route(struct rdma_id_private *id_priv)
@@ -1195,7 +1086,9 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
return NULL;
id_priv = container_of(id, struct rdma_id_private, id);
- if (cma_save_net_info(id, listen_id, ib_event))
+ if (cm_save_net_info((struct sockaddr *)&id->route.addr.src_addr,
+ (struct sockaddr *)&id->route.addr.dst_addr,
+ ib_event))
goto err;
rt = &id->route;
@@ -1241,7 +1134,9 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
return NULL;
id_priv = container_of(id, struct rdma_id_private, id);
- if (cma_save_net_info(id, listen_id, ib_event))
+ if (cm_save_net_info((struct sockaddr *)&id->route.addr.src_addr,
+ (struct sockaddr *)&id->route.addr.dst_addr,
+ ib_event))
goto err;
if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
@@ -1369,7 +1264,7 @@ EXPORT_SYMBOL(rdma_get_service_id);
static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
struct ib_cm_compare_data *compare)
{
- struct cma_hdr *cma_data, *cma_mask;
+ struct cm_hdr *cma_data, *cma_mask;
__be32 ip4_addr;
struct in6_addr ip6_addr;
@@ -1380,8 +1275,8 @@ static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
switch (addr->sa_family) {
case AF_INET:
ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
- cma_set_ip_ver(cma_data, 4);
- cma_set_ip_ver(cma_mask, 0xF);
+ cm_set_ip_ver(cma_data, 4);
+ cm_set_ip_ver(cma_mask, 0xF);
if (!cma_any_addr(addr)) {
cma_data->dst_addr.ip4.addr = ip4_addr;
cma_mask->dst_addr.ip4.addr = htonl(~0);
@@ -1389,8 +1284,8 @@ static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
break;
case AF_INET6:
ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr;
- cma_set_ip_ver(cma_data, 6);
- cma_set_ip_ver(cma_mask, 0xF);
+ cm_set_ip_ver(cma_data, 6);
+ cm_set_ip_ver(cma_mask, 0xF);
if (!cma_any_addr(addr)) {
cma_data->dst_addr.ip6 = ip6_addr;
memset(&cma_mask->dst_addr.ip6, 0xFF,
@@ -2615,35 +2510,6 @@ err1:
}
EXPORT_SYMBOL(rdma_bind_addr);
-static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
-{
- struct cma_hdr *cma_hdr;
-
- cma_hdr = hdr;
- cma_hdr->cma_version = CMA_VERSION;
- if (cma_family(id_priv) == AF_INET) {
- struct sockaddr_in *src4, *dst4;
-
- src4 = (struct sockaddr_in *) cma_src_addr(id_priv);
- dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv);
-
- cma_set_ip_ver(cma_hdr, 4);
- cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
- cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
- cma_hdr->port = src4->sin_port;
- } else if (cma_family(id_priv) == AF_INET6) {
- struct sockaddr_in6 *src6, *dst6;
-
- src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
- dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv);
-
- cma_set_ip_ver(cma_hdr, 6);
- cma_hdr->src_addr.ip6 = src6->sin6_addr;
- cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
- cma_hdr->port = src6->sin6_port;
- }
- return 0;
-}
static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
struct ib_cm_event *ib_event)
@@ -2731,7 +2597,9 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
conn_param->private_data_len);
if (private_data) {
- ret = cma_format_hdr(private_data, id_priv);
+ ret = cm_format_hdr(private_data, cma_family(id_priv),
+ cma_src_addr(id_priv),
+ cma_dst_addr(id_priv));
if (ret)
goto out;
req.private_data = private_data;
@@ -2796,7 +2664,9 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
route = &id_priv->id.route;
if (private_data) {
- ret = cma_format_hdr(private_data, id_priv);
+ ret = cm_format_hdr(private_data, cma_family(id_priv),
+ cma_src_addr(id_priv),
+ cma_dst_addr(id_priv));
if (ret)
goto out;
req.private_data = private_data;
diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h
index 0e3ff30..0e49933 100644
--- a/include/rdma/ib_cm.h
+++ b/include/rdma/ib_cm.h
@@ -274,6 +274,62 @@ struct ib_cm_event {
#define CM_LAP_ATTR_ID cpu_to_be16(0x0019)
#define CM_APR_ATTR_ID cpu_to_be16(0x001A)
+union cm_ip_addr {
+ struct in6_addr ip6;
+ struct {
+ __be32 pad[3];
+ __be32 addr;
+ } ip4;
+};
+
+struct cm_hdr {
+ u8 cm_version;
+ u8 ip_version; /* IP version: 7:4 */
+ __be16 port;
+ union cm_ip_addr src_addr;
+ union cm_ip_addr dst_addr;
+};
+
+#define RDMA_IP_CM_VERSION 0x00
+
+static inline u8 cm_get_ip_ver(struct cm_hdr *hdr)
+{
+ return hdr->ip_version >> 4;
+}
+
+static inline void cm_set_ip_ver(struct cm_hdr *hdr, u8 ip_ver)
+{
+ hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
+}
+
+/**
+ * cm_format_hdr - Fill in a cm_hdr struct according to connection details
+ * @hdr: cm_hdr struct to fill
+ * @family: ip family of the addresses - AF_INET or AF_INTET6
+ * @src_addr: source address of the connection
+ * @dst_addr: destination address of the connection
+ **/
+int cm_format_hdr(void *hdr, int family,
+ struct sockaddr *src_addr,
+ struct sockaddr *dst_addr);
+
+/**
+ * cm_save_net_info - saves ib connection event details
+ * @src_addr: source address of the connection
+ * @dst_addr: destination address of the connection
+ * @ib_event: ib event to take connection details from
+ **/
+int cm_save_net_info(struct sockaddr *src_addr,
+ struct sockaddr *dst_addr,
+ struct ib_cm_event *ib_event);
+
+/**
+ * cm_set_ip_ver - sets the ip version of a cm_hdr struct
+ * @hdr: cm_hdr struct to change
+ * @ip_ver: ip version to set - a 4 bit value
+ **/
+void cm_set_ip_ver(struct cm_hdr *hdr, u8 ip_ver);
+
/**
* ib_cm_handler - User-defined callback to process communication events.
* @cm_id: Communication identifier associated with the reported event.
--
1.7.11.2
^ permalink raw reply related
* [PATCH net 1/1] qlcnic: Delete existing multicast MAC list before adding new
From: Shahed Shaikh @ 2015-02-11 14:45 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept-GELinuxNICDev, Shahed Shaikh
From: Shahed Shaikh <shahed.shaikh@qlogic.com>
Driver keeps adding multicast addresses without deleting removed MACs and
worrying about adapters filter limit. This results into actual count of programmed
multicast addresses get accumulated over the time and overruns the adapter's
filter limit without putting device in ACCEPT_ALL_MULTI mode. This causes
newly added multicast traffic to fail after the sequence of addition - deletion
in certain pattern.
This issue is seen only when netdev's mcast list count is less than adapters
mcast filter limit.
e.g. If adapters multicast filter limit is 38 per function
then following sequence would result in multicast traffic failure for
newly added MACs.
- add less than 38 multicast MACs
- remove previously added multicast MACs
- add new multicast MACs (less than 38)
Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
---
Hi Dave,
please apply this patch to net.
Thanks,
Shahed
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 11 ++++++-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 34 +++++++++++++++++---
.../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 19 +++++++----
3 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index e56c1bb..fa43176 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -848,10 +848,17 @@ struct qlcnic_cardrsp_tx_ctx {
#define QLCNIC_MAC_VLAN_ADD 3
#define QLCNIC_MAC_VLAN_DEL 4
+enum qlcnic_mac_type {
+ QLCNIC_UNICAST_MAC,
+ QLCNIC_MULTICAST_MAC,
+ QLCNIC_BROADCAST_MAC,
+};
+
struct qlcnic_mac_vlan_list {
struct list_head list;
uint8_t mac_addr[ETH_ALEN+2];
u16 vlan_id;
+ enum qlcnic_mac_type mac_type;
};
/* MAC Learn */
@@ -1615,7 +1622,9 @@ void qlcnic_watchdog_task(struct work_struct *work);
void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
struct qlcnic_host_rds_ring *rds_ring, u8 ring_id);
void qlcnic_set_multi(struct net_device *netdev);
-int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16);
+void qlcnic_flush_mcast_mac(struct qlcnic_adapter *);
+int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16,
+ enum qlcnic_mac_type);
int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter);
int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 69b46c0..3e0f705 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -487,7 +487,8 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
return err;
}
-int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
+int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan,
+ enum qlcnic_mac_type mac_type)
{
struct qlcnic_mac_vlan_list *cur;
struct list_head *head;
@@ -513,10 +514,29 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
}
cur->vlan_id = vlan;
+ cur->mac_type = mac_type;
+
list_add_tail(&cur->list, &adapter->mac_list);
return 0;
}
+void qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_mac_vlan_list *cur;
+ struct list_head *head, *tmp;
+
+ list_for_each_safe(head, tmp, &adapter->mac_list) {
+ cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
+ if (cur->mac_type != QLCNIC_MULTICAST_MAC)
+ continue;
+
+ qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+ cur->vlan_id, QLCNIC_MAC_DEL);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+}
+
static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -530,8 +550,9 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
- qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan);
- qlcnic_nic_add_mac(adapter, bcast_addr, vlan);
+ qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan,
+ QLCNIC_UNICAST_MAC);
+ qlcnic_nic_add_mac(adapter, bcast_addr, vlan, QLCNIC_BROADCAST_MAC);
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
@@ -540,8 +561,10 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else if (!netdev_mc_empty(netdev)) {
+ qlcnic_flush_mcast_mac(adapter);
netdev_for_each_mc_addr(ha, netdev)
- qlcnic_nic_add_mac(adapter, ha->addr, vlan);
+ qlcnic_nic_add_mac(adapter, ha->addr, vlan,
+ QLCNIC_MULTICAST_MAC);
}
/* configure unicast MAC address, if there is not sufficient space
@@ -551,7 +574,8 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
mode = VPORT_MISS_MODE_ACCEPT_ALL;
} else if (!netdev_uc_empty(netdev)) {
netdev_for_each_uc_addr(ha, netdev)
- qlcnic_nic_add_mac(adapter, ha->addr, vlan);
+ qlcnic_nic_add_mac(adapter, ha->addr, vlan,
+ QLCNIC_UNICAST_MAC);
}
if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 1659c80..e631246 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -1489,7 +1489,8 @@ out:
return ret;
}
-static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac)
+static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac,
+ enum qlcnic_mac_type mac_type)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
@@ -1500,17 +1501,18 @@ static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac)
vf = &adapter->ahw->sriov->vf_info[0];
if (!qlcnic_sriov_check_any_vlan(vf)) {
- qlcnic_nic_add_mac(adapter, mac, 0);
+ qlcnic_nic_add_mac(adapter, mac, 0, mac_type);
} else {
spin_lock(&vf->vlan_list_lock);
for (i = 0; i < sriov->num_allowed_vlans; i++) {
vlan_id = vf->sriov_vlans[i];
if (vlan_id)
- qlcnic_nic_add_mac(adapter, mac, vlan_id);
+ qlcnic_nic_add_mac(adapter, mac, vlan_id,
+ mac_type);
}
spin_unlock(&vf->vlan_list_lock);
if (qlcnic_84xx_check(adapter))
- qlcnic_nic_add_mac(adapter, mac, 0);
+ qlcnic_nic_add_mac(adapter, mac, 0, mac_type);
}
}
@@ -1549,10 +1551,12 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else {
- qlcnic_vf_add_mc_list(netdev, bcast_addr);
+ qlcnic_vf_add_mc_list(netdev, bcast_addr, QLCNIC_BROADCAST_MAC);
if (!netdev_mc_empty(netdev)) {
+ qlcnic_flush_mcast_mac(adapter);
netdev_for_each_mc_addr(ha, netdev)
- qlcnic_vf_add_mc_list(netdev, ha->addr);
+ qlcnic_vf_add_mc_list(netdev, ha->addr,
+ QLCNIC_MULTICAST_MAC);
}
}
@@ -1563,7 +1567,8 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
mode = VPORT_MISS_MODE_ACCEPT_ALL;
} else if (!netdev_uc_empty(netdev)) {
netdev_for_each_uc_addr(ha, netdev)
- qlcnic_vf_add_mc_list(netdev, ha->addr);
+ qlcnic_vf_add_mc_list(netdev, ha->addr,
+ QLCNIC_UNICAST_MAC);
}
if (adapter->pdev->is_virtfn) {
--
1.5.6
^ permalink raw reply related
* Re: [PATCH] openvswitch: Add missing initialization in validate_and_copy_set_tun()
From: Thomas Graf @ 2015-02-11 15:57 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: David S. Miller, Pravin Shelar, netdev, dev, linux-kernel
In-Reply-To: <1423650218-24666-1-git-send-email-geert@linux-m68k.org>
On 02/11/15 at 11:23am, Geert Uytterhoeven wrote:
> net/openvswitch/flow_netlink.c: In function ‘validate_and_copy_set_tun’:
> net/openvswitch/flow_netlink.c:1749: warning: ‘err’ may be used uninitialized in this function
>
> If ipv4_tun_from_nlattr() returns a different positive value than
> OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, err will be uninitialized, and
> validate_and_copy_set_tun() may return an undefined value instead of a
> zero success indicator. Initialize err to zero to fix this.
>
> Fixes: 1dd144cf5b4b47e1 ("openvswitch: Support VXLAN Group Policy extension")
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Thomas Graf <tgraf@suug.ch>
^ permalink raw reply
* [PATCH v5 1/4] gpiolib: define gpio suffixes globally
From: Rojhalat Ibrahim @ 2015-02-11 16:27 UTC (permalink / raw)
To: linux-gpio@vger.kernel.org
Cc: Alexandre Courbot, Alexandre Courbot, Linus Walleij,
Mika Westerberg, Rafael J. Wysocki, David Miller, netdev
Avoid multiple identical definitions of the gpio suffix strings by putting
them into a global constant array.
Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
---
Change log:
v5: move the global definition to drivers/gpio/gpiolib.h
v4: no change
v3: add this change as a separate patch
drivers/gpio/gpiolib.c | 14 ++++++--------
drivers/gpio/gpiolib.h | 3 +++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index bf6016d..b71c351 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1657,19 +1657,18 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
- static const char * const suffixes[] = { "gpios", "gpio" };
char prop_name[32]; /* 32 is max size of property name */
enum of_gpio_flags of_flags;
struct gpio_desc *desc;
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id)
snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
- suffixes[i]);
+ gpio_suffixes[i]);
else
snprintf(prop_name, sizeof(prop_name), "%s",
- suffixes[i]);
+ gpio_suffixes[i]);
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
&of_flags);
@@ -1690,7 +1689,6 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
- static const char * const suffixes[] = { "gpios", "gpio" };
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
@@ -1698,13 +1696,13 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
int i;
/* Try first from _DSD */
- for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id && strcmp(con_id, "gpios")) {
snprintf(propname, sizeof(propname), "%s-%s",
- con_id, suffixes[i]);
+ con_id, gpio_suffixes[i]);
} else {
snprintf(propname, sizeof(propname), "%s",
- suffixes[i]);
+ gpio_suffixes[i]);
}
desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index e3a5211..3cbf3dd 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -27,6 +27,9 @@ struct acpi_gpio_info {
bool active_low;
};
+/* gpio suffixes used for ACPI and device tree lookup */
+static const char * const gpio_suffixes[] = { "gpios", "gpio" };
+
#ifdef CONFIG_ACPI
void acpi_gpiochip_add(struct gpio_chip *chip);
void acpi_gpiochip_remove(struct gpio_chip *chip);
--
2.0.5
^ permalink raw reply related
* [PATCH v5 3/4] gpiolib: add devm_gpiod_get_array and devm_gpiod_put_array functions
From: Rojhalat Ibrahim @ 2015-02-11 16:28 UTC (permalink / raw)
To: linux-gpio@vger.kernel.org
Cc: Alexandre Courbot, Alexandre Courbot, Linus Walleij,
Mika Westerberg, Rafael J. Wysocki, David Miller, netdev
Add device managed variants of gpiod_get_array() / gpiod_put_array()
functions for conveniently obtaining and disposing of an entire array
of GPIOs with one function call.
Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
---
Change log:
v5: no change
v4: no change
v3: make the flags argument mandatory for the new functions
v2: add this patch to the set
Documentation/gpio/consumer.txt | 14 ++++++-
drivers/gpio/devres.c | 89 +++++++++++++++++++++++++++++++++++++++++
include/linux/gpio/consumer.h | 30 ++++++++++++++
3 files changed, 131 insertions(+), 2 deletions(-)
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index 2924f2f..d29a972 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -102,11 +102,19 @@ Device-managed variants of these functions are also defined:
const char *con_id,
enum gpiod_flags flags)
- struct gpio_desc * devm_gpiod_get_index_optional(struct device *dev,
+ struct gpio_desc *devm_gpiod_get_index_optional(struct device *dev,
const char *con_id,
unsigned int index,
enum gpiod_flags flags)
+ struct gpio_descs *devm_gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+
+ struct gpio_descs *devm_gpiod_get_array_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+
A GPIO descriptor can be disposed of using the gpiod_put() function:
void gpiod_put(struct gpio_desc *desc)
@@ -119,10 +127,12 @@ It is strictly forbidden to use a descriptor after calling these functions.
It is also not allowed to individually release descriptors (using gpiod_put())
from an array acquired with gpiod_get_array().
-The device-managed variant is, unsurprisingly:
+The device-managed variants are, unsurprisingly:
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
+ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
+
Using GPIOs
===========
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 13dbd3d..fbc5cb8 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -35,6 +35,20 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data)
return *this == *gpio;
}
+static void devm_gpiod_release_array(struct device *dev, void *res)
+{
+ struct gpio_descs **descs = res;
+
+ gpiod_put_array(*descs);
+}
+
+static int devm_gpiod_match_array(struct device *dev, void *res, void *data)
+{
+ struct gpio_descs **this = res, **gpios = data;
+
+ return *this == *gpios;
+}
+
/**
* devm_gpiod_get - Resource-managed gpiod_get()
* @dev: GPIO consumer
@@ -170,6 +184,66 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de
EXPORT_SYMBOL(__devm_gpiod_get_index_optional);
/**
+ * devm_gpiod_get_array - Resource-managed gpiod_get_array()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get_array(). GPIO descriptors returned from this function are
+ * automatically disposed on driver detach. See gpiod_get_array() for detailed
+ * information about behavior and return values.
+ */
+struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_descs **dr;
+ struct gpio_descs *descs;
+
+ dr = devres_alloc(devm_gpiod_release_array,
+ sizeof(struct gpio_descs *), GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ descs = gpiod_get_array(dev, con_id, flags);
+ if (IS_ERR(descs)) {
+ devres_free(dr);
+ return descs;
+ }
+
+ *dr = descs;
+ devres_add(dev, dr);
+
+ return descs;
+}
+EXPORT_SYMBOL(devm_gpiod_get_array);
+
+/**
+ * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get_array_optional(). GPIO descriptors returned from this
+ * function are automatically disposed on driver detach.
+ * See gpiod_get_array_optional() for detailed information about behavior and
+ * return values.
+ */
+struct gpio_descs *__must_check
+devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_descs *descs;
+
+ descs = devm_gpiod_get_array(dev, con_id, flags);
+ if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT))
+ return NULL;
+
+ return descs;
+}
+EXPORT_SYMBOL(devm_gpiod_get_array_optional);
+
+/**
* devm_gpiod_put - Resource-managed gpiod_put()
* @desc: GPIO descriptor to dispose of
*
@@ -184,6 +258,21 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
}
EXPORT_SYMBOL(devm_gpiod_put);
+/**
+ * devm_gpiod_put_array - Resource-managed gpiod_put_array()
+ * @descs: GPIO descriptor array to dispose of
+ *
+ * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array().
+ * Normally this function will not be called as the GPIOs will be disposed of
+ * by the resource management code.
+ */
+void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
+{
+ WARN_ON(devres_release(dev, devm_gpiod_release_array,
+ devm_gpiod_match_array, &descs));
+}
+EXPORT_SYMBOL(devm_gpiod_put_array);
+
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index f71cad6..6611a53 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -83,7 +83,14 @@ struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev,
struct gpio_desc *__must_check
__devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
unsigned int index, enum gpiod_flags flags);
+struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags);
+struct gpio_descs *__must_check
+devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
+ enum gpiod_flags flags);
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
+void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
int gpiod_get_direction(struct gpio_desc *desc);
int gpiod_direction_input(struct gpio_desc *desc);
@@ -227,6 +234,20 @@ __devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
return ERR_PTR(-ENOSYS);
}
+static inline struct gpio_descs *__must_check
+devm_gpiod_get_array(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct gpio_descs *__must_check
+devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
{
might_sleep();
@@ -235,6 +256,15 @@ static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
WARN_ON(1);
}
+static inline void devm_gpiod_put_array(struct device *dev,
+ struct gpio_descs *descs)
+{
+ might_sleep();
+
+ /* GPIO can never have been requested */
+ WARN_ON(1);
+}
+
static inline int gpiod_get_direction(const struct gpio_desc *desc)
{
--
2.0.5
^ permalink raw reply related
* [PATCH v5 2/4] gpiolib: add gpiod_get_array and gpiod_put_array functions
From: Rojhalat Ibrahim @ 2015-02-11 16:27 UTC (permalink / raw)
To: linux-gpio@vger.kernel.org
Cc: Alexandre Courbot, Alexandre Courbot, Linus Walleij,
Mika Westerberg, Rafael J. Wysocki, David Miller, netdev
Introduce new functions for conveniently obtaining and disposing of an entire
array of GPIOs with one function call.
Suggested-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
ACPI part:
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
DT part:
Tested-by: Rojhalat Ibrahim <imr@rtschenk.de>
---
Change log:
v5: move the ACPI functions to gpiolib-acpi.c
v4: - use shorter names for members of struct gpio_descs
- rename lut_gpio_count to platform_gpio_count for clarity
- add check for successful memory allocation
- use ERR_CAST()
v3: - rebase on current linux-gpio devel branch
- fix ACPI GPIO counting
- allow for zero-sized arrays
- make the flags argument mandatory for the new functions
- clarify documentation
v2: change interface
Documentation/gpio/consumer.txt | 33 ++++++++-
drivers/gpio/gpiolib-acpi.c | 84 +++++++++++++++++++++++
drivers/gpio/gpiolib.c | 145 ++++++++++++++++++++++++++++++++++++++++
drivers/gpio/gpiolib.h | 7 ++
include/linux/gpio/consumer.h | 46 +++++++++++++
5 files changed, 312 insertions(+), 3 deletions(-)
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index d85fbae..2924f2f 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -58,7 +58,6 @@ pattern where a GPIO is optional, the gpiod_get_optional() and
gpiod_get_index_optional() functions can be used. These functions return NULL
instead of -ENOENT if no GPIO has been assigned to the requested function:
-
struct gpio_desc *gpiod_get_optional(struct device *dev,
const char *con_id,
enum gpiod_flags flags)
@@ -68,6 +67,27 @@ instead of -ENOENT if no GPIO has been assigned to the requested function:
unsigned int index,
enum gpiod_flags flags)
+For a function using multiple GPIOs all of those can be obtained with one call:
+
+ struct gpio_descs *gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+
+This function returns a struct gpio_descs which contains an array of
+descriptors:
+
+ struct gpio_descs {
+ unsigned int ndescs;
+ struct gpio_desc *desc[];
+ }
+
+The following function returns NULL instead of -ENOENT if no GPIOs have been
+assigned to the requested function:
+
+ struct gpio_descs *gpiod_get_array_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+
Device-managed variants of these functions are also defined:
struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id,
@@ -91,8 +111,15 @@ A GPIO descriptor can be disposed of using the gpiod_put() function:
void gpiod_put(struct gpio_desc *desc)
-It is strictly forbidden to use a descriptor after calling this function. The
-device-managed variant is, unsurprisingly:
+For an array of GPIOs this function can be used:
+
+ void gpiod_put_array(struct gpio_descs *descs)
+
+It is strictly forbidden to use a descriptor after calling these functions.
+It is also not allowed to individually release descriptors (using gpiod_put())
+from an array acquired with gpiod_get_array().
+
+The device-managed variant is, unsurprisingly:
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index c0929d9..c491996 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -712,3 +712,87 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
acpi_detach_data(handle, acpi_gpio_chip_dh);
kfree(acpi_gpio);
}
+
+static unsigned int acpi_gpio_package_count(const union acpi_object *obj)
+{
+ const union acpi_object *element = obj->package.elements;
+ const union acpi_object *end = element + obj->package.count;
+ unsigned int count = 0;
+
+ while (element < end) {
+ if (element->type == ACPI_TYPE_LOCAL_REFERENCE)
+ count++;
+
+ element++;
+ }
+ return count;
+}
+
+static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
+{
+ unsigned int *count = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_GPIO)
+ *count += ares->data.gpio.pin_table_length;
+
+ return 1;
+}
+
+/**
+ * acpi_gpio_count - return the number of GPIOs associated with a
+ * device / function or -ENOENT if no GPIO has been
+ * assigned to the requested function.
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ */
+int acpi_gpio_count(struct device *dev, const char *con_id)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ const union acpi_object *obj;
+ const struct acpi_gpio_mapping *gm;
+ int count = -ENOENT;
+ int ret;
+ char propname[32];
+ unsigned int i;
+
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios"))
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, gpio_suffixes[i]);
+ else
+ snprintf(propname, sizeof(propname), "%s",
+ gpio_suffixes[i]);
+
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ &obj);
+ if (ret == 0) {
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
+ count = 1;
+ else if (obj->type == ACPI_TYPE_PACKAGE)
+ count = acpi_gpio_package_count(obj);
+ } else if (adev->driver_gpios) {
+ for (gm = adev->driver_gpios; gm->name; gm++)
+ if (strcmp(propname, gm->name) == 0) {
+ count = gm->size;
+ break;
+ }
+ }
+ if (count >= 0)
+ break;
+ }
+
+ /* Then from plain _CRS GPIOs */
+ if (count < 0) {
+ struct list_head resource_list;
+ unsigned int crs_count = 0;
+
+ INIT_LIST_HEAD(&resource_list);
+ acpi_dev_get_resources(adev, &resource_list,
+ acpi_find_gpio_count, &crs_count);
+ acpi_dev_free_resource_list(&resource_list);
+ if (crs_count > 0)
+ count = crs_count;
+ }
+ return count;
+}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b71c351..2a25fba 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1801,6 +1801,70 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return desc;
}
+static int dt_gpio_count(struct device *dev, const char *con_id)
+{
+ int ret;
+ char propname[32];
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+ if (con_id)
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, gpio_suffixes[i]);
+ else
+ snprintf(propname, sizeof(propname), "%s",
+ gpio_suffixes[i]);
+
+ ret = of_gpio_named_count(dev->of_node, propname);
+ if (ret >= 0)
+ break;
+ }
+ return ret;
+}
+
+static int platform_gpio_count(struct device *dev, const char *con_id)
+{
+ struct gpiod_lookup_table *table;
+ struct gpiod_lookup *p;
+ unsigned int count = 0;
+
+ table = gpiod_find_lookup_table(dev);
+ if (!table)
+ return -ENOENT;
+
+ for (p = &table->table[0]; p->chip_label; p++) {
+ if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) ||
+ (!con_id && !p->con_id))
+ count++;
+ }
+ if (!count)
+ return -ENOENT;
+
+ return count;
+}
+
+/**
+ * gpiod_count - return the number of GPIOs associated with a device / function
+ * or -ENOENT if no GPIO has been assigned to the requested function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ */
+int gpiod_count(struct device *dev, const char *con_id)
+{
+ int count = -ENOENT;
+
+ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+ count = dt_gpio_count(dev, con_id);
+ else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev))
+ count = acpi_gpio_count(dev, con_id);
+
+ if (count < 0)
+ count = platform_gpio_count(dev, con_id);
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(gpiod_count);
+
/**
* gpiod_get - obtain a GPIO for a given GPIO function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
@@ -2002,6 +2066,72 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
EXPORT_SYMBOL_GPL(__gpiod_get_index_optional);
/**
+ * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This function acquires all the GPIOs defined under a given function.
+ *
+ * Return a struct gpio_descs containing an array of descriptors, -ENOENT if
+ * no GPIO has been assigned to the requested function, or another IS_ERR()
+ * code if an error occurred while trying to acquire the GPIOs.
+ */
+struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+ struct gpio_descs *descs;
+ int count;
+
+ count = gpiod_count(dev, con_id);
+ if (count < 0)
+ return ERR_PTR(count);
+
+ descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count,
+ GFP_KERNEL);
+ if (!descs)
+ return ERR_PTR(-ENOMEM);
+
+ for (descs->ndescs = 0; descs->ndescs < count; ) {
+ desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);
+ if (IS_ERR(desc)) {
+ gpiod_put_array(descs);
+ return ERR_CAST(desc);
+ }
+ descs->desc[descs->ndescs] = desc;
+ descs->ndescs++;
+ }
+ return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array);
+
+/**
+ * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO
+ * function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to gpiod_get_array(), except that when no GPIO was
+ * assigned to the requested function it will return NULL.
+ */
+struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_descs *descs;
+
+ descs = gpiod_get_array(dev, con_id, flags);
+ if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT))
+ return NULL;
+
+ return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array_optional);
+
+/**
* gpiod_put - dispose of a GPIO descriptor
* @desc: GPIO descriptor to dispose of
*
@@ -2013,6 +2143,21 @@ void gpiod_put(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_put);
+/**
+ * gpiod_put_array - dispose of multiple GPIO descriptors
+ * @descs: struct gpio_descs containing an array of descriptors
+ */
+void gpiod_put_array(struct gpio_descs *descs)
+{
+ unsigned int i;
+
+ for (i = 0; i < descs->ndescs; i++)
+ gpiod_put(descs->desc[i]);
+
+ kfree(descs);
+}
+EXPORT_SYMBOL_GPL(gpiod_put_array);
+
#ifdef CONFIG_DEBUG_FS
static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 3cbf3dd..054b401 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -40,6 +40,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
const char *propname, int index,
struct acpi_gpio_info *info);
+
+int acpi_gpio_count(struct device *dev, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
@@ -56,6 +58,11 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
{
return ERR_PTR(-ENOSYS);
}
+
+static inline int acpi_gpio_count(struct device *dev, const char *con_id)
+{
+ return -ENODEV;
+}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 45afc2d..f71cad6 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -16,6 +16,15 @@ struct device;
*/
struct gpio_desc;
+/**
+ * Struct containing an array of descriptors that can be obtained using
+ * gpiod_get_array().
+ */
+struct gpio_descs {
+ unsigned int ndescs;
+ struct gpio_desc *desc[];
+};
+
#define GPIOD_FLAGS_BIT_DIR_SET BIT(0)
#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
@@ -34,6 +43,9 @@ enum gpiod_flags {
#ifdef CONFIG_GPIOLIB
+/* Return the number of GPIOs associated with a device / function */
+int gpiod_count(struct device *dev, const char *con_id);
+
/* Acquire and dispose GPIOs */
struct gpio_desc *__must_check __gpiod_get(struct device *dev,
const char *con_id,
@@ -49,7 +61,14 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
const char *con_id,
unsigned int index,
enum gpiod_flags flags);
+struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags);
+struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags);
void gpiod_put(struct gpio_desc *desc);
+void gpiod_put_array(struct gpio_descs *descs);
struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev,
const char *con_id,
@@ -113,6 +132,11 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
struct fwnode_handle *child);
#else /* CONFIG_GPIOLIB */
+static inline int gpiod_count(struct device *dev, const char *con_id)
+{
+ return 0;
+}
+
static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
const char *con_id,
enum gpiod_flags flags)
@@ -142,6 +166,20 @@ __gpiod_get_index_optional(struct device *dev, const char *con_id,
return ERR_PTR(-ENOSYS);
}
+static inline struct gpio_descs *__must_check
+gpiod_get_array(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct gpio_descs *__must_check
+gpiod_get_array_optional(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline void gpiod_put(struct gpio_desc *desc)
{
might_sleep();
@@ -150,6 +188,14 @@ static inline void gpiod_put(struct gpio_desc *desc)
WARN_ON(1);
}
+static inline void gpiod_put_array(struct gpio_descs *descs)
+{
+ might_sleep();
+
+ /* GPIO can never have been requested */
+ WARN_ON(1);
+}
+
static inline struct gpio_desc *__must_check
__devm_gpiod_get(struct device *dev,
const char *con_id,
--
2.0.5
^ permalink raw reply related
* [PATCH v5 4/4] mdio-mux-gpio: use new gpiod_get_array and gpiod_put_array functions
From: Rojhalat Ibrahim @ 2015-02-11 16:28 UTC (permalink / raw)
To: linux-gpio@vger.kernel.org
Cc: Alexandre Courbot, Alexandre Courbot, Linus Walleij,
Mika Westerberg, Rafael J. Wysocki, David Miller, netdev
Use the new gpiod_get_array and gpiod_put_array functions for obtaining and
disposing of GPIO descriptors.
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
---
Change log:
v5: no change
v4: use shorter names for members of struct gpio_descs
v3: no change
v2: use the new interface
drivers/net/phy/mdio-mux-gpio.c | 60 ++++++++++++-----------------------------
1 file changed, 17 insertions(+), 43 deletions(-)
diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
index 320eb15..c49ad09 100644
--- a/drivers/net/phy/mdio-mux-gpio.c
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -12,33 +12,30 @@
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/mdio-mux.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#define DRV_VERSION "1.1"
#define DRV_DESCRIPTION "GPIO controlled MDIO bus multiplexer driver"
-#define MDIO_MUX_GPIO_MAX_BITS 8
-
struct mdio_mux_gpio_state {
- struct gpio_desc *gpio[MDIO_MUX_GPIO_MAX_BITS];
- unsigned int num_gpios;
+ struct gpio_descs *gpios;
void *mux_handle;
};
static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
void *data)
{
- int values[MDIO_MUX_GPIO_MAX_BITS];
- unsigned int n;
struct mdio_mux_gpio_state *s = data;
+ int values[s->gpios->ndescs];
+ unsigned int n;
if (current_child == desired_child)
return 0;
- for (n = 0; n < s->num_gpios; n++) {
+ for (n = 0; n < s->gpios->ndescs; n++)
values[n] = (desired_child >> n) & 1;
- }
- gpiod_set_array_cansleep(s->num_gpios, s->gpio, values);
+
+ gpiod_set_array_cansleep(s->gpios->ndescs, s->gpios->desc, values);
return 0;
}
@@ -46,56 +43,33 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
static int mdio_mux_gpio_probe(struct platform_device *pdev)
{
struct mdio_mux_gpio_state *s;
- int num_gpios;
- unsigned int n;
int r;
- if (!pdev->dev.of_node)
- return -ENODEV;
-
- num_gpios = of_gpio_count(pdev->dev.of_node);
- if (num_gpios <= 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
- return -ENODEV;
-
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
- s->num_gpios = num_gpios;
-
- for (n = 0; n < num_gpios; ) {
- struct gpio_desc *gpio = gpiod_get_index(&pdev->dev, NULL, n,
- GPIOD_OUT_LOW);
- if (IS_ERR(gpio)) {
- r = PTR_ERR(gpio);
- goto err;
- }
- s->gpio[n] = gpio;
- n++;
- }
+ s->gpios = gpiod_get_array(&pdev->dev, NULL, GPIOD_OUT_LOW);
+ if (IS_ERR(s->gpios))
+ return PTR_ERR(s->gpios);
r = mdio_mux_init(&pdev->dev,
mdio_mux_gpio_switch_fn, &s->mux_handle, s);
- if (r == 0) {
- pdev->dev.platform_data = s;
- return 0;
- }
-err:
- while (n) {
- n--;
- gpiod_put(s->gpio[n]);
+ if (r != 0) {
+ gpiod_put_array(s->gpios);
+ return r;
}
- return r;
+
+ pdev->dev.platform_data = s;
+ return 0;
}
static int mdio_mux_gpio_remove(struct platform_device *pdev)
{
- unsigned int n;
struct mdio_mux_gpio_state *s = dev_get_platdata(&pdev->dev);
mdio_mux_uninit(s->mux_handle);
- for (n = 0; n < s->num_gpios; n++)
- gpiod_put(s->gpio[n]);
+ gpiod_put_array(s->gpios);
return 0;
}
--
2.0.5
^ permalink raw reply related
* [PATCH FIX] bgmac: fix device initialization on Northstar SoCs (condition typo)
From: Rafał Miłecki @ 2015-02-11 17:06 UTC (permalink / raw)
To: David S. Miller, netdev; +Cc: Hauke Mehrtens, Rafał Miłecki
On Northstar (Broadcom's ARM architecture) we need to manually enable
all cores. Code for that is already in place, but the condition for it
was wrong.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
Can we have it for 3.20, please?
---
drivers/net/ethernet/broadcom/bgmac.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 3007d95..728373b 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1412,6 +1412,7 @@ static void bgmac_mii_unregister(struct bgmac *bgmac)
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
static int bgmac_probe(struct bcma_device *core)
{
+ struct bcma_chipinfo *ci = &core->bus->chipinfo;
struct net_device *net_dev;
struct bgmac *bgmac;
struct ssb_sprom *sprom = &core->bus->sprom;
@@ -1474,8 +1475,8 @@ static int bgmac_probe(struct bcma_device *core)
bgmac_chip_reset(bgmac);
/* For Northstar, we have to take all GMAC core out of reset */
- if (core->id.id == BCMA_CHIP_ID_BCM4707 ||
- core->id.id == BCMA_CHIP_ID_BCM53018) {
+ if (ci->id == BCMA_CHIP_ID_BCM4707 ||
+ ci->id == BCMA_CHIP_ID_BCM53018) {
struct bcma_device *ns_core;
int ns_gmac;
--
1.8.4.5
^ permalink raw reply related
* Re: network namespace bloat
From: Nicolas Dichtel @ 2015-02-11 17:09 UTC (permalink / raw)
To: Eric W. Biederman, netdev
Cc: Stephen Hemminger, roopa, hannes, Dinesh Dutt, Vipin Kumar,
Shmulik Ladkani, David Ahern, Eric Dumazet, David S. Miller
In-Reply-To: <871tlxtbhd.fsf_-_@x220.int.ebiederm.org>
Le 11/02/2015 03:42, Eric W. Biederman a écrit :
[snip]
>
> The next largest component appears to be all of the tunnel network
> devices that we allocate for compatibility reasons so that the old ioctl
> interfaces still work.
>
[snip]
>
>
> A knob (sysctl?) that controls the creation of the backwards
> compabitilty tunnel network devices seems desirable. As in many
> instances those are just overhead today.
Note that these interfaces are also used as fallback devices, they catch
packets that don't match any configured tunnels.
See: http://thread.gmane.org/gmane.linux.network/249634/focus=249634
[snip]
>
> In my ideal world enough of these issues would be fixed that a
> new empty network namespace would consume less than 100KiB of memory.
+1
Regards,
Nicolas
^ permalink raw reply
* [PATCH ipsec] xfrm: release dst_orig in case of error in xfrm_lookup()
From: Nicolas Dichtel @ 2015-02-11 17:10 UTC (permalink / raw)
To: steffen.klassert, herbert, davem; +Cc: netdev, huaibin Wang, Nicolas Dichtel
From: huaibin Wang <huaibin.wang@6wind.com>
dst_orig should be released on error. Function like __xfrm_route_forward()
expects that behavior.
Since a recent commit, xfrm_lookup() may also be called by xfrm_lookup_route(),
which expects the opposite.
Let's introduce a new flag (XFRM_LOOKUP_KEEP_DST_REF) to tell what should be
done in case of error.
Fixes: f92ee61982d("xfrm: Generate blackhole routes only from route lookup functions")
Signed-off-by: huaibin Wang <huaibin.wang@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/net/dst.h | 1 +
net/xfrm/xfrm_policy.c | 12 ++++++------
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index a8ae4e760778..0fb99a26e973 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -481,6 +481,7 @@ void dst_init(void);
enum {
XFRM_LOOKUP_ICMP = 1 << 0,
XFRM_LOOKUP_QUEUE = 1 << 1,
+ XFRM_LOOKUP_KEEP_DST_REF = 1 << 2,
};
struct flowi;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index cee479bc655c..638af0655aaf 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2269,11 +2269,9 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
* have the xfrm_state's. We need to wait for KM to
* negotiate new SA's or bail out with error.*/
if (net->xfrm.sysctl_larval_drop) {
- dst_release(dst);
- xfrm_pols_put(pols, drop_pols);
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-
- return ERR_PTR(-EREMOTE);
+ err = -EREMOTE;
+ goto error;
}
err = -EAGAIN;
@@ -2324,7 +2322,8 @@ nopol:
error:
dst_release(dst);
dropdst:
- dst_release(dst_orig);
+ if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
+ dst_release(dst_orig);
xfrm_pols_put(pols, drop_pols);
return ERR_PTR(err);
}
@@ -2338,7 +2337,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
struct sock *sk, int flags)
{
struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
- flags | XFRM_LOOKUP_QUEUE);
+ flags | XFRM_LOOKUP_QUEUE |
+ XFRM_LOOKUP_KEEP_DST_REF);
if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
return make_blackhole(net, dst_orig->ops->family, dst_orig);
--
2.2.2
^ permalink raw reply related
* Re: [PATCH net-next] sunvnet: don't change gso data on clones
From: David L Stevens @ 2015-02-11 17:35 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1423662993.4847.19.camel@edumazet-glaptop2.roam.corp.google.com>
On 02/11/2015 08:56 AM, Eric Dumazet wrote:
> On Wed, 2015-02-11 at 08:20 -0500, David L Stevens wrote:
>> This patch unclones an skb for the case where the sunvnet driver needs to
>> change the segmentation size so that it doesn't interfere with TCP SACK's
>> use of them.
>>
>> Signed-off-by: David L Stevens <david.stevens@oracle.com>
>> ---
>
> Hmm... this would point to a TCP bug ?
>
> What happens if not GSO is needed, TCP corrupts data currently
> read/processed by NIC/driver ?
I don't think I understand your concern. This problem can result in a
panic using sunvnet because the sunvnet driver is changing the original
skb, which is always, or at least almost always, a clone. TCP uses gso_segs
to track packet counts, so changing it in the driver can result in bad math--
TCP assumes its copy of the clone's data shouldn't change (of course).
A driver that doesn't change the segmentation or original data doesn't
need to care whether it's a clone or not-- it'll free it and drop a
reference. Since sunvnet is changing the gso_size and gso_segs, it needs
to unclone first.
+-DLS
^ permalink raw reply
* Re: [PATCH] et131x: use msecs_to_jiffies for conversions
From: Mark Einon @ 2015-02-11 18:11 UTC (permalink / raw)
To: Nicholas Mc Guire; +Cc: David S. Miller, netdev, linux-kernel
In-Reply-To: <1423646874-24403-1-git-send-email-hofrat@osadl.org>
On Wed, Feb 11, 2015 at 04:27:54AM -0500, Nicholas Mc Guire wrote:
> This is only an API consolidation and should make things more readable.
> Converting milliseconds to jiffies by "val * HZ / 1000" is technically
> OK but msecs_to_jiffies(val) is the cleaner solution and handles all
> corner cases correctly. This is a minor API cleanup only.
>
> Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Mark Einon <mark.einon@gmail.com>
^ permalink raw reply
* Re: [PATCH] brcmfmac: use msecs_to_jiffies for time conversion
From: Arend van Spriel @ 2015-02-11 18:18 UTC (permalink / raw)
To: Nicholas Mc Guire
Cc: Brett Rudley, Franky (Zhenhui) Lin, Hante Meuleman, Kalle Valo,
Pieter-Paul Giesberts, John W. Linville, Daniel Kim,
linux-wireless, brcm80211-dev-list, netdev, linux-kernel
In-Reply-To: <1423218405-17624-1-git-send-email-hofrat@osadl.org>
On 02/06/15 11:26, Nicholas Mc Guire wrote:
> This is only an API consolidation and should make things more readable
> it replaces var * HZ / 1000 by msecs_to_jiffies(var).
Acked-by: Arend van Spriel <arend@broadcom.com>
> Signed-off-by: Nicholas Mc Guire<hofrat@osadl.org>
> ---
>
> Patch was only compile tested with x86_64_defconfig + CONFIG_BRCMFMAC=m,
> CONFIG_MMC=m, CONFIG_BRCMFMAC_SDIO=y
>
> Patch is against 3.19.0-rc7 (localversion-next is -next-20150204)
>
> drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
> index 5e9d208..4f9469b 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
> @@ -3972,7 +3972,7 @@ brcmf_sdio_watchdog(unsigned long data)
> /* Reschedule the watchdog */
> if (bus->wd_timer_valid)
> mod_timer(&bus->timer,
> - jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
> + jiffies + msecs_to_jiffies(BRCMF_WD_POLL_MS));
> }
> }
>
> @@ -4291,13 +4291,13 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
> dynamically changed or in the first instance
> */
> bus->timer.expires =
> - jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
> + jiffies + msecs_to_jiffies(BRCMF_WD_POLL_MS);
> add_timer(&bus->timer);
>
> } else {
> /* Re arm the timer, at last watchdog period */
> mod_timer(&bus->timer,
> - jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
> + jiffies + msecs_to_jiffies(BRCMF_WD_POLL_MS));
> }
>
> bus->wd_timer_valid = true;
^ permalink raw reply
* pull-request: wireless-drivers 2015-02-11
From: Kalle Valo @ 2015-02-11 18:43 UTC (permalink / raw)
To: David Miller; +Cc: linux-wireless, netdev, linux-kernel
Hi Dave,
here's one rtlwifi fix for 3.20. We have had two reports of this issue
already, so it would be good to get this to -rc1 or -rc2.
I rebased wireless-drivers on top of net-next, so this patch applies to
net-next. I hope that's ok.
Kalle
The following changes since commit b0f9ca53cbb103e9240a29a974e0b6085e58f9f7:
ipv4: Namespecify TCP PMTU mechanism (2015-02-09 18:45:00 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git tags/wireless-drivers-for-davem-2015-02-11
for you to fetch changes up to aeb2d2a4c0ae1739a6e1782bd8c1c96aee8db4e1:
rtlwifi: Remove logging statement that is no longer needed (2015-02-10 16:09:11 +0200)
----------------------------------------------------------------
rtlwifi:
* remove superfluous warning message which is not needed anymore
----------------------------------------------------------------
Larry Finger (1):
rtlwifi: Remove logging statement that is no longer needed
drivers/net/wireless/rtlwifi/pci.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
^ permalink raw reply
* Option HSO tty returning NUL bytes read continuously in USB3 port
From: Aleksander Morgado @ 2015-02-11 19:43 UTC (permalink / raw)
To: linux-usb, netdev@vger.kernel.org; +Cc: Dan Williams
Hey,
I'm trying to understand why this Option Globetrotter modem
(net/usb/hso driver, 0af0:6971) ends up returning NUL bytes read
continuously in the TTY when plugged in a USB3 port but not in a USB2
one.
I'm testing this with a 3.18.6 kernel plus a self-compiled hso driver
from net-next; but I had realized about this issue quite some time
ago, so it's likely not a new thing.
ATI output:
Manufacturer: Option N.V.
Model: GlobeTrotter HSDPA Modem
Revision: 2.5.13Hd (Date: Feb 18 2008, Time: 18:32:40)
The device ends up handled like this in the usb tree:
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 5000M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=hso, 12M
|__ Port 1: Dev 4, If 1, Class=Vendor Specific Class, Driver=hso, 12M
|__ Port 1: Dev 4, If 2, Class=Vendor Specific Class, Driver=hso, 12M
I just need to plug in the modem, and send something to the TTY (e.g.
using minicom) and the modem ends up in a cycle of sending NUL bytes,
see driver/usbmon logs below.
[ +7,092221] hso: /home/aleksander/Development/foss/hso/hso.c: Option Wireless
[ +0,000058] [2419:hso_net_init]: sizeof hso_net is 200
[ +0,000642] usbcore: registered new interface driver hso
$ sudo minicom -D /dev/ttyHS0
[feb11 20:24] [1278:hso_serial_open]: Opening 0
[ +0,000006] [1119:_hso_serial_set_termios]: port 0
[ +0,000025] [1416:hso_serial_set_termios]: Termios called with:
cflags new[7346] - old[5298]
[ +0,000003] [1119:_hso_serial_set_termios]: port 0
[ +0,000007] [1416:hso_serial_set_termios]: Termios called with:
cflags new[-2147476302] - old[7346]
[ +0,000002] [1119:_hso_serial_set_termios]: port 0
[ +0,000007] [1416:hso_serial_set_termios]: Termios called with:
cflags new[-2147476302] - old[-2147476302]
[ +0,000003] [1119:_hso_serial_set_termios]: port 0
[ +0,000004] [1416:hso_serial_set_termios]: Termios called with:
cflags new[-2147476302] - old[-2147476302]
[ +0,000003] [1119:_hso_serial_set_termios]: port 0
[ +0,023639] [1876:intr_callback]:
--- Got intr callback 0x00 ---
[ +0,000006] [1880:intr_callback]: port_req = 0x02
[ +0,000004] [1888:intr_callback]: Pending read interrupt on port 1
[ +0,000003] [1901:intr_callback]: Already a read pending on port 1
or port not open
[ +0,031998] [1876:intr_callback]:
--- Got intr callback 0x00 ---
[ +0,000006] [1880:intr_callback]: port_req = 0x02
[ +0,000005] [1888:intr_callback]: Pending read interrupt on port 1
[ +0,000003] [1901:intr_callback]: Already a read pending on port 1
or port not open
minicom$ AT<enter>
--- Got muxed ctrl callback 0x00 ---
[ +0,000008] [1997:ctrl_callback]: Actual length of urb = 1
[ +0,335992] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000006] [1997:ctrl_callback]: Actual length of urb = 1
[ +1,048984] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000007] [1997:ctrl_callback]: Actual length of urb = 1
[ +0,019000] [1876:intr_callback]:
--- Got intr callback 0x00 ---
[ +0,000006] [1880:intr_callback]: port_req = 0x01
[ +0,000004] [1888:intr_callback]: Pending read interrupt on port 0
[ +0,002989] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000007] [1997:ctrl_callback]: Actual length of urb = 6
[ +0,000004] [2035:put_rxbuf_data]: data to push to tty
[ +0,002982] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000006] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000004] [2035:put_rxbuf_data]: data to push to tty
[ +0,002934] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000006] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000003] [2035:put_rxbuf_data]: data to push to tty
[ +0,003052] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000006] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000004] [2035:put_rxbuf_data]: data to push to tty
[ +0,002933] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000004] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000003] [2035:put_rxbuf_data]: data to push to tty
[ +0,003045] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000006] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000004] [2035:put_rxbuf_data]: data to push to tty
[ +0,002994] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000006] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000004] [2035:put_rxbuf_data]: data to push to tty
[ +0,002956] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000005] [1997:ctrl_callback]: Actual length of urb = 1024
[ +0,000003] [2035:put_rxbuf_data]: data to push to tty
[ +0,002990] [1996:ctrl_callback]:
--- Got muxed ctrl callback 0x00 ---
[ +0,000005] [1997:ctrl_callback]: Actual length of urb = 1024
usbmon output looks like:
ffff8800b898b240 3929042350 S Ii:1:004:5 -115:128 1 <
ffff8800b898b240 3929059968 C Ii:1:004:5 0:128 1 = 02
ffff8800b898b240 3929059996 S Ii:1:004:5 -115:128 1 <
ffff8800b898b240 3929091901 C Ii:1:004:5 0:128 1 = 02
ffff8800b898b240 3929091919 S Ii:1:004:5 -115:128 1 <
ffff8800b898b9c0 3933759033 S Co:1:004:0 s 21 00 0000 0000 0001 1 = 41
ffff8800b898b9c0 3933761249 C Co:1:004:0 0 1 >
ffff8800b898b9c0 3934027079 S Co:1:004:0 s 21 00 0000 0000 0001 1 = 54
ffff8800b898b9c0 3934029197 C Co:1:004:0 0 1 >
ffff8800b898b9c0 3934330977 S Co:1:004:0 s 21 00 0000 0000 0001 1 = 0d
ffff8800b898b9c0 3934333147 C Co:1:004:0 0 1 >
ffff8800b898b240 3934339157 C Ii:1:004:5 0:128 1 = 01
ffff8800b898b3c0 3934339182 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b240 3934339187 S Ii:1:004:5 -115:128 1 <
ffff8800b898b3c0 3934342145 C Ci:1:004:0 0 6 = 0d0a4f4b 0d0a
ffff8800b898b3c0 3934342171 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934345157 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934345184 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934348156 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934348182 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934351148 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934351174 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934354154 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934354181 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934357148 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934357175 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934360089 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934360111 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934363117 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934363142 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934366154 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934366180 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934369085 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934369109 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934372085 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
ffff8800b898b3c0 3934372109 S Ci:1:004:0 s a1 01 0000 0000 0400 1024 <
ffff8800b898b3c0 3934375142 C Ci:1:004:0 0 1024 = 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
Any hint?
--
Aleksander
https://aleksander.es
^ permalink raw reply
* Re: [PATCH] openvswitch: Add missing initialization in validate_and_copy_set_tun()
From: Pravin Shelar @ 2015-02-11 21:31 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: David S. Miller, Thomas Graf, netdev, dev@openvswitch.org, LKML
In-Reply-To: <1423650218-24666-1-git-send-email-geert@linux-m68k.org>
On Wed, Feb 11, 2015 at 2:23 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> net/openvswitch/flow_netlink.c: In function ‘validate_and_copy_set_tun’:
> net/openvswitch/flow_netlink.c:1749: warning: ‘err’ may be used uninitialized in this function
>
> If ipv4_tun_from_nlattr() returns a different positive value than
> OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, err will be uninitialized, and
> validate_and_copy_set_tun() may return an undefined value instead of a
> zero success indicator. Initialize err to zero to fix this.
>
> Fixes: 1dd144cf5b4b47e1 ("openvswitch: Support VXLAN Group Policy extension")
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
^ permalink raw reply
* [PATCH next v2 3/6] bonding: Implement port churn-machine (AD standard 43.4.17).
From: Mahesh Bandewar @ 2015-02-11 22:05 UTC (permalink / raw)
To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
Nikolay Aleksandrov, David Miller
Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet
The Chrun Detection machines detect the situation where a port is operable,
but the Actor and Partner have not attached the link to an Aggregator and
brought the link into operation within a bound time period. Under normal
operation of the LACP, aggrement between Actor and Partner should be reached
very rapidly. Continued failure to reach aggrement can be symptomatic of
device failure.
Actor-churn-dection state-machine
=================================
BEGIN=True + PortEnable=False
|
v
+------------------------+ ActorPort.Sync=True +------------------+
| ACTOR_CHURN_MONITOR | ---------------------> | NO_ACTOR_CHURN |
|========================| |==================|
| ActorChurn=False | ActorPort.Sync=False | ActorChurn=False |
| ActorChurn.Timer=Start | <--------------------- | |
+------------------------+ +------------------+
| ^
| |
ActorChurn.Timer=Expired |
| ActorPort.Sync=True
| |
| +-----------------+ |
| | ACTOR_CHURN | |
| |=================| |
+--------------> | ActorChurn=True | ------------+
| |
+-----------------+
Similar for the Partner-churn-detection.
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
Initial version
v2:
Rebase
drivers/net/bonding/bond_3ad.c | 56 +++++++++++++++++++++++++++++++++++++--
drivers/net/bonding/bond_procfs.c | 40 +++++++++++++++++++++++++---
include/net/bond_3ad.h | 29 ++++++++++++++++++++
3 files changed, 119 insertions(+), 6 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 14f2ebe786c5..2a69095266c1 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -38,6 +38,7 @@
#define AD_STANDBY 0x2
#define AD_MAX_TX_IN_SECOND 3
#define AD_COLLECTOR_MAX_DELAY 0
+#define AD_MONITOR_CHURNED 0x1000
/* Timer definitions (43.4.4 in the 802.3ad standard) */
#define AD_FAST_PERIODIC_TIME 1
@@ -1013,16 +1014,19 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
/* check if state machine should change state */
/* first, check if port was reinitialized */
- if (port->sm_vars & AD_PORT_BEGIN)
+ if (port->sm_vars & AD_PORT_BEGIN) {
port->sm_rx_state = AD_RX_INITIALIZE;
+ port->sm_vars |= AD_MONITOR_CHURNED;
/* check if port is not enabled */
- else if (!(port->sm_vars & AD_PORT_BEGIN)
+ } else if (!(port->sm_vars & AD_PORT_BEGIN)
&& !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED))
port->sm_rx_state = AD_RX_PORT_DISABLED;
/* check if new lacpdu arrived */
else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) ||
(port->sm_rx_state == AD_RX_DEFAULTED) ||
(port->sm_rx_state == AD_RX_CURRENT))) {
+ if (port->sm_rx_state != AD_RX_CURRENT)
+ port->sm_vars |= AD_MONITOR_CHURNED;
port->sm_rx_timer_counter = 0;
port->sm_rx_state = AD_RX_CURRENT;
} else {
@@ -1100,9 +1104,11 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
*/
port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
port->sm_vars &= ~AD_PORT_MATCHED;
+ port->partner_oper.port_state |= AD_STATE_LACP_TIMEOUT;
port->partner_oper.port_state |= AD_STATE_LACP_ACTIVITY;
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
port->actor_oper_port_state |= AD_STATE_EXPIRED;
+ port->sm_vars |= AD_MONITOR_CHURNED;
break;
case AD_RX_DEFAULTED:
__update_default_selected(port);
@@ -1131,6 +1137,44 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
}
}
+/* ad_churn_machine - handle port churn's state machine
+ * @port: the port we're looking at
+ *
+ */
+static void ad_churn_machine(struct port *port)
+{
+ if (port->sm_vars & AD_MONITOR_CHURNED) {
+ port->sm_vars &= ~AD_MONITOR_CHURNED;
+ port->sm_churn_actor_state = AD_CHURN_MONITOR;
+ port->sm_churn_partner_state = AD_CHURN_MONITOR;
+ port->sm_churn_actor_timer_counter =
+ __ad_timer_to_ticks(AD_ACTOR_CHURN_TIMER, 0);
+ port->sm_churn_partner_timer_counter =
+ __ad_timer_to_ticks(AD_PARTNER_CHURN_TIMER, 0);
+ return;
+ }
+ if (port->sm_churn_actor_timer_counter &&
+ !(--port->sm_churn_actor_timer_counter) &&
+ (port->sm_churn_actor_state == AD_CHURN_MONITOR)) {
+ if (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION) {
+ port->sm_churn_actor_state = AD_NO_CHURN;
+ } else {
+ port->churn_actor_count++;
+ port->sm_churn_actor_state = AD_CHURN;
+ }
+ }
+ if (port->sm_churn_partner_timer_counter &&
+ !(--port->sm_churn_partner_timer_counter) &&
+ (port->sm_churn_partner_state == AD_CHURN_MONITOR)) {
+ if (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) {
+ port->sm_churn_partner_state = AD_NO_CHURN;
+ } else {
+ port->churn_partner_count++;
+ port->sm_churn_partner_state = AD_CHURN;
+ }
+ }
+}
+
/**
* ad_tx_machine - handle a port's tx state machine
* @port: the port we're looking at
@@ -1745,6 +1789,13 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
port->next_port_in_aggregator = NULL;
port->transaction_id = 0;
+ port->sm_churn_actor_timer_counter = 0;
+ port->sm_churn_actor_state = 0;
+ port->churn_actor_count = 0;
+ port->sm_churn_partner_timer_counter = 0;
+ port->sm_churn_partner_state = 0;
+ port->churn_partner_count = 0;
+
memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu));
}
}
@@ -2164,6 +2215,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
ad_port_selection_logic(port, &update_slave_arr);
ad_mux_machine(port, &update_slave_arr);
ad_tx_machine(port);
+ ad_churn_machine(port);
/* turn off the BEGIN bit, since we already handled it */
if (port->sm_vars & AD_PORT_BEGIN)
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 976f5ad2a0f2..83095a0b4b90 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -178,13 +178,45 @@ static void bond_info_show_slave(struct seq_file *seq,
seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr);
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
- const struct aggregator *agg
- = SLAVE_AD_INFO(slave)->port.aggregator;
+ const struct port *port = &SLAVE_AD_INFO(slave)->port;
+ const struct aggregator *agg = port->aggregator;
- if (agg)
+ if (agg) {
seq_printf(seq, "Aggregator ID: %d\n",
agg->aggregator_identifier);
- else
+ seq_printf(seq, "Actor Churn State: %s\n",
+ bond_3ad_churn_desc(port->sm_churn_actor_state));
+ seq_printf(seq, "Partner Churn State: %s\n",
+ bond_3ad_churn_desc(port->sm_churn_partner_state));
+ seq_printf(seq, "Actor Churned Count: %d\n",
+ port->churn_actor_count);
+ seq_printf(seq, "Partner Churned Count: %d\n",
+ port->churn_partner_count);
+
+ seq_puts(seq, "details actor lacp pdu:\n");
+ seq_printf(seq, " system priority: %d\n",
+ port->actor_system_priority);
+ seq_printf(seq, " port key: %d\n",
+ port->actor_oper_port_key);
+ seq_printf(seq, " port priority: %d\n",
+ port->actor_port_priority);
+ seq_printf(seq, " port number: %d\n",
+ port->actor_port_number);
+ seq_printf(seq, " port state: %d\n",
+ port->actor_oper_port_state);
+
+ seq_puts(seq, "details partner lacp pdu:\n");
+ seq_printf(seq, " system priority: %d\n",
+ port->partner_oper.system_priority);
+ seq_printf(seq, " oper key: %d\n",
+ port->partner_oper.key);
+ seq_printf(seq, " port priority: %d\n",
+ port->partner_oper.port_priority);
+ seq_printf(seq, " port number: %d\n",
+ port->partner_oper.port_number);
+ seq_printf(seq, " port state: %d\n",
+ port->partner_oper.port_state);
+ } else
seq_puts(seq, "Aggregator ID: N/A\n");
}
seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id);
diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h
index 6c455c646d61..170f8926ff66 100644
--- a/include/net/bond_3ad.h
+++ b/include/net/bond_3ad.h
@@ -82,6 +82,13 @@ typedef enum {
AD_TRANSMIT /* tx Machine */
} tx_states_t;
+/* churn machine states(43.4.17 in the 802.3ad standard) */
+typedef enum {
+ AD_CHURN_MONITOR, /* monitoring for churn */
+ AD_CHURN, /* churn detected (error) */
+ AD_NO_CHURN /* no churn (no error) */
+} churn_state_t;
+
/* rx indication types */
typedef enum {
AD_TYPE_LACPDU = 1, /* type lacpdu */
@@ -229,6 +236,12 @@ typedef struct port {
u16 sm_mux_timer_counter; /* state machine mux timer counter */
tx_states_t sm_tx_state; /* state machine tx state */
u16 sm_tx_timer_counter; /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */
+ u16 sm_churn_actor_timer_counter;
+ u16 sm_churn_partner_timer_counter;
+ u32 churn_actor_count;
+ u32 churn_partner_count;
+ churn_state_t sm_churn_actor_state;
+ churn_state_t sm_churn_partner_state;
struct slave *slave; /* pointer to the bond slave that this port belongs to */
struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
@@ -262,6 +275,22 @@ struct ad_slave_info {
u16 id;
};
+static inline const char *bond_3ad_churn_desc(churn_state_t state)
+{
+ static const char *const churn_description[] =
+ { "monitoring",
+ "churned",
+ "none",
+ "unknown"
+ };
+ int max_size = sizeof(churn_description) / sizeof(churn_description[0]);
+
+ if (state >= max_size)
+ state = max_size - 1;
+
+ return churn_description[state];
+}
+
/* ========== AD Exported functions to the main bonding code ========== */
void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
void bond_3ad_bind_slave(struct slave *slave);
--
2.2.0.rc0.207.ga3a616c
^ permalink raw reply related
* [PATCH next v2 5/6] bonding: Allow userspace to set actors' macaddr in an AD-system.
From: Mahesh Bandewar @ 2015-02-11 22:05 UTC (permalink / raw)
To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
Nikolay Aleksandrov, David Miller
Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet
In an AD system, the communication between actor and partner is the
business between these two entiries. In the current setup anyone on the
same L2 can "guess" the LACPDU contents and then possibly send the
spoofed LACPDUs and trick the partner causing connectivity issues for
the AD system. This patch allows to use a random mac-address obscuring
it's identity making it harder for someone in the L2 is do the same thing.
This patch allows user-space to set the mac-address on the bonding device.
This mac-address can not be NULL or a Multicast. If the mac-address is set
from user-space; kernel will honor it and will not overwrite it. In the
absense (value from user space); the logic will default to using the
masters' mac as the mac-address for the AD system.
It can be set using example code below -
# modprobe bonding mode=4
# sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
$(( (RANDOM & 0xFE) | 0x02 )) \
$(( RANDOM & 0xFF )) \
$(( RANDOM & 0xFF )) \
$(( RANDOM & 0xFF )) \
$(( RANDOM & 0xFF )) \
$(( RANDOM & 0xFF )))
# echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system
# echo +eth1 > /sys/class/net/bond0/bonding/slaves
...
# ip link set bond0 up
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
Initial version
v2:
Renamed ad_actor_system_mac_address to ad_actor_system
Documentation/networking/bonding.txt | 12 ++++++++++++
drivers/net/bonding/bond_3ad.c | 7 ++++++-
drivers/net/bonding/bond_main.c | 1 +
drivers/net/bonding/bond_options.c | 29 +++++++++++++++++++++++++++++
drivers/net/bonding/bond_procfs.c | 6 ++++++
drivers/net/bonding/bond_sysfs.c | 15 +++++++++++++++
include/net/bond_options.h | 1 +
include/net/bonding.h | 1 +
8 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index f19d888651b8..f0d93c58cdb0 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -187,6 +187,18 @@ ad_actor_sys_prio
This paramter has effect only in 802.3ad mode and is available through
SysFs interface.
+ad_actor_system
+
+ In an AD system, this specifies the mac-address for the actor in
+ protocol packet exchanges (LACPDUs). The value cannot be NULL or
+ multicast. It is preferred to have the local-admin bit set for this
+ mac but driver does not enforce it. If the value is not given then
+ system defaults to using the masters' mac address as actors' system
+ address.
+
+ This paramter has effect only in 802.3ad mode and is available through
+ SysFs interface.
+
ad_select
Specifies the 802.3ad aggregation selection logic to use. The
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 46aa847a0132..4b28d8cc0e84 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1914,7 +1914,12 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
BOND_AD_INFO(bond).system.sys_priority =
bond->params.ad_actor_sys_prio;
- BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
+ if (is_zero_ether_addr(bond->params.ad_actor_system))
+ BOND_AD_INFO(bond).system.sys_mac_addr =
+ *((struct mac_addr *)bond->dev->dev_addr);
+ else
+ BOND_AD_INFO(bond).system.sys_mac_addr =
+ *((struct mac_addr *)bond->params.ad_actor_system);
/* initialize how many times this module is called in one
* second (should be about every 100ms)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index f8f6a80231b6..f899f3053e82 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4474,6 +4474,7 @@ static int bond_check_params(struct bond_params *params)
params->packets_per_slave = packets_per_slave;
params->tlb_dynamic_lb = 1; /* Default value */
params->ad_actor_sys_prio = ad_actor_sys_prio;
+ eth_zero_addr(params->ad_actor_system);
if (packets_per_slave > 0) {
params->reciprocal_packets_per_slave =
reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 05d5e735eaec..f2c011b3ea33 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -72,6 +72,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
const struct bond_opt_value *newval);
+static int bond_option_ad_actor_system_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
static const struct bond_opt_value bond_mode_tbl[] = {
@@ -396,6 +398,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
.values = bond_ad_actor_sys_prio_tbl,
.set = bond_option_ad_actor_sys_prio_set,
},
+ [BOND_OPT_AD_ACTOR_SYSTEM] = {
+ .id = BOND_OPT_AD_ACTOR_SYSTEM,
+ .name = "ad_actor_system",
+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+ .flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN,
+ .set = bond_option_ad_actor_system_set,
+ },
};
/* Searches for an option by name */
@@ -1376,3 +1385,23 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
bond->params.ad_actor_sys_prio = newval->value;
return 0;
}
+
+static int bond_option_ad_actor_system_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ u8 macaddr[ETH_ALEN];
+ int i;
+
+ i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &macaddr[0], &macaddr[1], &macaddr[2],
+ &macaddr[3], &macaddr[4], &macaddr[5]);
+
+ if (i != ETH_ALEN || !is_valid_ether_addr(macaddr)) {
+ netdev_err(bond->dev, "Invalid MAC address.\n");
+ return -EINVAL;
+ }
+
+ ether_addr_copy(bond->params.ad_actor_system, macaddr);
+
+ return 0;
+}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 9e33c48886ef..81452ced852f 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -136,6 +136,8 @@ static void bond_info_show_master(struct seq_file *seq)
optval->string);
seq_printf(seq, "System priority: %d\n",
BOND_AD_INFO(bond).system.sys_priority);
+ seq_printf(seq, "System MAC address: %pM\n",
+ &BOND_AD_INFO(bond).system.sys_mac_addr);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n",
@@ -198,6 +200,8 @@ static void bond_info_show_slave(struct seq_file *seq,
seq_puts(seq, "details actor lacp pdu:\n");
seq_printf(seq, " system priority: %d\n",
port->actor_system_priority);
+ seq_printf(seq, " system mac address: %pM\n",
+ &port->actor_system);
seq_printf(seq, " port key: %d\n",
port->actor_oper_port_key);
seq_printf(seq, " port priority: %d\n",
@@ -210,6 +214,8 @@ static void bond_info_show_slave(struct seq_file *seq,
seq_puts(seq, "details partner lacp pdu:\n");
seq_printf(seq, " system priority: %d\n",
port->partner_oper.system_priority);
+ seq_printf(seq, " system mac address: %pM\n",
+ &port->partner_oper.system);
seq_printf(seq, " oper key: %d\n",
port->partner_oper.key);
seq_printf(seq, " port priority: %d\n",
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 1a4a591a58c9..efa994243a2d 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -706,6 +706,20 @@ static ssize_t bonding_show_ad_actor_sys_prio(struct device *d,
static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR,
bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option);
+static ssize_t bonding_show_ad_actor_system(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD)
+ return sprintf(buf, "%pM\n", bond->params.ad_actor_system);
+
+ return 0;
+}
+static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR,
+ bonding_show_ad_actor_system, bonding_sysfs_store_option);
+
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
@@ -740,6 +754,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_packets_per_slave.attr,
&dev_attr_tlb_dynamic_lb.attr,
&dev_attr_ad_actor_sys_prio.attr,
+ &dev_attr_ad_actor_system.attr,
NULL,
};
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index 894002a2620f..eeeefa1d3cd8 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -64,6 +64,7 @@ enum {
BOND_OPT_SLAVES,
BOND_OPT_TLB_DYNAMIC_LB,
BOND_OPT_AD_ACTOR_SYS_PRIO,
+ BOND_OPT_AD_ACTOR_SYSTEM,
BOND_OPT_LAST
};
diff --git a/include/net/bonding.h b/include/net/bonding.h
index cb4587f6516e..f24f9862cea9 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -144,6 +144,7 @@ struct bond_params {
int tlb_dynamic_lb;
struct reciprocal_value reciprocal_packets_per_slave;
u16 ad_actor_sys_prio;
+ u8 ad_actor_system[ETH_ALEN];
};
struct bond_parm_tbl {
--
2.2.0.rc0.207.ga3a616c
^ permalink raw reply related
* [PATCH next v2 4/6] bonding: Allow userspace to set actors' system_priority in AD system
From: Mahesh Bandewar @ 2015-02-11 22:05 UTC (permalink / raw)
To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
Nikolay Aleksandrov, David Miller
Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet
This patch allows user to randomize the system-priority in an ad-system.
The allowed range is 1 - 0xFFFF while default value is 0xFFFF. If user
does not specify this value, the system defaults to 0xFFFF, which is
what it was before this patch.
Following example code could set the value -
# modprobe bonding mode=4
# sys_prio=$(( 1 + RANDOM + RANDOM ))
# echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio
# echo +eth1 > /sys/class/net/bond0/bonding/slaves
...
# ip link set bond0 up
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
Initial version
v2:
Rename ad_actor_system_priority to ad_actor_sys_prio
Documentation/networking/bonding.txt | 9 +++++++++
drivers/net/bonding/bond_3ad.c | 5 ++++-
drivers/net/bonding/bond_main.c | 14 ++++++++++++++
drivers/net/bonding/bond_options.c | 29 ++++++++++++++++++++++++++++-
drivers/net/bonding/bond_procfs.c | 2 ++
drivers/net/bonding/bond_sysfs.c | 15 +++++++++++++++
include/net/bond_options.h | 1 +
include/net/bonding.h | 1 +
8 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 83bf4986baea..f19d888651b8 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -178,6 +178,15 @@ active_slave
active slave, or the empty string if there is no active slave or
the current mode does not use an active slave.
+ad_actor_sys_prio
+
+ In an AD system, this specifies the system priority. The allowed range
+ is 1 - 65535. If the value is not specified, it takes 65535 as the
+ default value.
+
+ This paramter has effect only in 802.3ad mode and is available through
+ SysFs interface.
+
ad_select
Specifies the 802.3ad aggregation selection logic to use. The
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 2a69095266c1..46aa847a0132 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1912,7 +1912,8 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
BOND_AD_INFO(bond).aggregator_identifier = 0;
- BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
+ BOND_AD_INFO(bond).system.sys_priority =
+ bond->params.ad_actor_sys_prio;
BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
/* initialize how many times this module is called in one
@@ -1963,6 +1964,8 @@ void bond_3ad_bind_slave(struct slave *slave)
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
/* actor system is the bond's system */
port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
+ port->actor_system_priority =
+ BOND_AD_INFO(bond).system.sys_priority;
/* tx timer(to verify that no more than MAX_TX_IN_SECOND
* lacpdu's are sent in one second)
*/
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8433fe464f95..f8f6a80231b6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4138,6 +4138,7 @@ static int bond_check_params(struct bond_params *params)
struct bond_opt_value newval;
const struct bond_opt_value *valptr;
int arp_all_targets_value;
+ u16 ad_actor_sys_prio = 0;
/* Convert string parameters. */
if (mode) {
@@ -4432,6 +4433,18 @@ static int bond_check_params(struct bond_params *params)
fail_over_mac_value = BOND_FOM_NONE;
}
+ if (bond_mode == BOND_MODE_8023AD) {
+ bond_opt_initstr(&newval, "default");
+ valptr = bond_opt_parse(
+ bond_opt_get(BOND_OPT_AD_ACTOR_SYS_PRIO),
+ &newval);
+ if (!valptr) {
+ pr_err("Error: No ad_actor_sys_prio default value");
+ return -EINVAL;
+ }
+ ad_actor_sys_prio = valptr->value;
+ }
+
if (lp_interval == 0) {
pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
@@ -4460,6 +4473,7 @@ static int bond_check_params(struct bond_params *params)
params->lp_interval = lp_interval;
params->packets_per_slave = packets_per_slave;
params->tlb_dynamic_lb = 1; /* Default value */
+ params->ad_actor_sys_prio = ad_actor_sys_prio;
if (packets_per_slave > 0) {
params->reciprocal_packets_per_slave =
reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 4df28943d222..05d5e735eaec 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -70,6 +70,8 @@ static int bond_option_slaves_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval);
+static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
static const struct bond_opt_value bond_mode_tbl[] = {
@@ -186,6 +188,12 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
{ NULL, -1, 0}
};
+static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
+ { "minval", 1, BOND_VALFLAG_MIN},
+ { "maxval", 65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT},
+ { NULL, -1, 0},
+};
+
static const struct bond_option bond_opts[BOND_OPT_LAST] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
@@ -379,7 +387,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
.values = bond_tlb_dynamic_lb_tbl,
.flags = BOND_OPTFLAG_IFDOWN,
.set = bond_option_tlb_dynamic_lb_set,
- }
+ },
+ [BOND_OPT_AD_ACTOR_SYS_PRIO] = {
+ .id = BOND_OPT_AD_ACTOR_SYS_PRIO,
+ .name = "ad_actor_sys_prio",
+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+ .flags = BOND_OPTFLAG_IFDOWN,
+ .values = bond_ad_actor_sys_prio_tbl,
+ .set = bond_option_ad_actor_sys_prio_set,
+ },
};
/* Searches for an option by name */
@@ -1349,3 +1365,14 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
return 0;
}
+
+
+static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ netdev_info(bond->dev, "Setting ad_actor_sys_prio to (%llu)\n",
+ newval->value);
+
+ bond->params.ad_actor_sys_prio = newval->value;
+ return 0;
+}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 83095a0b4b90..9e33c48886ef 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -134,6 +134,8 @@ static void bond_info_show_master(struct seq_file *seq)
bond->params.ad_select);
seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
optval->string);
+ seq_printf(seq, "System priority: %d\n",
+ BOND_AD_INFO(bond).system.sys_priority);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n",
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 7e9e151d4d61..1a4a591a58c9 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -692,6 +692,20 @@ static ssize_t bonding_show_packets_per_slave(struct device *d,
static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR,
bonding_show_packets_per_slave, bonding_sysfs_store_option);
+static ssize_t bonding_show_ad_actor_sys_prio(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD)
+ return sprintf(buf, "%hu\n", bond->params.ad_actor_sys_prio);
+
+ return 0;
+}
+static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR,
+ bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option);
+
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
@@ -725,6 +739,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_lp_interval.attr,
&dev_attr_packets_per_slave.attr,
&dev_attr_tlb_dynamic_lb.attr,
+ &dev_attr_ad_actor_sys_prio.attr,
NULL,
};
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index ea6546d2c946..894002a2620f 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -63,6 +63,7 @@ enum {
BOND_OPT_LP_INTERVAL,
BOND_OPT_SLAVES,
BOND_OPT_TLB_DYNAMIC_LB,
+ BOND_OPT_AD_ACTOR_SYS_PRIO,
BOND_OPT_LAST
};
diff --git a/include/net/bonding.h b/include/net/bonding.h
index fda6feeb6c1f..cb4587f6516e 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -143,6 +143,7 @@ struct bond_params {
int packets_per_slave;
int tlb_dynamic_lb;
struct reciprocal_value reciprocal_packets_per_slave;
+ u16 ad_actor_sys_prio;
};
struct bond_parm_tbl {
--
2.2.0.rc0.207.ga3a616c
^ permalink raw reply related
* [PATCH next v2 1/6] bonding: Verify RX LACPDU has proper dest mac-addr
From: Mahesh Bandewar @ 2015-02-11 22:05 UTC (permalink / raw)
To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
Nikolay Aleksandrov, David Miller
Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet
The 802.1AX standard states:
"The DA in LACPDUs is the Slow_Protocols_Multicast address."
This patch enforces that and drops LACPDUs with destination MAC
addresses other than Slow_Protocols_Multicast address
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
Initial version
v2:
Rebase
drivers/net/bonding/bond_3ad.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index cfc4a9c1000a..9b436696b95e 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2485,6 +2485,9 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
if (skb->protocol != PKT_TYPE_LACPDU)
return RX_HANDLER_ANOTHER;
+ if (!MAC_ADDRESS_EQUAL(eth_hdr(skb)->h_dest, lacpdu_mcast_addr))
+ return RX_HANDLER_ANOTHER;
+
lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
if (!lacpdu)
return RX_HANDLER_ANOTHER;
--
2.2.0.rc0.207.ga3a616c
^ permalink raw reply related
* [PATCH next v2 6/6] bonding: Implement user key part of port_key in an AD system.
From: Mahesh Bandewar @ 2015-02-11 22:05 UTC (permalink / raw)
To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
Nikolay Aleksandrov, David Miller
Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet
The port key has three components - user-key, speed-part, and duplex-part.
The LSBit is for the duplex-part, next 5 bits are for the speed while the
remaining 10 bits are the user defined key bits. Get these 10 bits
from the user-space (through the SysFs interface) and use it to form the
admin port-key. Allowed range for the user-key is 0 - 1023 (10 bits). If
it is not provided then use zero for the user-key-bits (default).
It can set using following example code -
# modprobe bonding mode=4
# usr_port_key=$(( RANDOM & 0x3FF ))
# echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key
# echo +eth1 > /sys/class/net/bond0/bonding/slaves
...
# ip link set bond0 up
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
Initial version
v2:
Renamed ad_actor_user_port_key ad_user_port_key
Documentation/networking/bonding.txt | 62 ++++++++++++++++++++++++++++++++++++
drivers/net/bonding/bond_3ad.c | 14 ++++----
drivers/net/bonding/bond_main.c | 10 ++++++
drivers/net/bonding/bond_options.c | 26 +++++++++++++++
drivers/net/bonding/bond_sysfs.c | 15 +++++++++
include/net/bond_options.h | 1 +
include/net/bonding.h | 1 +
7 files changed, 122 insertions(+), 7 deletions(-)
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index f0d93c58cdb0..da22956b408f 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -51,6 +51,7 @@ Table of Contents
3.4 Configuring Bonding Manually via Sysfs
3.5 Configuration with Interfaces Support
3.6 Overriding Configuration for Special Cases
+3.7 Configuring LACP for 802.3ad mode in a more secure way
4. Querying Bonding Configuration
4.1 Bonding Configuration
@@ -241,6 +242,21 @@ ad_select
This option was added in bonding version 3.4.0.
+ad_user_port_key
+
+ In an AD system, the port-key has three parts as shown below -
+
+ Bits Use
+ 00 Duplex
+ 01-05 Speed
+ 06-15 User-defined
+
+ This defines the upper 10 bits of the port key. The values can be
+ from 0 - 1023. If not given, the system defaults to 0.
+
+ This paramter has effect only in 802.3ad mode and is available through
+ SysFs interface.
+
all_slaves_active
Specifies that duplicate frames (received on inactive ports) should be
@@ -1643,6 +1659,52 @@ output port selection.
This feature first appeared in bonding driver version 3.7.0 and support for
output slave selection was limited to round-robin and active-backup modes.
+3.7 Configuring LACP for 802.3ad mode in a more secure way
+----------------------------------------------------------
+
+When using 802.3ad bonding mode, the Actor (host) and Partner (switch)
+exchange LACPDUs. These LACPDUs cannot be sniffed, because they are
+destined to link local mac addresses (which switches/bridges are not
+supposed to forward). However, most of the values are easily predictable
+or are simply the machine's MAC address (which is trivially known to all
+other hosts in the same L2). This implies that other machines in the L2
+domain can spoof LACPDU packets from other hosts to the switch and potentially
+cause mayhem by joining (from the point of view of the switch) another
+machine's aggregate, thus receiving a portion of that hosts incoming
+traffic and / or spoofing traffic from that machine themselves (potentially
+even successfully terminating some portion of flows). Though this is not
+a likely scenario, one could avoid this possibility by simply configuring
+few bonding parameters:
+
+ (a) ad_actor_system : You can set a random mac-address that can be used for
+ these LACPDU exchanges. The value can not be either NULL or Multicast.
+ Also it's preferable to set the local-admin bit. This can be done using
+ the following shell code -
+
+ # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
+ $(( (RANDOM & 0xFE) | 0x02 )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )))
+ # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system
+
+ (b) ad_actor_sys_prio : Randomize the system priority. The default value
+ is 65535, but system can take the value from 1 - 65535. You can do this
+ this using the following shell code -
+
+ # sys_prio=$(( 1 + RANDOM + RANDOM ))
+ # echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio
+
+ (c) ad_user_port_key : Use the user portion of the port-key. The default
+ keeps this empty. These the upper 10 bits of the port-key and value
+ ranges from 0 - 1023. You can do this using the following shell code -
+
+ # usr_port_key=$(( RANDOM & 0x3FF ))
+ # echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key
+
+
4 Querying Bonding Configuration
=================================
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 4b28d8cc0e84..d39d16d7711a 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -75,10 +75,10 @@
/* Port Key definitions
* key is determined according to the link speed, duplex and
* user key (which is yet not supported)
- * --------------------------------------------------------------
- * Port key : | User key | Speed | Duplex |
- * --------------------------------------------------------------
- * 16 6 1 0
+ * --------------------------------------------------------------
+ * Port key | User key (10 bits) | Speed (5 bits) | Duplex|
+ * --------------------------------------------------------------
+ * |15 6|5 1|0
*/
#define AD_DUPLEX_KEY_MASKS 0x1
#define AD_SPEED_KEY_MASKS 0x3E
@@ -1955,10 +1955,10 @@ void bond_3ad_bind_slave(struct slave *slave)
port->slave = slave;
port->actor_port_number = SLAVE_AD_INFO(slave)->id;
- /* key is determined according to the link speed, duplex and user key(which
- * is yet not supported)
+ /* key is determined according to the link speed, duplex and
+ * user key
*/
- port->actor_admin_port_key = 0;
+ port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
port->actor_admin_port_key |= __get_duplex(port);
port->actor_admin_port_key |= (__get_link_speed(port) << 1);
port->actor_oper_port_key = port->actor_admin_port_key;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index f899f3053e82..e5a9344dae26 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4139,6 +4139,7 @@ static int bond_check_params(struct bond_params *params)
const struct bond_opt_value *valptr;
int arp_all_targets_value;
u16 ad_actor_sys_prio = 0;
+ u16 ad_user_port_key = 0;
/* Convert string parameters. */
if (mode) {
@@ -4443,6 +4444,14 @@ static int bond_check_params(struct bond_params *params)
return -EINVAL;
}
ad_actor_sys_prio = valptr->value;
+
+ valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_USER_PORT_KEY),
+ &newval);
+ if (!valptr) {
+ pr_err("Error: No ad_user_port_key default value");
+ return -EINVAL;
+ }
+ ad_user_port_key = valptr->value;
}
if (lp_interval == 0) {
@@ -4475,6 +4484,7 @@ static int bond_check_params(struct bond_params *params)
params->tlb_dynamic_lb = 1; /* Default value */
params->ad_actor_sys_prio = ad_actor_sys_prio;
eth_zero_addr(params->ad_actor_system);
+ params->ad_user_port_key = ad_user_port_key;
if (packets_per_slave > 0) {
params->reciprocal_packets_per_slave =
reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index f2c011b3ea33..eb0a8e9fafe7 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -74,6 +74,8 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ad_actor_system_set(struct bonding *bond,
const struct bond_opt_value *newval);
+static int bond_option_ad_user_port_key_set(struct bonding *bond,
+ const struct bond_opt_value *newval);
static const struct bond_opt_value bond_mode_tbl[] = {
@@ -196,6 +198,12 @@ static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
{ NULL, -1, 0},
};
+static const struct bond_opt_value bond_ad_user_port_key_tbl[] = {
+ { "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
+ { "maxval", 1023, BOND_VALFLAG_MAX},
+ { NULL, -1, 0},
+};
+
static const struct bond_option bond_opts[BOND_OPT_LAST] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
@@ -405,6 +413,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
.flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN,
.set = bond_option_ad_actor_system_set,
},
+ [BOND_OPT_AD_USER_PORT_KEY] = {
+ .id = BOND_OPT_AD_USER_PORT_KEY,
+ .name = "ad_user_port_key",
+ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+ .flags = BOND_OPTFLAG_IFDOWN,
+ .values = bond_ad_user_port_key_tbl,
+ .set = bond_option_ad_user_port_key_set,
+ }
};
/* Searches for an option by name */
@@ -1405,3 +1421,13 @@ static int bond_option_ad_actor_system_set(struct bonding *bond,
return 0;
}
+
+static int bond_option_ad_user_port_key_set(struct bonding *bond,
+ const struct bond_opt_value *newval)
+{
+ netdev_info(bond->dev, "Setting ad_user_port_key to (%llu)\n",
+ newval->value);
+
+ bond->params.ad_user_port_key = newval->value;
+ return 0;
+}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index efa994243a2d..a6950647d99d 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -720,6 +720,20 @@ static ssize_t bonding_show_ad_actor_system(struct device *d,
static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR,
bonding_show_ad_actor_system, bonding_sysfs_store_option);
+static ssize_t bonding_show_ad_user_port_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD)
+ return sprintf(buf, "%hu\n", bond->params.ad_user_port_key);
+
+ return 0;
+}
+static DEVICE_ATTR(ad_user_port_key, S_IRUGO | S_IWUSR,
+ bonding_show_ad_user_port_key, bonding_sysfs_store_option);
+
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
@@ -755,6 +769,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_tlb_dynamic_lb.attr,
&dev_attr_ad_actor_sys_prio.attr,
&dev_attr_ad_actor_system.attr,
+ &dev_attr_ad_user_port_key.attr,
NULL,
};
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index eeeefa1d3cd8..c28aca25320e 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -65,6 +65,7 @@ enum {
BOND_OPT_TLB_DYNAMIC_LB,
BOND_OPT_AD_ACTOR_SYS_PRIO,
BOND_OPT_AD_ACTOR_SYSTEM,
+ BOND_OPT_AD_USER_PORT_KEY,
BOND_OPT_LAST
};
diff --git a/include/net/bonding.h b/include/net/bonding.h
index f24f9862cea9..0ac45b4f7f2a 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -144,6 +144,7 @@ struct bond_params {
int tlb_dynamic_lb;
struct reciprocal_value reciprocal_packets_per_slave;
u16 ad_actor_sys_prio;
+ u16 ad_user_port_key;
u8 ad_actor_system[ETH_ALEN];
};
--
2.2.0.rc0.207.ga3a616c
^ permalink raw reply related
* [PATCH next v2 2/6] bonding: implement bond_poll_controller()
From: Mahesh Bandewar @ 2015-02-11 22:05 UTC (permalink / raw)
To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
Nikolay Aleksandrov, David Miller
Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet
This patches implements the poll_controller support for all
bonding driver. If the slaves have poll_controller net_op defined,
this implementation calls them. This is mode agnostic implementation
and iterates through all slaves (based on mode) and calls respective
handler.
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
Initial version
v2:
Eliminate bool variable.
drivers/net/bonding/bond_3ad.c | 24 ++++++++++++++++++++++++
drivers/net/bonding/bond_main.c | 33 +++++++++++++++++++++++++++++++++
include/net/bond_3ad.h | 1 +
3 files changed, 58 insertions(+)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 9b436696b95e..14f2ebe786c5 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2477,6 +2477,30 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
return ret;
}
+#define BOND_3AD_PORT_OPERATIONAL \
+ (AD_STATE_DISTRIBUTING | AD_STATE_COLLECTING | \
+ AD_STATE_SYNCHRONIZATION | AD_STATE_AGGREGATION)
+
+static int bond_3ad_port_operational(struct slave *slave)
+{
+ port_t *port = &SLAVE_AD_INFO(slave)->port;
+
+ return bond_slave_can_tx(slave) &&
+ (port->actor_oper_port_state & port->partner_oper.port_state &
+ BOND_3AD_PORT_OPERATIONAL) == BOND_3AD_PORT_OPERATIONAL;
+}
+
+/* bond_3ad_port_is_active - check if a slave port is active or not. A port
+ * is active when it can forward traffic.
+ *
+ * @slave: slave port to check state for.
+ * Returns: 0 if not active else is active.
+ */
+int bond_3ad_port_is_active(struct slave *slave)
+{
+ return bond_3ad_port_operational(slave);
+}
+
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave)
{
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b979c265fc51..8433fe464f95 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -928,6 +928,39 @@ static inline void slave_disable_netpoll(struct slave *slave)
static void bond_poll_controller(struct net_device *bond_dev)
{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave = NULL;
+ struct list_head *iter;
+ struct ad_info ad_info;
+ struct netpoll_info *ni;
+ const struct net_device_ops *ops;
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD)
+ if (bond_3ad_get_active_agg_info(bond, &ad_info))
+ return;
+
+ bond_for_each_slave(bond, slave, iter) {
+ ops = slave->dev->netdev_ops;
+ if (!bond_slave_is_up(slave) || !ops->ndo_poll_controller)
+ continue;
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ struct aggregator *agg =
+ SLAVE_AD_INFO(slave)->port.aggregator;
+
+ if (agg && agg->aggregator_identifier !=
+ ad_info.aggregator_id)
+ continue;
+ if (!bond_3ad_port_is_active(slave) || ad_info.ports != 1)
+ continue;
+ }
+
+ ni = rcu_dereference_bh(slave->dev->npinfo);
+ if (down_trylock(&ni->dev_lock))
+ continue;
+ ops->ndo_poll_controller(slave->dev);
+ up(&ni->dev_lock);
+ }
}
static void bond_netpoll_cleanup(struct net_device *bond_dev)
diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h
index f04cdbb7848e..6c455c646d61 100644
--- a/include/net/bond_3ad.h
+++ b/include/net/bond_3ad.h
@@ -278,5 +278,6 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave);
int bond_3ad_set_carrier(struct bonding *bond);
void bond_3ad_update_lacp_rate(struct bonding *bond);
+int bond_3ad_port_is_active(struct slave *slave);
#endif /* _NET_BOND_3AD_H */
--
2.2.0.rc0.207.ga3a616c
^ permalink raw reply related
* Re: [PATCH 0/2] Netfilter updates for net-next
From: David Miller @ 2015-02-11 22:27 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1423546474-3539-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Tue, 10 Feb 2015 06:34:32 +0100
> The following patchset contains two small Netfilter updates for your
> net-next tree, they are:
>
> 1) Add ebtables support to nft_compat, from Arturo Borrero.
>
> 2) Fix missing validation of the SET_ID attribute in the lookup
> expressions, from Patrick McHardy.
Pulled, thanks Pablo.
^ permalink raw reply
* Re: [PATCH v2 net-next] ipv6: Partial checksum only UDP packets
From: David Miller @ 2015-02-11 22:32 UTC (permalink / raw)
To: vyasevich; +Cc: netdev, sd, vyasevic
In-Reply-To: <1423586249-5950-1-git-send-email-vyasevic@redhat.com>
From: Vladislav Yasevich <vyasevich@gmail.com>
Date: Tue, 10 Feb 2015 11:37:29 -0500
> ip6_append_data is used by other protocols and some of them can't
> be partially checksummed. Only partially checksum UDP protocol.
>
> Fixes: 32dce968dd987a (ipv6: Allow for partial checksums on non-ufo packets)
> Reported-by: Sabrina Dubroca <sd@queasysnail.net>
> Tested-by: Sabrina Dubroca <sd@queasysnail.net>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> ---
> v2: added tested-by tag and fixed compile issue with prior patch.
Applied, thanks.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox