@@ -1850,9 +1850,10 @@ func commonFlows(hostSubnets []*net.IPNet, bridge *bridgeConfiguration) ([]strin
18501850 defaultOpenFlowCookie , netConfig .ofPortPatch , bridgeMacAddress , config .Default .ConntrackZone ,
18511851 netConfig .masqCTMark , ofPortPhys ))
18521852
1853- // Allow OVN->Host traffic on the same node
1853+ // Allow (a) OVN->host traffic on the same node
1854+ // (b) host->host traffic on the same node
18541855 if config .Gateway .Mode == config .GatewayModeShared || config .Gateway .Mode == config .GatewayModeLocal {
1855- dftFlows = append (dftFlows , ovnToHostNetworkNormalActionFlows (netConfig , bridgeMacAddress , hostSubnets , false )... )
1856+ dftFlows = append (dftFlows , hostNetworkNormalActionFlows (netConfig , bridgeMacAddress , hostSubnets , false )... )
18561857 }
18571858 } else {
18581859 // for UDN we additionally SNAT the packet from masquerade IP -> node IP
@@ -1946,9 +1947,10 @@ func commonFlows(hostSubnets []*net.IPNet, bridge *bridgeConfiguration) ([]strin
19461947 "actions=ct(commit, zone=%d, exec(set_field:%s->ct_mark)), output:%s" ,
19471948 defaultOpenFlowCookie , netConfig .ofPortPatch , bridgeMacAddress , config .Default .ConntrackZone , netConfig .masqCTMark , ofPortPhys ))
19481949
1949- // Allow OVN->Host traffic on the same node
1950+ // Allow (a) OVN->host traffic on the same node
1951+ // (b) host->host traffic on the same node
19501952 if config .Gateway .Mode == config .GatewayModeShared || config .Gateway .Mode == config .GatewayModeLocal {
1951- dftFlows = append (dftFlows , ovnToHostNetworkNormalActionFlows (netConfig , bridgeMacAddress , hostSubnets , true )... )
1953+ dftFlows = append (dftFlows , hostNetworkNormalActionFlows (netConfig , bridgeMacAddress , hostSubnets , true )... )
19521954 }
19531955 } else {
19541956 // for UDN we additionally SNAT the packet from masquerade IP -> node IP
@@ -2128,23 +2130,15 @@ func commonFlows(hostSubnets []*net.IPNet, bridge *bridgeConfiguration) ([]strin
21282130 return dftFlows , nil
21292131}
21302132
2131- // ovnToHostNetworkNormalActionFlows returns the flows that allow IP{v4,v6} traffic from the OVN network to the host network
2132- // when the destination is on the same node as the sender. This is necessary for pods in the default network to reach
2133- // localnet pods on the same node, when the localnet is mapped to breth0. The expected srcMAC is the MAC address of breth0
2134- // and the expected hostSubnets is the host subnets found on the node primary interface.
2135- func ovnToHostNetworkNormalActionFlows (netConfig * bridgeUDNConfiguration , srcMAC string , hostSubnets []* net.IPNet , isV6 bool ) []string {
2136- var inPort , ctMark , ipFamily , ipFamilyDest string
2133+ // hostNetworkNormalActionFlows returns the flows that allow IP{v4,v6} traffic:
2134+ // a. from pods in the OVN network to pods in a localnet network, on the same node
2135+ // b. from pods on the host to pods in a localnet network, on the same node
2136+ // when the localnet is mapped to breth0.
2137+ // The expected srcMAC is the MAC address of breth0 and the expected hostSubnets is the host subnets found on the node
2138+ // primary interface.
2139+ func hostNetworkNormalActionFlows (netConfig * bridgeUDNConfiguration , srcMAC string , hostSubnets []* net.IPNet , isV6 bool ) []string {
21372140 var flows []string
2138-
2139- if config .Gateway .Mode == config .GatewayModeShared {
2140- inPort = netConfig .ofPortPatch
2141- ctMark = netConfig .masqCTMark
2142- } else if config .Gateway .Mode == config .GatewayModeLocal {
2143- inPort = "LOCAL"
2144- ctMark = ctMarkHost
2145- } else {
2146- return nil
2147- }
2141+ var ipFamily , ipFamilyDest string
21482142
21492143 if isV6 {
21502144 ipFamily = "ipv6"
@@ -2154,38 +2148,69 @@ func ovnToHostNetworkNormalActionFlows(netConfig *bridgeUDNConfiguration, srcMAC
21542148 ipFamilyDest = "nw_dst"
21552149 }
21562150
2151+ formatFlow := func (inPort , destIP , ctMark string ) string {
2152+ // Matching IP traffic will be handled by the bridge instead of being output directly
2153+ // to the NIC by the existing flow at prio=100.
2154+ flowTemplate := "cookie=%s, priority=102, in_port=%s, dl_src=%s, %s, %s=%s, " +
2155+ "actions=ct(commit, zone=%d, exec(set_field:%s->ct_mark)), output:NORMAL"
2156+ return fmt .Sprintf (flowTemplate ,
2157+ defaultOpenFlowCookie ,
2158+ inPort ,
2159+ srcMAC ,
2160+ ipFamily ,
2161+ ipFamilyDest ,
2162+ destIP ,
2163+ config .Default .ConntrackZone ,
2164+ ctMark )
2165+ }
2166+
2167+ // Traffic path (a): OVN->localnet for shared gw mode
2168+ if config .Gateway .Mode == config .GatewayModeShared {
2169+ for _ , hostSubnet := range hostSubnets {
2170+ if utilnet .IsIPv6 (hostSubnet .IP ) != isV6 {
2171+ continue
2172+ }
2173+ flows = append (flows , formatFlow (netConfig .ofPortPatch , hostSubnet .String (), netConfig .masqCTMark ))
2174+ }
2175+ }
2176+
2177+ // Traffic path (a): OVN->localnet for local gw mode
2178+ // Traffic path (b): host->localnet for both gw modes
21572179 for _ , hostSubnet := range hostSubnets {
2158- if (hostSubnet .IP . To4 () == nil ) != isV6 {
2180+ if utilnet . IsIPv6 (hostSubnet .IP ) != isV6 {
21592181 continue
21602182 }
2161- // IP traffic from the OVN network to the host network should be handled normally by the bridge instead of
2162- // being output directly to the NIC by the existing flow at prio=100.
2163- flows = append (flows ,
2164- fmt .Sprintf ("cookie=%s, priority=102, in_port=%s, dl_src=%s, %s, %s=%s, " +
2165- "actions=ct(commit, zone=%d, exec(set_field:%s->ct_mark)), output:NORMAL" ,
2183+ flows = append (flows , formatFlow ("LOCAL" , hostSubnet .String (), ctMarkHost ))
2184+ }
2185+
2186+ if isV6 {
2187+ // IPv6 neighbor discovery uses ICMPv6 messages sent to a special destination (ff02::1:ff00:0/104)
2188+ // that is unrelated to the host subnets matched in the prio=102 flow above.
2189+ // Allow neighbor discovery by matching against ICMP type and ingress port.
2190+ formatICMPFlow := func (inPort , ctMark string , icmpType int ) string {
2191+ icmpFlowTemplate := "cookie=%s, priority=102, in_port=%s, dl_src=%s, icmp6, icmpv6_type=%d, " +
2192+ "actions=ct(commit, zone=%d, exec(set_field:%s->ct_mark)), output:NORMAL"
2193+ return fmt .Sprintf (icmpFlowTemplate ,
21662194 defaultOpenFlowCookie ,
21672195 inPort ,
21682196 srcMAC ,
2169- ipFamily ,
2170- ipFamilyDest ,
2171- hostSubnet .String (),
2197+ icmpType ,
21722198 config .Default .ConntrackZone ,
2173- ctMark ))
2174- }
2199+ ctMark )
2200+ }
21752201
2176- if isV6 {
2177- // Neighbor discovery in IPv6 happens through ICMPv6 messages to a special destination (ff02::1:ff00:0/104),
2178- // which has nothing to do with the host subnets we're matching against in the flow above at prio=102.
2179- // Let's allow neighbor discovery by matching against icmp type and in_port.
21802202 for _ , icmpType := range []int {types .NeighborSolicitationICMPType , types .NeighborAdvertisementICMPType } {
2181- flows = append (flows ,
2182- fmt .Sprintf ("cookie=%s, priority=102, in_port=%s, dl_src=%s, icmp6, icmpv6_type=%d, " +
2183- "actions=ct(commit, zone=%d, exec(set_field:%s->ct_mark)), output:NORMAL" ,
2184- defaultOpenFlowCookie , inPort , srcMAC , icmpType ,
2185- config .Default .ConntrackZone , ctMark ))
2203+ // Traffic path (a) for ICMP: OVN-> localnet for shared gw mode
2204+ if config .Gateway .Mode == config .GatewayModeShared {
2205+ flows = append (flows ,
2206+ formatICMPFlow (netConfig .ofPortPatch , netConfig .masqCTMark , icmpType ))
2207+ }
2208+
2209+ // Traffic path (a) for ICMP: OVN->localnet for local gw mode
2210+ // Traffic path (b) for ICMP: host->localnet for both gw modes
2211+ flows = append (flows , formatICMPFlow ("LOCAL" , ctMarkHost , icmpType ))
21862212 }
21872213 }
2188-
21892214 return flows
21902215}
21912216
0 commit comments