diff --git a/network/ovs_endpointclient_linux.go b/network/ovs_endpointclient_linux.go index ae033b8dcf..a702196559 100644 --- a/network/ovs_endpointclient_linux.go +++ b/network/ovs_endpointclient_linux.go @@ -90,7 +90,7 @@ func (client *OVSEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error { } log.Printf("[ovs] Get ovs port for interface %v.", client.hostVethName) - containerPort, err := ovsctl.GetOVSPortNumber(client.hostVethName) + containerOVSPort, err := ovsctl.GetOVSPortNumber(client.hostVethName) if err != nil { log.Printf("[ovs] Get ofport failed with error %v", err) return err @@ -103,12 +103,6 @@ func (client *OVSEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error { return err } - // IP SNAT Rule - log.Printf("[ovs] Adding IP SNAT rule for egress traffic on %v.", containerPort) - if err := ovsctl.AddIpSnatRule(client.bridgeName, containerPort, client.hostPrimaryMac, ""); err != nil { - return err - } - for _, ipAddr := range epInfo.IPAddresses { // Add Arp Reply Rules // Set Vlan id on arp request packet and forward it to table 1 @@ -116,9 +110,18 @@ func (client *OVSEndpointClient) AddEndpointRules(epInfo *EndpointInfo) error { return err } - // Add IP DNAT rule based on dst ip and vlanid - log.Printf("[ovs] Adding MAC DNAT rule for IP address %v on %v.", ipAddr.IP.String(), hostPort) - if err := ovsctl.AddMacDnatRule(client.bridgeName, hostPort, ipAddr.IP, client.containerMac, client.vlanID); err != nil { + // IP SNAT Rule - Change src mac to VM Mac for packets coming from container host veth port. + // This rule also checks if packets coming from right source ip based on the ovs port to prevent ip spoofing. + // Otherwise it drops the packet. + log.Printf("[ovs] Adding IP SNAT rule for egress traffic on %v.", containerOVSPort) + if err := ovsctl.AddIpSnatRule(client.bridgeName, ipAddr.IP, client.vlanID, containerOVSPort, client.hostPrimaryMac, hostPort); err != nil { + return err + } + + // Add IP DNAT rule based on dst ip and vlanid - This rule changes the destination mac to corresponding container mac based on the ip and + // forwards the packet to corresponding container hostveth port + log.Printf("[ovs] Adding MAC DNAT rule for IP address %v on hostport %v, containerport: %v", ipAddr.IP.String(), hostPort, containerOVSPort) + if err := ovsctl.AddMacDnatRule(client.bridgeName, hostPort, ipAddr.IP, client.containerMac, client.vlanID, containerOVSPort); err != nil { return err } } diff --git a/network/ovsinfravnet/infravnet.go b/network/ovsinfravnet/infravnet.go index ee4dfd86f3..df22fa399b 100644 --- a/network/ovsinfravnet/infravnet.go +++ b/network/ovsinfravnet/infravnet.go @@ -65,12 +65,14 @@ func (client *OVSInfraVnetClient) CreateInfraVnetRules( return err } - if err := ovsctl.AddIpSnatRule(bridgeName, infraContainerPort, hostPrimaryMac, hostPort); err != nil { + // 0 signifies not to add vlan tag to this traffic + if err := ovsctl.AddIpSnatRule(bridgeName, infraIP.IP, 0, infraContainerPort, hostPrimaryMac, hostPort); err != nil { log.Printf("[ovs] AddIpSnatRule failed with error %v", err) return err } - if err := ovsctl.AddMacDnatRule(bridgeName, hostPort, infraIP.IP, client.containerInfraMac, 0); err != nil { + // 0 signifies not to match traffic based on vlan tag + if err := ovsctl.AddMacDnatRule(bridgeName, hostPort, infraIP.IP, client.containerInfraMac, 0, infraContainerPort); err != nil { log.Printf("[ovs] AddMacDnatRule failed with error %v", err) return err } diff --git a/ovsctl/ovsctl.go b/ovsctl/ovsctl.go index 5186fbd610..ce21f46d38 100644 --- a/ovsctl/ovsctl.go +++ b/ovsctl/ovsctl.go @@ -14,6 +14,13 @@ const ( defaultMacForArpResponse = "12:34:56:78:9a:bc" ) +// Open flow rule priorities. Higher the number higher the priority +const ( + low = 10 + mid = 15 + high = 20 +) + func CreateOVSBridge(bridgeName string) error { log.Printf("[ovs] Creating OVS Bridge %v", bridgeName) @@ -41,13 +48,7 @@ func DeleteOVSBridge(bridgeName string) error { } func AddPortOnOVSBridge(hostIfName string, bridgeName string, vlanID int) error { - cmd := "" - - if vlanID == 0 { - cmd = fmt.Sprintf("ovs-vsctl add-port %s %s", bridgeName, hostIfName) - } else { - cmd = fmt.Sprintf("ovs-vsctl add-port %s %s tag=%d", bridgeName, hostIfName, vlanID) - } + cmd := fmt.Sprintf("ovs-vsctl add-port %s %s", bridgeName, hostIfName) _, err := platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Error while setting OVS as master to primary interface %v", err) @@ -69,7 +70,7 @@ func GetOVSPortNumber(interfaceName string) (string, error) { } func AddVMIpAcceptRule(bridgeName string, primaryIP string, mac string) error { - cmd := fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,dl_dst=%s,priority=20,actions=normal", bridgeName, primaryIP, mac) + cmd := fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,dl_dst=%s,priority=%d,actions=normal", bridgeName, primaryIP, mac, high) _, err := platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Adding SNAT rule failed with error %v", err) @@ -80,8 +81,8 @@ func AddVMIpAcceptRule(bridgeName string, primaryIP string, mac string) error { } func AddArpSnatRule(bridgeName string, mac string, macHex string, ofport string) error { - cmd := fmt.Sprintf(`ovs-ofctl add-flow %v table=1,priority=10,arp,arp_op=1,actions='mod_dl_src:%s, - load:0x%s->NXM_NX_ARP_SHA[],output:%s'`, bridgeName, mac, macHex, ofport) + cmd := fmt.Sprintf(`ovs-ofctl add-flow %v table=1,priority=%d,arp,arp_op=1,actions='mod_dl_src:%s, + load:0x%s->NXM_NX_ARP_SHA[],output:%s'`, bridgeName, low, mac, macHex, ofport) _, err := platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Adding ARP SNAT rule failed with error %v", err) @@ -91,21 +92,32 @@ func AddArpSnatRule(bridgeName string, mac string, macHex string, ofport string) return nil } -func AddIpSnatRule(bridgeName string, port string, mac string, outport string) error { +// IP SNAT Rule - Change src mac to VM Mac for packets coming from container host veth port. +func AddIpSnatRule(bridgeName string, ip net.IP, vlanID int, port string, mac string, outport string) error { + var cmd string if outport == "" { outport = "normal" } - cmd := fmt.Sprintf("ovs-ofctl add-flow %v priority=20,ip,in_port=%s,vlan_tci=0,actions=mod_dl_src:%s,strip_vlan,%v", - bridgeName, port, mac, outport) + commonPrefix := fmt.Sprintf("ovs-ofctl add-flow %v priority=%d,ip,nw_src=%s,in_port=%s,vlan_tci=0,actions=mod_dl_src:%s", bridgeName, high, ip.String(), port, mac) + + // This rule also checks if packets coming from right source ip based on the ovs port to prevent ip spoofing. + // Otherwise it drops the packet. + if vlanID != 0 { + cmd = fmt.Sprintf("%s,mod_vlan_vid:%v,%v", commonPrefix, vlanID, outport) + } else { + cmd = fmt.Sprintf("%s,strip_vlan,%v", commonPrefix, outport) + } + _, err := platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Adding IP SNAT rule failed with error %v", err) return err } - cmd = fmt.Sprintf("ovs-ofctl add-flow %v priority=10,ip,in_port=%s,actions=drop", - bridgeName, port) + // Drop other packets which doesn't satisfy above condition + cmd = fmt.Sprintf("ovs-ofctl add-flow %v priority=%d,ip,in_port=%s,actions=drop", + bridgeName, low, port) _, err = platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Dropping vlantag packet rule failed with error %v", err) @@ -134,11 +146,11 @@ func AddFakeArpReply(bridgeName string, ip net.IP) error { ipAddrInt := common.IpToInt(ip) log.Printf("[ovs] Adding ARP reply rule for IP address %v ", ip.String()) - cmd := fmt.Sprintf(`ovs-ofctl add-flow %s arp,arp_op=1,priority=20,actions='load:0x2->NXM_OF_ARP_OP[], + cmd := fmt.Sprintf(`ovs-ofctl add-flow %s arp,arp_op=1,priority=%d,actions='load:0x2->NXM_OF_ARP_OP[], move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:%s, move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_TPA[]->NXM_OF_ARP_SPA[], load:0x%s->NXM_NX_ARP_SHA[],load:0x%x->NXM_OF_ARP_TPA[],IN_PORT'`, - bridgeName, defaultMacForArpResponse, macAddrHex, ipAddrInt) + bridgeName, high, defaultMacForArpResponse, macAddrHex, ipAddrInt) _, err := platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Adding ARP reply rule failed with error %v", err) @@ -163,11 +175,11 @@ func AddArpReplyRule(bridgeName string, port string, ip net.IP, mac string, vlan // If arp fields matches, set arp reply rule for the request log.Printf("[ovs] Adding ARP reply rule for IP address %v and vlanid %v.", ip, vlanid) - cmd = fmt.Sprintf(`ovs-ofctl add-flow %s table=1,arp,arp_tpa=%s,dl_vlan=%v,arp_op=1,priority=20,actions='load:0x2->NXM_OF_ARP_OP[], + cmd = fmt.Sprintf(`ovs-ofctl add-flow %s table=1,arp,arp_tpa=%s,dl_vlan=%v,arp_op=1,priority=%d,actions='load:0x2->NXM_OF_ARP_OP[], move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:%s, move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x%s->NXM_NX_ARP_SHA[],load:0x%x->NXM_OF_ARP_SPA[],strip_vlan,IN_PORT'`, - bridgeName, ip.String(), vlanid, mac, macAddrHex, ipAddrInt) + bridgeName, ip.String(), vlanid, high, mac, macAddrHex, ipAddrInt) _, err = platform.ExecuteCommand(cmd) if err != nil { log.Printf("[ovs] Adding ARP reply rule failed with error %v", err) @@ -177,15 +189,17 @@ func AddArpReplyRule(bridgeName string, port string, ip net.IP, mac string, vlan return nil } -func AddMacDnatRule(bridgeName string, port string, ip net.IP, mac string, vlanid int) error { +// Add MAC DNAT rule based on dst ip and vlanid +func AddMacDnatRule(bridgeName string, port string, ip net.IP, mac string, vlanid int, containerPort string) error { var cmd string + // This rule changes the destination mac to speciifed mac based on the ip and vlanid. + // and forwards the packet to corresponding container hostveth port + commonPrefix := fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,in_port=%s", bridgeName, ip.String(), port) if vlanid != 0 { - cmd = fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,dl_vlan=%v,in_port=%s,actions=mod_dl_dst:%s,normal", - bridgeName, ip.String(), vlanid, port, mac) + cmd = fmt.Sprintf("%s,dl_vlan=%v,actions=mod_dl_dst:%s,strip_vlan,%s", commonPrefix, vlanid, mac, containerPort) } else { - cmd = fmt.Sprintf("ovs-ofctl add-flow %s ip,nw_dst=%s,in_port=%s,actions=mod_dl_dst:%s,normal", - bridgeName, ip.String(), port, mac) + cmd = fmt.Sprintf("%s,actions=mod_dl_dst:%s,strip_vlan,%s", commonPrefix, mac, containerPort) } _, err := platform.ExecuteCommand(cmd) if err != nil {