Skip to content

Commit deff5e6

Browse files
pliurhjcaamano
authored andcommitted
Add the IP rule for a UDN only when it is advertised to the default VRF
When an UDN is advertised to a non default VRF, we shall not add the ip rule to the default VRF. Otherwise if another UDN is advertised to the default VRF with the same subnet. The ingress traffic intended for the second UDN cannot be correctly routed to its respective VRF. Signed-off-by: Peng Liu <[email protected]>
1 parent d14d848 commit deff5e6

File tree

2 files changed

+315
-79
lines changed

2 files changed

+315
-79
lines changed

go-controller/pkg/node/gateway_udn.go

Lines changed: 119 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ type UserDefinedNetworkGateway struct {
8989

9090
// gwInterfaceIndex holds the link index of gateway interface
9191
gwInterfaceIndex int
92+
93+
// save BGP state at the start of reconciliation loop run to handle it consistently throughout the run
94+
isNetworkAdvertisedToDefaultVRF bool
95+
isNetworkAdvertised bool
9296
}
9397

9498
// UTILS Needed for UDN (also leveraged for default netInfo) in bridgeConfiguration
@@ -366,18 +370,18 @@ func (udng *UserDefinedNetworkGateway) AddNetwork() error {
366370
return fmt.Errorf("could not add VRF %s routes for network %s, err: %v", vrfDeviceName, udng.GetNetworkName(), err)
367371
}
368372

369-
isNetworkAdvertised := util.IsPodNetworkAdvertisedAtNode(udng.NetInfo, udng.node.Name)
373+
udng.updateAdvertisementStatus()
370374

371375
// create the iprules for this network
372-
if err = udng.updateUDNVRFIPRules(isNetworkAdvertised); err != nil {
376+
if err = udng.updateUDNVRFIPRules(); err != nil {
373377
return fmt.Errorf("failed to update IP rules for network %s: %w", udng.GetNetworkName(), err)
374378
}
375379

376-
if err = udng.updateAdvertisedUDNIsolationRules(isNetworkAdvertised); err != nil {
380+
if err = udng.updateAdvertisedUDNIsolationRules(); err != nil {
377381
return fmt.Errorf("failed to update isolation rules for network %s: %w", udng.GetNetworkName(), err)
378382
}
379383

380-
if err := udng.updateUDNVRFIPRoute(isNetworkAdvertised); err != nil {
384+
if err := udng.updateUDNVRFIPRoute(); err != nil {
381385
return fmt.Errorf("failed to update ip routes for network %s: %w", udng.GetNetworkName(), err)
382386
}
383387

@@ -455,18 +459,16 @@ func (udng *UserDefinedNetworkGateway) DelNetwork() error {
455459
}
456460
}
457461

458-
if util.IsPodNetworkAdvertisedAtNode(udng.NetInfo, udng.node.Name) {
459-
err := udng.updateAdvertisedUDNIsolationRules(false)
460-
if err != nil {
461-
return fmt.Errorf("failed to remove advertised UDN isolation rules for network %s: %w", udng.GetNetworkName(), err)
462-
}
462+
err := udng.deleteAdvertisedUDNIsolationRules()
463+
if err != nil {
464+
return fmt.Errorf("failed to remove advertised UDN isolation rules for network %s: %w", udng.GetNetworkName(), err)
463465
}
464466

465467
if err := udng.delMarkChain(); err != nil {
466468
return err
467469
}
468470
// delete the management port interface for this network
469-
err := udng.deleteUDNManagementPort()
471+
err = udng.deleteUDNManagementPort()
470472
if err != nil {
471473
return err
472474
}
@@ -622,8 +624,7 @@ func (udng *UserDefinedNetworkGateway) computeRoutesForUDN(mpLink netlink.Link)
622624

623625
// Route2: Add default route: default via 172.18.0.1 dev breth0 mtu 1400
624626
// necessary for UDN CNI and host-networked pods default traffic to go to node's gatewayIP
625-
isNetworkAdvertised := util.IsPodNetworkAdvertisedAtNode(udng.NetInfo, udng.node.Name)
626-
defaultRoute, err := udng.getDefaultRoute(isNetworkAdvertised)
627+
defaultRoute, err := udng.getDefaultRouteWithAdvertisedCheck()
627628
if err != nil {
628629
return nil, fmt.Errorf("unable to add default route for network %s, err: %v", udng.GetNetworkName(), err)
629630
}
@@ -724,15 +725,7 @@ func (udng *UserDefinedNetworkGateway) computeRoutesForUDN(mpLink netlink.Link)
724725
return retVal, nil
725726
}
726727

727-
func (udng *UserDefinedNetworkGateway) getDefaultRoute(isNetworkAdvertised bool) ([]netlink.Route, error) {
728-
vrfs := udng.GetPodNetworkAdvertisedOnNodeVRFs(udng.node.Name)
729-
// If the network is advertised on a non default VRF then we should only consider routes received from external BGP
730-
// device and not send any traffic based on default route similar to one present in default VRF. This is more important
731-
// for VRF-Lite usecase where we need traffic to leave from vlan device instead of default gateway interface.
732-
if isNetworkAdvertised && !slices.Contains(vrfs, types.DefaultNetworkName) {
733-
return nil, nil
734-
}
735-
728+
func (udng *UserDefinedNetworkGateway) getDefaultRoute() ([]netlink.Route, error) {
736729
networkMTU := udng.NetInfo.MTU()
737730
if networkMTU == 0 {
738731
networkMTU = config.Default.MTU
@@ -757,6 +750,16 @@ func (udng *UserDefinedNetworkGateway) getDefaultRoute(isNetworkAdvertised bool)
757750
return retVal, nil
758751
}
759752

753+
func (udng *UserDefinedNetworkGateway) getDefaultRouteWithAdvertisedCheck() ([]netlink.Route, error) {
754+
// If the network is advertised on a non default VRF then we should only consider routes received from external BGP
755+
// device and not send any traffic based on default route similar to one present in default VRF. This is more important
756+
// for VRF-Lite usecase where we need traffic to leave from vlan device instead of default gateway interface.
757+
if udng.isNetworkAdvertised && !udng.isNetworkAdvertisedToDefaultVRF {
758+
return nil, nil
759+
}
760+
return udng.getDefaultRoute()
761+
}
762+
760763
// getV4MasqueradeIP returns the V4 management port masqueradeIP for this network
761764
func (udng *UserDefinedNetworkGateway) getV4MasqueradeIP() (*net.IPNet, error) {
762765
if !config.IPv4Mode {
@@ -789,12 +792,15 @@ func (udng *UserDefinedNetworkGateway) getV6MasqueradeIP() (*net.IPNet, error) {
789792
// 2000: from all to 169.254.0.12 lookup 1007
790793
// 2000: from all fwmark 0x1002 lookup 1009
791794
// 2000: from all to 169.254.0.14 lookup 1009
792-
// If the network is advertised, an example of the rules we set for a network is:
795+
// If the network is advertised to the default VRF, an example of the rules we set for a network is:
793796
// 2000: from all fwmark 0x1001 lookup 1007
794797
// 2000: from all to 10.132.0.0/14 lookup 1007
795798
// 2000: from all fwmark 0x1001 lookup 1009
796799
// 2000: from all to 10.134.0.0/14 lookup 1009
797-
func (udng *UserDefinedNetworkGateway) constructUDNVRFIPRules(isNetworkAdvertised bool) ([]netlink.Rule, []netlink.Rule, error) {
800+
// If the network is advertised ot a non-default VRF, an example of the rules we set for a network is:
801+
// 2000: from all fwmark 0x1001 lookup 1007
802+
// 2000: from all fwmark 0x1001 lookup 1009
803+
func (udng *UserDefinedNetworkGateway) constructUDNVRFIPRules() ([]netlink.Rule, []netlink.Rule, error) {
798804
var addIPRules []netlink.Rule
799805
var delIPRules []netlink.Rule
800806
var masqIPRules []netlink.Rule
@@ -827,12 +833,18 @@ func (udng *UserDefinedNetworkGateway) constructUDNVRFIPRules(isNetworkAdvertise
827833
}
828834
}
829835
switch {
830-
case !isNetworkAdvertised:
831-
addIPRules = append(addIPRules, masqIPRules...)
832-
delIPRules = append(delIPRules, subnetIPRules...)
833-
default:
836+
case udng.isNetworkAdvertisedToDefaultVRF:
837+
// the network is advertised to the default VRF
838+
delIPRules = append(delIPRules, masqIPRules...)
834839
addIPRules = append(addIPRules, subnetIPRules...)
840+
case udng.isNetworkAdvertised:
841+
// the network is advertised to a non-default VRF
835842
delIPRules = append(delIPRules, masqIPRules...)
843+
delIPRules = append(delIPRules, subnetIPRules...)
844+
default:
845+
// the network is not advertised
846+
delIPRules = append(delIPRules, subnetIPRules...)
847+
addIPRules = append(addIPRules, masqIPRules...)
836848
}
837849
return addIPRules, delIPRules, nil
838850
}
@@ -928,19 +940,20 @@ func (udng *UserDefinedNetworkGateway) doReconcile() error {
928940
return fmt.Errorf("openflow manager with default bridge configuration has not been provided for network %s", udng.GetNetworkName())
929941
}
930942

943+
udng.updateAdvertisementStatus()
944+
931945
// update bridge configuration
932-
isNetworkAdvertised := util.IsPodNetworkAdvertisedAtNode(udng.NetInfo, udng.node.Name)
933946
netConfig := udng.openflowManager.defaultBridge.getNetworkBridgeConfig(udng.GetNetworkName())
934947
if netConfig == nil {
935948
return fmt.Errorf("missing bridge configuration for network %s", udng.GetNetworkName())
936949
}
937-
netConfig.advertised.Store(isNetworkAdvertised)
950+
netConfig.advertised.Store(udng.isNetworkAdvertised)
938951

939-
if err := udng.updateUDNVRFIPRules(isNetworkAdvertised); err != nil {
952+
if err := udng.updateUDNVRFIPRules(); err != nil {
940953
return fmt.Errorf("error while updating ip rule for UDN %s: %s", udng.GetNetworkName(), err)
941954
}
942955

943-
if err := udng.updateUDNVRFIPRoute(isNetworkAdvertised); err != nil {
956+
if err := udng.updateUDNVRFIPRoute(); err != nil {
944957
return fmt.Errorf("error while updating ip route for UDN %s: %s", udng.GetNetworkName(), err)
945958
}
946959

@@ -954,16 +967,16 @@ func (udng *UserDefinedNetworkGateway) doReconcile() error {
954967
// let's sync these flows immediately
955968
udng.openflowManager.requestFlowSync()
956969

957-
if err := udng.updateAdvertisedUDNIsolationRules(isNetworkAdvertised); err != nil {
970+
if err := udng.updateAdvertisedUDNIsolationRules(); err != nil {
958971
return fmt.Errorf("error while updating advertised UDN isolation rules for network %s: %w", udng.GetNetworkName(), err)
959972
}
960973
return nil
961974
}
962975

963976
// updateUDNVRFIPRules updates IP rules for a network depending on whether the
964-
// network is advertised or not
965-
func (udng *UserDefinedNetworkGateway) updateUDNVRFIPRules(isNetworkAdvertised bool) error {
966-
addIPRules, deleteIPRules, err := udng.constructUDNVRFIPRules(isNetworkAdvertised)
977+
// network is advertised to the default VRF or not
978+
func (udng *UserDefinedNetworkGateway) updateUDNVRFIPRules() error {
979+
addIPRules, deleteIPRules, err := udng.constructUDNVRFIPRules()
967980
if err != nil {
968981
return fmt.Errorf("unable to get iprules for network %s, err: %v", udng.GetNetworkName(), err)
969982
}
@@ -982,30 +995,40 @@ func (udng *UserDefinedNetworkGateway) updateUDNVRFIPRules(isNetworkAdvertised b
982995
}
983996

984997
// Add or remove default route from a vrf device based on the network is
985-
// advertised on its own network or default network
986-
func (udng *UserDefinedNetworkGateway) updateUDNVRFIPRoute(isNetworkAdvertised bool) error {
987-
vrfs := udng.GetPodNetworkAdvertisedOnNodeVRFs(udng.node.Name)
988-
if isNetworkAdvertised && !slices.Contains(vrfs, types.DefaultNetworkName) {
998+
// advertised on its own network or the default network
999+
func (udng *UserDefinedNetworkGateway) updateUDNVRFIPRoute() error {
1000+
vrfName := util.GetNetworkVRFName(udng.NetInfo)
1001+
1002+
switch {
1003+
case udng.isNetworkAdvertised && !udng.isNetworkAdvertisedToDefaultVRF:
1004+
// Remove default route for networks advertised to non-default VRF
9891005
if err := udng.removeDefaultRouteFromVRF(); err != nil {
990-
return fmt.Errorf("error while removing default route from VRF %s corresponding to network %s: %s",
991-
util.GetNetworkVRFName(udng.NetInfo), udng.GetNetworkName(), err)
1006+
return fmt.Errorf("failed to remove default route from VRF %s for network %s: %v",
1007+
vrfName, udng.GetNetworkName(), err)
9921008
}
993-
} else if !isNetworkAdvertised || slices.Contains(vrfs, types.DefaultNetworkName) {
994-
defaultRoute, err := udng.getDefaultRoute(isNetworkAdvertised)
1009+
1010+
default:
1011+
// Add default route for networks that are either:
1012+
// - not advertised
1013+
// - advertised to default VRF
1014+
defaultRoute, err := udng.getDefaultRouteWithAdvertisedCheck()
9951015
if err != nil {
996-
return fmt.Errorf("unable to get default route for network %s, err: %v", udng.GetNetworkName(), err)
1016+
return fmt.Errorf("failed to get default route for network %s: %v",
1017+
udng.GetNetworkName(), err)
9971018
}
998-
if err = udng.vrfManager.AddVRFRoutes(util.GetNetworkVRFName(udng.NetInfo), defaultRoute); err != nil {
999-
return fmt.Errorf("error while adding default route to VRF %s corresponding to network %s, err: %v",
1000-
util.GetNetworkVRFName(udng.NetInfo), udng.GetNetworkName(), err)
1019+
1020+
if err = udng.vrfManager.AddVRFRoutes(vrfName, defaultRoute); err != nil {
1021+
return fmt.Errorf("failed to add default route to VRF %s for network %s: %v",
1022+
vrfName, udng.GetNetworkName(), err)
10011023
}
10021024
}
1025+
10031026
return nil
10041027
}
10051028

10061029
func (udng *UserDefinedNetworkGateway) removeDefaultRouteFromVRF() error {
10071030
vrfDeviceName := util.GetNetworkVRFName(udng.NetInfo)
1008-
defaultRoute, err := udng.getDefaultRoute(false)
1031+
defaultRoute, err := udng.getDefaultRoute()
10091032
if err != nil {
10101033
return fmt.Errorf("unable to get default route for network %s, err: %v", udng.GetNetworkName(), err)
10111034
}
@@ -1034,39 +1057,22 @@ func (udng *UserDefinedNetworkGateway) removeDefaultRouteFromVRF() error {
10341057
// comment "advertised UDNs V4 subnets"
10351058
// elements = { 10.10.0.0/16 comment "cluster_udn_l3network" }
10361059
// }
1037-
func (udng *UserDefinedNetworkGateway) updateAdvertisedUDNIsolationRules(isNetworkAdvertised bool) error {
1060+
func (udng *UserDefinedNetworkGateway) updateAdvertisedUDNIsolationRules() error {
1061+
switch {
1062+
case udng.isNetworkAdvertised:
1063+
return udng.addAdvertisedUDNIsolationRules()
1064+
default:
1065+
return udng.deleteAdvertisedUDNIsolationRules()
1066+
}
1067+
}
1068+
1069+
func (udng *UserDefinedNetworkGateway) addAdvertisedUDNIsolationRules() error {
10381070
nft, err := nodenft.GetNFTablesHelper()
10391071
if err != nil {
10401072
return fmt.Errorf("failed to get nftables helper: %v", err)
10411073
}
10421074
tx := nft.NewTransaction()
10431075

1044-
if !isNetworkAdvertised {
1045-
existingV4, err := nft.ListElements(context.TODO(), "set", nftablesAdvertisedUDNsSetV4)
1046-
if err != nil {
1047-
if !knftables.IsNotFound(err) {
1048-
return fmt.Errorf("could not list existing items in %s set: %w", nftablesAdvertisedUDNsSetV4, err)
1049-
}
1050-
}
1051-
existingV6, err := nft.ListElements(context.TODO(), "set", nftablesAdvertisedUDNsSetV6)
1052-
if err != nil {
1053-
if !knftables.IsNotFound(err) {
1054-
return fmt.Errorf("could not list existing items in %s set: %w", nftablesAdvertisedUDNsSetV6, err)
1055-
}
1056-
}
1057-
1058-
for _, elem := range append(existingV4, existingV6...) {
1059-
if elem.Comment != nil && *elem.Comment == udng.GetNetworkName() {
1060-
tx.Delete(elem)
1061-
}
1062-
}
1063-
1064-
if tx.NumOperations() == 0 {
1065-
return nil
1066-
}
1067-
return nft.Run(context.TODO(), tx)
1068-
}
1069-
10701076
for _, udnNet := range udng.Subnets() {
10711077
set := nftablesAdvertisedUDNsSetV4
10721078
if utilnet.IsIPv6CIDR(udnNet.CIDR) {
@@ -1085,3 +1091,41 @@ func (udng *UserDefinedNetworkGateway) updateAdvertisedUDNIsolationRules(isNetwo
10851091
}
10861092
return nft.Run(context.TODO(), tx)
10871093
}
1094+
1095+
func (udng *UserDefinedNetworkGateway) deleteAdvertisedUDNIsolationRules() error {
1096+
nft, err := nodenft.GetNFTablesHelper()
1097+
if err != nil {
1098+
return fmt.Errorf("failed to get nftables helper: %v", err)
1099+
}
1100+
tx := nft.NewTransaction()
1101+
1102+
existingV4, err := nft.ListElements(context.TODO(), "set", nftablesAdvertisedUDNsSetV4)
1103+
if err != nil {
1104+
if !knftables.IsNotFound(err) {
1105+
return fmt.Errorf("could not list existing items in %s set: %w", nftablesAdvertisedUDNsSetV4, err)
1106+
}
1107+
}
1108+
existingV6, err := nft.ListElements(context.TODO(), "set", nftablesAdvertisedUDNsSetV6)
1109+
if err != nil {
1110+
if !knftables.IsNotFound(err) {
1111+
return fmt.Errorf("could not list existing items in %s set: %w", nftablesAdvertisedUDNsSetV6, err)
1112+
}
1113+
}
1114+
1115+
for _, elem := range append(existingV4, existingV6...) {
1116+
if elem.Comment != nil && *elem.Comment == udng.GetNetworkName() {
1117+
tx.Delete(elem)
1118+
}
1119+
}
1120+
1121+
if tx.NumOperations() == 0 {
1122+
return nil
1123+
}
1124+
return nft.Run(context.TODO(), tx)
1125+
}
1126+
1127+
func (udng *UserDefinedNetworkGateway) updateAdvertisementStatus() {
1128+
vrfs := udng.GetPodNetworkAdvertisedOnNodeVRFs(udng.node.Name)
1129+
udng.isNetworkAdvertised = len(vrfs) > 0
1130+
udng.isNetworkAdvertisedToDefaultVRF = slices.Contains(vrfs, types.DefaultNetworkName)
1131+
}

0 commit comments

Comments
 (0)