Permalink
Browse files

teamd: lacp: use original hwaddr as source address in lacpdus

The team lacp runner sets the mac addresses of all member interfaces
to be the same value.  However, LACPDUs should carry an interface's
original (individual) MAC address.

The Addressing section (5.2.10 in 802.1ax) explains this:
        Protocol entities sourcing frames from within the Link Aggregation
        sublayer (e.g., LACP and the Marker protocol) use the MAC address
        of the MAC within an underlying port as the source address in
        frames transmitted through that port.  The MAC Client sees only
        the Aggregator and not the underlying MACs, and therefore uses
        the Aggregator's MAC address as the source address in transmitted
        frames.

Signed-off-by: Eric Kinzie <ehkinzie@gmail.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
  • Loading branch information...
1 parent 6d54ab1 commit c18a6349a7bd0a2d41d0193128b95a520479591f @ehkinzie ehkinzie committed with Apr 14, 2016
Showing with 58 additions and 10 deletions.
  1. +5 −0 teamd/teamd.h
  2. +37 −5 teamd/teamd_common.c
  3. +16 −5 teamd/teamd_runner_lacp.c
View
@@ -353,6 +353,10 @@ void teamd_balancer_port_removed(struct teamd_balancer *tb,
int teamd_hash_func_set(struct teamd_context *ctx);
+int teamd_packet_sock_open_type(int type, int *sock_p, const uint32_t ifindex,
+ const unsigned short family,
+ const struct sock_fprog *fprog,
+ const struct sock_fprog *alt_fprog);
int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
const unsigned short family,
const struct sock_fprog *fprog,
@@ -361,6 +365,7 @@ int teamd_getsockname_hwaddr(int sock, struct sockaddr_ll *addr,
size_t expected_len);
int teamd_sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
+int teamd_send(int sockfd, const void *buf, size_t len, int flags);
int teamd_recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t addrlen);
View
@@ -81,17 +81,17 @@ static int attach_filter(int sock, const struct sock_fprog *pref_fprog,
return 0;
}
-int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
- const unsigned short family,
- const struct sock_fprog *fprog,
- const struct sock_fprog *alt_fprog)
+int teamd_packet_sock_open_type(int type, int *sock_p, const uint32_t ifindex,
+ const unsigned short family,
+ const struct sock_fprog *fprog,
+ const struct sock_fprog *alt_fprog)
{
struct sockaddr_ll ll_my;
int sock;
int ret;
int err;
- sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ sock = socket(PF_PACKET, type, 0);
if (sock == -1) {
teamd_log_err("Failed to create packet socket.");
return -errno;
@@ -121,6 +121,15 @@ int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
return err;
}
+int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
+ const unsigned short family,
+ const struct sock_fprog *fprog,
+ const struct sock_fprog *alt_fprog)
+{
+ return teamd_packet_sock_open_type(SOCK_DGRAM, sock_p, ifindex, family,
+ fprog, alt_fprog);
+}
+
int teamd_getsockname_hwaddr(int sock, struct sockaddr_ll *addr,
size_t expected_len)
{
@@ -164,6 +173,29 @@ int teamd_sendto(int sockfd, const void *buf, size_t len, int flags,
return 0;
}
+int teamd_send(int sockfd, const void *buf, size_t len, int flags)
+{
+ ssize_t ret;
+
+resend:
+ ret = send(sockfd, buf, len, flags);
+ if (ret == -1) {
+ switch(errno) {
+ case EINTR:
+ goto resend;
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EADDRNOTAVAIL:
+ case ENXIO:
+ return 0;
+ default:
+ teamd_log_err("send failed.");
+ return -errno;
+ }
+ }
+ return 0;
+}
+
int teamd_recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t addrlen)
{
View
@@ -30,6 +30,7 @@
#include <errno.h>
#include <team.h>
#include <private/misc.h>
+#include <net/ethernet.h>
#include "teamd.h"
#include "teamd_config.h"
@@ -60,6 +61,7 @@ struct lacpdu_info {
} __attribute__((__packed__));
struct lacpdu {
+ struct ether_header hdr;
uint8_t subtype;
uint8_t version_number;
uint8_t actor_tlv_type;
@@ -1013,6 +1015,8 @@ static int lacpdu_send(struct lacp_port *lacp_port)
struct lacpdu lacpdu;
struct sockaddr_ll ll_my;
struct sockaddr_ll ll_slow;
+ char *hwaddr;
+ unsigned char hwaddr_len;
int err;
bool admin_state;
@@ -1028,12 +1032,19 @@ static int lacpdu_send(struct lacp_port *lacp_port)
memcpy(lacp_port->actor.system, lacp_port->ctx->hwaddr, ETH_ALEN);
+ hwaddr = team_get_ifinfo_orig_hwaddr(lacp_port->tdport->team_ifinfo);
+ hwaddr_len = team_get_ifinfo_orig_hwaddr_len(lacp_port->tdport->team_ifinfo);
+ if (hwaddr_len != ETH_ALEN)
+ return 0;
+
lacpdu_init(&lacpdu);
lacpdu.actor = lacp_port->actor;
lacpdu.partner = lacp_port->partner;
+ memcpy(lacpdu.hdr.ether_shost, hwaddr, hwaddr_len);
+ memcpy(lacpdu.hdr.ether_dhost, ll_slow.sll_addr, ll_slow.sll_halen);
+ lacpdu.hdr.ether_type = htons(ETH_P_SLOW);
- err = teamd_sendto(lacp_port->sock, &lacpdu, sizeof(lacpdu), 0,
- (struct sockaddr *) &ll_slow, sizeof(ll_slow));
+ err = teamd_send(lacp_port->sock, &lacpdu, sizeof(lacpdu), 0);
return err;
}
@@ -1201,9 +1212,9 @@ static int lacp_port_added(struct teamd_context *ctx,
return err;
}
- err = teamd_packet_sock_open(&lacp_port->sock,
- tdport->ifindex,
- htons(ETH_P_SLOW), NULL, NULL);
+ err = teamd_packet_sock_open_type(SOCK_RAW, &lacp_port->sock,
+ tdport->ifindex,
+ htons(ETH_P_SLOW), NULL, NULL);
if (err)
return err;

0 comments on commit c18a634

Please sign in to comment.