Skip to content

Commit 313e21a

Browse files
VR: Fix Redundant VRouter guest network on wrong interface (#3847)
1 parent 3f8b2c3 commit 313e21a

File tree

9 files changed

+3144
-109
lines changed

9 files changed

+3144
-109
lines changed

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 33 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,17 +1783,11 @@ protected ExecutionResult prepareNetworkElementCommand(final IpAssocVpcCommand c
17831783

17841784
try {
17851785
conn = getLibvirtUtilitiesHelper().getConnectionByVmName(routerName);
1786-
final IpAddressTO[] ips = cmd.getIpAddresses();
1787-
Integer devNum = 0;
1788-
final List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
1789-
final Map<String, Integer> macAddressToNicNum = new HashMap<>(pluggedNics.size());
1790-
1791-
for (final InterfaceDef pluggedNic : pluggedNics) {
1792-
final String pluggedVlan = pluggedNic.getBrName();
1793-
macAddressToNicNum.put(pluggedNic.getMacAddress(), devNum);
1794-
devNum++;
1795-
}
1786+
Pair<Map<String, Integer>, Integer> macAddressToNicNumPair = getMacAddressToNicNumPair(conn, routerName);
1787+
final Map<String, Integer> macAddressToNicNum = macAddressToNicNumPair.first();
1788+
Integer devNum = macAddressToNicNumPair.second();
17961789

1790+
final IpAddressTO[] ips = cmd.getIpAddresses();
17971791
for (final IpAddressTO ip : ips) {
17981792
ip.setNicDevId(macAddressToNicNum.get(ip.getVifMacAddress()));
17991793
}
@@ -1810,35 +1804,22 @@ public ExecutionResult prepareNetworkElementCommand(final IpAssocCommand cmd) {
18101804
final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
18111805
Connect conn;
18121806
try {
1813-
conn = LibvirtConnection.getConnectionByVmName(routerName);
1814-
final List<InterfaceDef> nics = getInterfaces(conn, routerName);
1815-
final Map<String, Integer> broadcastUriAllocatedToVM = new HashMap<String, Integer>();
1816-
Integer nicPos = 0;
1817-
for (final InterfaceDef nic : nics) {
1818-
if (nic.getBrName().equalsIgnoreCase(_linkLocalBridgeName)) {
1819-
broadcastUriAllocatedToVM.put("LinkLocal", nicPos);
1820-
} else {
1821-
if (nic.getBrName().equalsIgnoreCase(_publicBridgeName) || nic.getBrName().equalsIgnoreCase(_privBridgeName) ||
1822-
nic.getBrName().equalsIgnoreCase(_guestBridgeName)) {
1823-
broadcastUriAllocatedToVM.put(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString(), nicPos);
1824-
} else {
1825-
final String broadcastUri = getBroadcastUriFromBridge(nic.getBrName());
1826-
broadcastUriAllocatedToVM.put(broadcastUri, nicPos);
1827-
}
1828-
}
1829-
nicPos++;
1830-
}
1807+
conn = getLibvirtUtilitiesHelper().getConnectionByVmName(routerName);
1808+
Pair<Map<String, Integer>, Integer> macAddressToNicNumPair = getMacAddressToNicNumPair(conn, routerName);
1809+
final Map<String, Integer> macAddressToNicNum = macAddressToNicNumPair.first();
1810+
Integer devNum = macAddressToNicNumPair.second();
1811+
18311812
final IpAddressTO[] ips = cmd.getIpAddresses();
18321813
int nicNum = 0;
18331814
for (final IpAddressTO ip : ips) {
18341815
boolean newNic = false;
1835-
if (!broadcastUriAllocatedToVM.containsKey(ip.getBroadcastUri())) {
1816+
if (!macAddressToNicNum.containsKey(ip.getVifMacAddress())) {
18361817
/* plug a vif into router */
18371818
VifHotPlug(conn, routerName, ip.getBroadcastUri(), ip.getVifMacAddress());
1838-
broadcastUriAllocatedToVM.put(ip.getBroadcastUri(), nicPos++);
1819+
macAddressToNicNum.put(ip.getVifMacAddress(), devNum++);
18391820
newNic = true;
18401821
}
1841-
nicNum = broadcastUriAllocatedToVM.get(ip.getBroadcastUri());
1822+
nicNum = macAddressToNicNum.get(ip.getVifMacAddress());
18421823
networkUsage(routerIp, "addVif", "eth" + nicNum);
18431824

18441825
ip.setNicDevId(nicNum);
@@ -1860,39 +1841,21 @@ protected ExecutionResult cleanupNetworkElementCommand(final IpAssocCommand cmd)
18601841
final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
18611842
final String lastIp = cmd.getAccessDetail(NetworkElementCommand.NETWORK_PUB_LAST_IP);
18621843
Connect conn;
1863-
1864-
1865-
try{
1866-
conn = LibvirtConnection.getConnectionByVmName(routerName);
1867-
final List<InterfaceDef> nics = getInterfaces(conn, routerName);
1868-
final Map<String, Integer> broadcastUriAllocatedToVM = new HashMap<String, Integer>();
1869-
1870-
Integer nicPos = 0;
1871-
for (final InterfaceDef nic : nics) {
1872-
if (nic.getBrName().equalsIgnoreCase(_linkLocalBridgeName)) {
1873-
broadcastUriAllocatedToVM.put("LinkLocal", nicPos);
1874-
} else {
1875-
if (nic.getBrName().equalsIgnoreCase(_publicBridgeName) || nic.getBrName().equalsIgnoreCase(_privBridgeName) ||
1876-
nic.getBrName().equalsIgnoreCase(_guestBridgeName)) {
1877-
broadcastUriAllocatedToVM.put(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString(), nicPos);
1878-
} else {
1879-
final String broadcastUri = getBroadcastUriFromBridge(nic.getBrName());
1880-
broadcastUriAllocatedToVM.put(broadcastUri, nicPos);
1881-
}
1882-
}
1883-
nicPos++;
1884-
}
1844+
try {
1845+
conn = getLibvirtUtilitiesHelper().getConnectionByVmName(routerName);
1846+
Pair<Map<String, Integer>, Integer> macAddressToNicNumPair = getMacAddressToNicNumPair(conn, routerName);
1847+
final Map<String, Integer> macAddressToNicNum = macAddressToNicNumPair.first();
1848+
Integer devNum = macAddressToNicNumPair.second();
18851849

18861850
final IpAddressTO[] ips = cmd.getIpAddresses();
18871851
int nicNum = 0;
18881852
for (final IpAddressTO ip : ips) {
1889-
1890-
if (!broadcastUriAllocatedToVM.containsKey(ip.getBroadcastUri())) {
1853+
if (!macAddressToNicNum.containsKey(ip.getVifMacAddress())) {
18911854
/* plug a vif into router */
18921855
VifHotPlug(conn, routerName, ip.getBroadcastUri(), ip.getVifMacAddress());
1893-
broadcastUriAllocatedToVM.put(ip.getBroadcastUri(), nicPos++);
1856+
macAddressToNicNum.put(ip.getVifMacAddress(), devNum++);
18941857
}
1895-
nicNum = broadcastUriAllocatedToVM.get(ip.getBroadcastUri());
1858+
nicNum = macAddressToNicNum.get(ip.getVifMacAddress());
18961859

18971860
if (org.apache.commons.lang.StringUtils.equalsIgnoreCase(lastIp, "true") && !ip.isAdd()) {
18981861
// in isolated network eth2 is the default public interface. We don't want to delete it.
@@ -1914,6 +1877,19 @@ protected ExecutionResult cleanupNetworkElementCommand(final IpAssocCommand cmd)
19141877
return new ExecutionResult(true, null);
19151878
}
19161879

1880+
1881+
private Pair<Map<String, Integer>, Integer> getMacAddressToNicNumPair(Connect conn, String routerName) {
1882+
Integer devNum = 0;
1883+
final List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
1884+
final Map<String, Integer> macAddressToNicNum = new HashMap<>(pluggedNics.size());
1885+
for (final InterfaceDef pluggedNic : pluggedNics) {
1886+
final String pluggedVlan = pluggedNic.getBrName();
1887+
macAddressToNicNum.put(pluggedNic.getMacAddress(), devNum);
1888+
devNum++;
1889+
}
1890+
return new Pair<Map<String, Integer>, Integer>(macAddressToNicNum, devNum);
1891+
}
1892+
19171893
protected PowerState convertToPowerState(final DomainState ps) {
19181894
final PowerState state = s_powerStatesTable.get(ps);
19191895
return state == null ? PowerState.PowerUnknown : state;

server/src/main/java/com/cloud/network/router/CommandSetupHelper.java

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,20 @@ public void createVpcAssociatePublicIPCommands(final VirtualRouter router, final
674674
vlanIpMap.put(vlanTag, ipList);
675675
}
676676

677+
Long guestNetworkId = null;
678+
final List<NicVO> nics = _nicDao.listByVmId(router.getId());
679+
for (final NicVO nic : nics) {
680+
final NetworkVO nw = _networkDao.findById(nic.getNetworkId());
681+
if (nw.getTrafficType() == TrafficType.Guest) {
682+
guestNetworkId = nw.getId();
683+
break;
684+
}
685+
}
686+
687+
Map<String, Boolean> vlanLastIpMap = getVlanLastIpMap(router.getVpcId(), guestNetworkId);
688+
677689
for (final Map.Entry<String, ArrayList<PublicIpAddress>> vlanAndIp : vlanIpMap.entrySet()) {
690+
final String vlanTagKey = vlanAndIp.getKey();
678691
final List<PublicIpAddress> ipAddrList = vlanAndIp.getValue();
679692

680693
// Source nat ip address should always be sent first
@@ -732,6 +745,8 @@ public int compare(final PublicIpAddress o1, final PublicIpAddress o2) {
732745
final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
733746
cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString());
734747

748+
setAccessDetailNetworkLastPublicIp(vlanLastIpMap, vlanTagKey, cmd);
749+
735750
cmds.addCommand(ipAssocCommand, cmd);
736751
}
737752

@@ -769,15 +784,25 @@ public void createRedundantAssociateIPCommands(final VirtualRouter router, final
769784

770785
final List<NicVO> nics = _nicDao.listByVmId(router.getId());
771786
String baseMac = null;
787+
Map<String, String> vlanMacAddress = new HashMap<String, String>();;
788+
Long guestNetworkId = null;
772789
for (final NicVO nic : nics) {
773790
final NetworkVO nw = _networkDao.findById(nic.getNetworkId());
774791
if (nw.getTrafficType() == TrafficType.Public) {
775-
baseMac = nic.getMacAddress();
776-
break;
792+
if (baseMac == null) {
793+
baseMac = nic.getMacAddress();
794+
}
795+
final String vlanTag = BroadcastDomainType.getValue(nic.getBroadcastUri());
796+
vlanMacAddress.put(vlanTag, nic.getMacAddress());
797+
} else if (nw.getTrafficType() == TrafficType.Guest && guestNetworkId == null) {
798+
guestNetworkId = nw.getId();
777799
}
778800
}
779801

802+
Map<String, Boolean> vlanLastIpMap = getVlanLastIpMap(router.getVpcId(), guestNetworkId);
803+
780804
for (final Map.Entry<String, ArrayList<PublicIpAddress>> vlanAndIp : vlanIpMap.entrySet()) {
805+
final String vlanTagKey = vlanAndIp.getKey();
781806
final List<PublicIpAddress> ipAddrList = vlanAndIp.getValue();
782807
// Source nat ip address should always be sent first
783808
Collections.sort(ipAddrList, new Comparator<PublicIpAddress>() {
@@ -809,19 +834,16 @@ public int compare(final PublicIpAddress o1, final PublicIpAddress o2) {
809834
final String vlanGateway = ipAddr.getGateway();
810835
final String vlanNetmask = ipAddr.getNetmask();
811836
String vifMacAddress = null;
812-
// For non-source nat IP, set the mac to be something based on
813-
// first public nic's MAC
814-
// We cannot depend on first ip because we need to deal with
815-
// first ip of other nics
816-
if (router.getVpcId() != null) {
817-
//vifMacAddress = NetUtils.generateMacOnIncrease(baseMac, ipAddr.getVlanId());
818-
vifMacAddress = ipAddr.getMacAddress();
837+
final String vlanTag = BroadcastDomainType.getValue(BroadcastDomainType.fromString(ipAddr.getVlanTag()));
838+
if (vlanMacAddress.containsKey(vlanTag)) {
839+
vifMacAddress = vlanMacAddress.get(vlanTag);
819840
} else {
820-
if (!sourceNat && ipAddr.getVlanId() != 0) {
841+
if (ipAddr.getVlanId() != 0) {
821842
vifMacAddress = NetUtils.generateMacOnIncrease(baseMac, ipAddr.getVlanId());
822843
} else {
823844
vifMacAddress = ipAddr.getMacAddress();
824845
}
846+
vlanMacAddress.put(vlanTag, vifMacAddress);
825847
}
826848

827849
final IpAddressTO ip = new IpAddressTO(ipAddr.getAccountId(), ipAddr.getAddress().addr(), add, firstIP, sourceNat, vlanId, vlanGateway, vlanNetmask,
@@ -839,56 +861,59 @@ public int compare(final PublicIpAddress o1, final PublicIpAddress o2) {
839861
}
840862
}
841863

842-
Long associatedWithNetworkId = ipAddrList.get(0).getAssociatedWithNetworkId();
843-
if (associatedWithNetworkId == null || associatedWithNetworkId == 0) {
844-
associatedWithNetworkId = ipAddrList.get(0).getNetworkId();
845-
}
846-
847-
// for network if the ips does not have any rules, then only last ip
848-
final List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(associatedWithNetworkId, null);
849-
boolean hasSourceNat = false;
850-
if (isVPC && userIps.size() > 0 && userIps.get(0) != null) {
851-
// All ips should belong to a VPC
852-
final Long vpcId = userIps.get(0).getVpcId();
853-
final List<IPAddressVO> sourceNatIps = _ipAddressDao.listByAssociatedVpc(vpcId, true);
854-
if (sourceNatIps != null && sourceNatIps.size() > 0) {
855-
hasSourceNat = true;
856-
}
857-
}
858-
859-
int ipsWithrules = 0;
860-
int ipsStaticNat = 0;
861-
for (IPAddressVO ip : userIps) {
862-
if ( _rulesDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Active) > 0){
863-
ipsWithrules++;
864-
}
865-
866-
// check onetoonenat and also check if the ip "add":false. If there are 2 PF rules remove and
867-
// 1 static nat rule add
868-
if (ip.isOneToOneNat() && ip.getRuleState() == null) {
869-
ipsStaticNat++;
870-
}
864+
final IpAssocCommand cmd;
865+
if (router.getVpcId() != null) {
866+
cmd = new IpAssocVpcCommand(ipsToSend);
867+
} else {
868+
cmd = new IpAssocCommand(ipsToSend);
871869
}
872-
873-
final IpAssocCommand cmd = new IpAssocCommand(ipsToSend);
874870
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
875-
cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(associatedWithNetworkId, router.getId()));
871+
cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(ipAddrList.get(0).getNetworkId(), router.getId()));
876872
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
877873
final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
878874
cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString());
879875

880-
// if there is 1 static nat then it will be checked for remove at the resource
881-
if (ipsWithrules == 0 && ipsStaticNat == 0 && !hasSourceNat) {
882-
// there is only one ip address for the network.
883-
cmd.setAccessDetail(NetworkElementCommand.NETWORK_PUB_LAST_IP, "true");
884-
} else {
885-
cmd.setAccessDetail(NetworkElementCommand.NETWORK_PUB_LAST_IP, "false");
886-
}
876+
setAccessDetailNetworkLastPublicIp(vlanLastIpMap, vlanTagKey, cmd);
887877

888878
cmds.addCommand(ipAssocCommand, cmd);
889879
}
890880
}
891881

882+
private void setAccessDetailNetworkLastPublicIp(Map<String, Boolean> vlanLastIpMap, String vlanTagKey, IpAssocCommand cmd) {
883+
// if public ip is the last ip in the vlan which is used for static nat or has active rules,
884+
// it will be checked for remove at the resource
885+
Boolean lastIp = vlanLastIpMap.get(vlanTagKey);
886+
if (lastIp == null) {
887+
cmd.setAccessDetail(NetworkElementCommand.NETWORK_PUB_LAST_IP, "true");
888+
} else {
889+
cmd.setAccessDetail(NetworkElementCommand.NETWORK_PUB_LAST_IP, "false");
890+
}
891+
}
892+
893+
private Map<String, Boolean> getVlanLastIpMap(Long vpcId, Long guestNetworkId) {
894+
// for network if the ips does not have any rules, then only last ip
895+
final Map<String, Boolean> vlanLastIpMap = new HashMap<String, Boolean>();
896+
final List<IPAddressVO> userIps;
897+
if (vpcId != null) {
898+
userIps = _ipAddressDao.listByAssociatedVpc(vpcId, null);
899+
} else {
900+
userIps = _ipAddressDao.listByAssociatedNetwork(guestNetworkId, null);
901+
}
902+
for (IPAddressVO ip : userIps) {
903+
String vlanTag = _vlanDao.findById(ip.getVlanId()).getVlanTag();
904+
Boolean lastIp = vlanLastIpMap.get(vlanTag);
905+
if (lastIp != null && !lastIp) {
906+
continue;
907+
}
908+
if (ip.isSourceNat()
909+
|| _rulesDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Active) > 0
910+
|| (ip.isOneToOneNat() && ip.getRuleState() == null)) {
911+
vlanLastIpMap.put(vlanTag, false);
912+
}
913+
}
914+
return vlanLastIpMap;
915+
}
916+
892917
public void createStaticRouteCommands(final List<StaticRouteProfile> staticRoutes, final DomainRouterVO router, final Commands cmds) {
893918
final SetStaticRouteCommand cmd = new SetStaticRouteCommand(staticRoutes);
894919
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));

systemvm/debian/etc/sysctl.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ net.ipv4.conf.default.send_redirects = 0
2727
net.ipv4.conf.all.secure_redirects = 0
2828
net.ipv4.conf.default.secure_redirects = 0
2929

30+
# Promote secondary ip to be primary if primary IP is removed
31+
net.ipv4.conf.all.promote_secondaries = 1
32+
net.ipv4.conf.default.promote_secondaries = 1
33+
3034
# For smooth transition of the vip address in case of a keepalived failover
3135
net.ipv4.ip_nonlocal_bind = 1
3236

0 commit comments

Comments
 (0)