From 388a6d8478b520e18c9e9fdcb2744b8d96536b80 Mon Sep 17 00:00:00 2001 From: Carl Byington Date: Sun, 23 Nov 2014 19:09:52 -0800 Subject: MACVLAN_MODE_VRRP only moves vrrp multicast packets back to the lower interface. All other packets are left on the upper device. The vyos keepalived does all the vrrp communication over multicast on the lower device, but we need the ARP packets to show up on the upper device. --- drivers/net/macvlan.c | 35 ++++++++++++++++++++++++++++------- 1 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9fc98b5..c53fd12 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -182,6 +182,31 @@ static void macvlan_broadcast(struct sk_buff *skb, } } +/* multicast vrrp address per rfc5798 */ +static const u8 vrrp_multicast_addr[ETH_ALEN] __aligned(2) = +{ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x12 }; +/* vrrp mac address per rfc5798 */ +static const u8 vrrp_mac_addr[ETH_ALEN] __aligned(2) = +{ 0x00, 0x00, 0x5e, 0x00, 0x01, 0x00 }; + +static inline bool is_vrrp_multicast_ether_addr(const u8 *addr) +{ + __be16 *a = (__be16 *)addr; + static const __be16 *b = (const __be16 *)vrrp_multicast_addr; + static const __be16 m = cpu_to_be16(0xff00); + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; +} + +static inline bool is_vrrp_mac_ether_addr(const u8 *addr) +{ + __be16 *a = (__be16 *)addr; + static const __be16 *b = (const __be16 *)vrrp_mac_addr; + static const __be16 m = cpu_to_be16(0xff00); + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; +} + /* called under rcu_read_lock() from netif_receive_skb */ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) { @@ -224,7 +249,9 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) else { /* forward to original port. */ vlan = src; - if (vlan->mode == MACVLAN_MODE_VRRP) { + if ((vlan->mode == MACVLAN_MODE_VRRP) && + (is_vrrp_multicast_ether_addr(eth->h_dest)) && + (is_vrrp_mac_ether_addr(eth->h_src))) { skb->dev = vlan->lowerdev; skb->pkt_type = PACKET_MULTICAST; return RX_HANDLER_PASS; @@ -244,12 +271,6 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) if (vlan == NULL) return RX_HANDLER_PASS; - if (vlan->mode == MACVLAN_MODE_VRRP) { - skb->dev = vlan->lowerdev; - skb->pkt_type = PACKET_HOST; - return RX_HANDLER_PASS; - } - dev = vlan->dev; if (unlikely(!(dev->flags & IFF_UP))) { kfree_skb(skb); -- 1.7.1 From d62a9dfa5920ee130f395afc8c270ea53ec954ae Mon Sep 17 00:00:00 2001 From: Carl Byington Date: Mon, 24 Nov 2014 07:44:16 -0800 Subject: MACVLAN_MODE_VRRP only moves vrrp multicast packets back to the lower interface. All other packets are left on the upper device. The vyos keepalived does all the vrrp communication over multicast on the lower device, but we need the ARP packets to show up on the upper device. --- drivers/net/macvlan.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c53fd12..aca2e5a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -193,7 +193,6 @@ static inline bool is_vrrp_multicast_ether_addr(const u8 *addr) { __be16 *a = (__be16 *)addr; static const __be16 *b = (const __be16 *)vrrp_multicast_addr; - static const __be16 m = cpu_to_be16(0xff00); return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; } @@ -251,7 +250,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) vlan = src; if ((vlan->mode == MACVLAN_MODE_VRRP) && (is_vrrp_multicast_ether_addr(eth->h_dest)) && - (is_vrrp_mac_ether_addr(eth->h_src))) { + (is_vrrp_mac_ether_addr(eth->h_source))) { skb->dev = vlan->lowerdev; skb->pkt_type = PACKET_MULTICAST; return RX_HANDLER_PASS; -- 1.7.1