Skip to content

Commit 3ded3e9

Browse files
committed
Merge pull request #887 from schubergphilis/vr_fixes_combined
[BLOCKER] Combined PRs that fix VR issuesTonight I worked with @wilderrodrigues to figure out what is wrong with the virtual router. As we couldn't test single PRs any more (because of other issues with them causing tests to fail) we added all VR related PRs in a separate branch and started testing from there. We combined the following PRs into this PR: #836 #851 #867 #870 #881 #882 #842 After that, one issue remains: the VPC does not get a default gateway. Which is strange, because we already solved it in PR #738. When I look back, it was fixed again in PR #784. It could very well be that either one fixed one specific case, but also breaking the other. We need to investigate this, and make sure there will be a fix that works both for VPCs and VRs. When we manually add the default gateway on the VPC, most tests pass and also spinning up two VPCs with one tier each, having a VM and them using s2s to VPN them together works fine. See for more details the report Wilder sent earlier. Tomorrow we'll try to figure out how to fix the default gateway and merge this. Then we should have a base to work from again. Any PR that fixes another blocker, should at least then be rebased against the fixed master so we can run the tests against the PR branch. I'm not saying everything is fixed, I'm just saying that we can spin up a cloud that has working VMs. When, in the mean time, someone has the time to checkout this branch and make the default route work for both VPC and VR that would be awesome. After that we should double check and verify the test results. Pinging @karuturi to let her know the current status. Regards, Wilder / Remi * pr/887: Fixing the index out of bounds error in the check_if_link_up() function small cleanups Fixing the defaut route for VPC routers Formatting the get_gateway() method in the CsDatabag.py file Fixing the dhcpsrvr iptables file Formatting the router_proxy.sh script CLOUDSTACK-8881: Fixed Static and PF configuration issue CLOUDSTACK-8905: Fixed hooking egress rules CLOUDSTACK-8891: Fixed default iptables rules on VR for guest traffic Configured dnsmasq to listen on all interfaces so that vpn client gets dns CLOUDSTACK-8864: Not able to add TCP port forwarding rule in VPN for specific ports CLOUDSTACK-8863: VM doesn't reconnect to internet post VR RESTART/STOP-START/RECREATE CLOUDSTACK-8843: Fixed issue in default iptables rules on shared network VR Signed-off-by: Remi Bergsma <[email protected]>
2 parents 415631a + 09e05f2 commit 3ded3e9

File tree

11 files changed

+210
-43
lines changed

11 files changed

+210
-43
lines changed

scripts/network/domr/router_proxy.sh

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
# specific language governing permissions and limitations
1717
# under the License.
1818

19-
20-
2119
# used as a proxy to call script inside virtual router
2220

2321
#set -x
@@ -47,12 +45,3 @@ check_gw "$domRIp"
4745

4846
ssh -p 3922 -q -o StrictHostKeyChecking=no -i $cert root@$domRIp "/opt/cloud/bin/$script $*"
4947
exit $?
50-
51-
52-
53-
54-
55-
56-
57-
58-

server/src/com/cloud/network/firewall/FirewallManagerImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflict
426426
// we allow port forwarding rules with the same parameters but different protocols
427427
boolean allowPf =
428428
(rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(
429-
rule.getProtocol()));
429+
rule.getProtocol())) || (rule.getPurpose() == Purpose.Vpn && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(
430+
rule.getProtocol()));
430431
boolean allowStaticNat =
431432
(rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()));
432433

server/test/com/cloud/network/firewall/FirewallManagerTest.java

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,28 @@
2222
import static org.mockito.Mockito.mock;
2323
import static org.mockito.Mockito.verify;
2424
import static org.mockito.Mockito.when;
25+
import static org.mockito.Mockito.spy;
2526

2627
import java.util.ArrayList;
2728
import java.util.List;
2829

29-
import javax.inject.Inject;
30-
30+
import com.cloud.exception.NetworkRuleConflictException;
31+
import com.cloud.network.NetworkModel;
32+
import com.cloud.network.dao.FirewallRulesDao;
33+
import com.cloud.network.vpc.VpcManager;
34+
import com.cloud.user.AccountManager;
35+
import com.cloud.user.DomainManager;
3136
import junit.framework.Assert;
3237

3338
import org.apache.log4j.Logger;
39+
import org.junit.Before;
3440
import org.junit.Ignore;
3541
import org.junit.Test;
3642
import org.junit.runner.RunWith;
37-
import org.springframework.test.context.ContextConfiguration;
38-
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
43+
import org.mockito.InjectMocks;
44+
import org.mockito.Mock;
45+
import org.mockito.MockitoAnnotations;
46+
import org.mockito.runners.MockitoJUnitRunner;
3947

4048
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
4149

@@ -52,9 +60,9 @@
5260
import com.cloud.network.rules.FirewallRuleVO;
5361
import com.cloud.utils.component.ComponentContext;
5462

55-
@Ignore("Requires database to be set up")
56-
@RunWith(SpringJUnit4ClassRunner.class)
57-
@ContextConfiguration(locations = "classpath:/testContext.xml")
63+
//@Ignore("Requires database to be set up")
64+
@RunWith(MockitoJUnitRunner.class)
65+
//@ContextConfiguration(locations = "classpath:/testContext.xml")
5866
//@ComponentSetup(managerName="management-server", setupXml="network-mgr-component.xml")
5967
public class FirewallManagerTest {
6068
private static final Logger s_logger = Logger.getLogger(FirewallManagerTest.class);
@@ -71,6 +79,7 @@ public class FirewallManagerTest {
7179
// super.setUp();
7280
// }
7381

82+
@Ignore("Requires database to be set up")
7483
@Test
7584
public void testInjected() {
7685

@@ -100,9 +109,30 @@ public void testInjected() {
100109

101110
}
102111

103-
@Inject
104-
FirewallManager _firewallMgr;
112+
@Mock
113+
AccountManager _accountMgr;
114+
@Mock
115+
NetworkOrchestrationService _networkMgr;
116+
@Mock
117+
NetworkModel _networkModel;
118+
@Mock
119+
DomainManager _domainMgr;
120+
@Mock
121+
VpcManager _vpcMgr;
122+
@Mock
123+
IpAddressManager _ipAddrMgr;
124+
@Mock
125+
FirewallRulesDao _firewallDao;
126+
127+
@InjectMocks
128+
FirewallManager _firewallMgr = new FirewallManagerImpl();
129+
130+
@Before
131+
public void initMocks() {
132+
MockitoAnnotations.initMocks(this);
133+
}
105134

135+
@Ignore("Requires database to be set up")
106136
@Test
107137
public void testApplyRules() {
108138
List<FirewallRuleVO> ruleList = new ArrayList<FirewallRuleVO>();
@@ -123,6 +153,7 @@ public void testApplyRules() {
123153
}
124154
}
125155

156+
@Ignore("Requires database to be set up")
126157
@Test
127158
public void testApplyFWRules() {
128159
List<FirewallRuleVO> ruleList = new ArrayList<FirewallRuleVO>();
@@ -151,4 +182,38 @@ public void testApplyFWRules() {
151182
}
152183
}
153184

185+
@Test
186+
public void testDetectRulesConflict() {
187+
List<FirewallRuleVO> ruleList = new ArrayList<FirewallRuleVO>();
188+
FirewallRuleVO rule1 = spy(new FirewallRuleVO("rule1", 3, 500, "UDP", 1, 2, 1, Purpose.Vpn, null, null, null, null));
189+
FirewallRuleVO rule2 = spy(new FirewallRuleVO("rule2", 3, 1701, "UDP", 1, 2, 1, Purpose.Vpn, null, null, null, null));
190+
FirewallRuleVO rule3 = spy(new FirewallRuleVO("rule3", 3, 4500, "UDP", 1, 2, 1, Purpose.Vpn, null, null, null, null));
191+
192+
ruleList.add(rule1);
193+
ruleList.add(rule2);
194+
ruleList.add(rule3);
195+
196+
FirewallManagerImpl firewallMgr = (FirewallManagerImpl)_firewallMgr;
197+
198+
when(firewallMgr._firewallDao.listByIpAndPurposeAndNotRevoked(3,null)).thenReturn(ruleList);
199+
when(rule1.getId()).thenReturn(1L);
200+
when(rule2.getId()).thenReturn(2L);
201+
when(rule3.getId()).thenReturn(3L);
202+
203+
FirewallRule newRule1 = new FirewallRuleVO("newRule1", 3, 500, "TCP", 1, 2, 1, Purpose.PortForwarding, null, null, null, null);
204+
FirewallRule newRule2 = new FirewallRuleVO("newRule2", 3, 1701, "TCP", 1, 2, 1, Purpose.PortForwarding, null, null, null, null);
205+
FirewallRule newRule3 = new FirewallRuleVO("newRule3", 3, 4500, "TCP", 1, 2, 1, Purpose.PortForwarding, null, null, null, null);
206+
207+
try {
208+
firewallMgr.detectRulesConflict(newRule1);
209+
firewallMgr.detectRulesConflict(newRule2);
210+
firewallMgr.detectRulesConflict(newRule3);
211+
}
212+
catch (NetworkRuleConflictException ex) {
213+
Assert.fail();
214+
}
215+
}
216+
217+
218+
154219
}

systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ local=/2.vmops-test.vmops.com/
8787
# specified interfaces (and the loopback) give the name of the
8888
# interface (eg eth0) here.
8989
# Repeat the line for more than one interface.
90-
interface=eth0
90+
#interface=eth0
9191
# Or you can specify which interface _not_ to listen on
9292
except-interface=eth1
9393
except-interface=eth2
@@ -108,7 +108,7 @@ no-dhcp-interface=eth2
108108
# want dnsmasq to really bind only the interfaces it is listening on,
109109
# uncomment this option. About the only time you may need this is when
110110
# running another nameserver on the same machine.
111-
bind-interfaces
111+
#bind-interfaces
112112

113113
# If you don't want dnsmasq to read /etc/hosts, uncomment the
114114
# following line.

systemvm/patches/debian/config/etc/init.d/cloud-early-config

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,8 +706,6 @@ setup_dnsmasq() {
706706
sed -i -e "s/^dhcp-range_ip6=.*$//" /etc/dnsmasq.conf
707707
fi
708708

709-
sed -i -e "s/^[#]*listen-address=.*$/listen-address=$LOCAL_ADDRS/" /etc/dnsmasq.conf
710-
711709
if [ "$RROUTER" == "1" ]
712710
then
713711
DEFAULT_GW=$GUEST_GW
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
*nat
19+
:PREROUTING ACCEPT [0:0]
20+
:POSTROUTING ACCEPT [0:0]
21+
:OUTPUT ACCEPT [0:0]
22+
COMMIT
23+
*filter
24+
:INPUT DROP [0:0]
25+
:FORWARD DROP [0:0]
26+
:OUTPUT ACCEPT [0:0]
27+
:FW_EGRESS_RULES - [0:0]
28+
:FW_OUTBOUND - [0:0]
29+
-A INPUT -d 224.0.0.18/32 -j ACCEPT
30+
-A INPUT -d 225.0.0.50/32 -j ACCEPT
31+
-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
32+
-A INPUT -i eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
33+
-A INPUT -i eth2 -m state --state RELATED,ESTABLISHED -j ACCEPT
34+
-A INPUT -p icmp -j ACCEPT
35+
-A INPUT -i lo -j ACCEPT
36+
-A INPUT -i eth0 -p udp -m udp --dport 67 -j ACCEPT
37+
-A INPUT -i eth0 -p udp -m udp --dport 53 -j ACCEPT
38+
-A INPUT -i eth0 -p tcp -m tcp --dport 53 -j ACCEPT
39+
-A INPUT -i eth1 -p tcp -m tcp -m state --state NEW,ESTABLISHED --dport 3922 -j ACCEPT
40+
-A INPUT -i eth0 -p tcp -m tcp -m state --state NEW --dport 80 -j ACCEPT
41+
-A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
42+
-A FORWARD -i eth2 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
43+
-A FORWARD -i eth0 -o eth0 -m state --state NEW -j ACCEPT
44+
-A FORWARD -i eth0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
45+
-A FORWARD -i eth0 -o eth2 -j FW_OUTBOUND
46+
-A FW_EGRESS_RULES -j ACCEPT
47+
-I FW_OUTBOUND -m state --state RELATED,ESTABLISHED -j ACCEPT
48+
-A FW_OUTBOUND -j FW_EGRESS_RULES
49+
COMMIT
50+
*mangle
51+
:PREROUTING ACCEPT [0:0]
52+
:INPUT ACCEPT [0:0]
53+
:FORWARD ACCEPT [0:0]
54+
:OUTPUT ACCEPT [0:0]
55+
:POSTROUTING ACCEPT [0:0]
56+
-A PREROUTING -m state --state ESTABLISHED,RELATED -j CONNMARK --restore-mark
57+
-A POSTROUTING -p udp -m udp --dport bootpc -j CHECKSUM --checksum-fill
58+
COMMIT

systemvm/patches/debian/config/opt/cloud/bin/configure.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def add_rule(self, cidr):
124124
" -m %s " % rule['protocol'] +
125125
" --dport %s -j RETURN" % rnge])
126126
if self.direction == 'egress':
127+
self.fw.append(["filter", "", " -A FW_OUTBOUND -j FIREWALL_EGRESS_RULES"])
127128
if rule['protocol'] == "icmp":
128129
self.fw.append(["filter", "front",
129130
" -A FIREWALL_EGRESS_RULES" +
@@ -662,6 +663,20 @@ def process(self):
662663
elif rule["type"] == "staticnat":
663664
self.processStaticNatRule(rule)
664665

666+
#return the VR guest interface ipo
667+
def getGuestIp(self):
668+
ipr = []
669+
ipAddr = None
670+
for ip in self.config.address().get_ips():
671+
if ip.is_guest():
672+
ipr.append(ip)
673+
if len(ipr) > 0:
674+
ipAddr = sorted(ipr)[-1]
675+
if ipAddr:
676+
return ipAddr.get_ip()
677+
678+
return None
679+
665680
def getDeviceByIp(self, ipa):
666681
for ip in self.config.address().get_ips():
667682
if ip.ip_in_subnet(ipa):
@@ -725,7 +740,7 @@ def forward_vr(self, rule):
725740
)
726741
fw4 = "-j SNAT --to-source %s -A POSTROUTING -s %s -d %s/32 -o %s -p %s -m %s --dport %s" % \
727742
(
728-
self.getGatewayByIp(rule['internal_ip']),
743+
self.getGuestIp(),
729744
self.getNetworkByIp(rule['internal_ip']),
730745
rule['internal_ip'],
731746
self.getDeviceByIp(rule['internal_ip']),
@@ -809,6 +824,14 @@ def processStaticNatRule(self, rule):
809824
"-A POSTROUTING -o %s -s %s/32 -j SNAT --to-source %s" % (device, rule["internal_ip"], rule["public_ip"])])
810825
self.fw.append(["nat", "front",
811826
"-A OUTPUT -d %s/32 -j DNAT --to-destination %s" % (rule["public_ip"], rule["internal_ip"])])
827+
self.fw.append(["filter", "",
828+
"-A FORWARD -i %s -o eth0 -d %s -m state --state NEW -j ACCEPT " % (device, rule["internal_ip"])])
829+
830+
#configure the hairpin nat
831+
self.fw.append(["nat", "front",
832+
"-A PREROUTING -d %s -i eth0 -j DNAT --to-destination %s" % (rule["public_ip"], rule["internal_ip"])])
833+
834+
self.fw.append(["nat", "front", "-A POSTROUTING -s %s -d %s -j SNAT -o eth0 --to-source %s" % (self.getNetworkByIp(rule['internal_ip']),rule["internal_ip"], self.getGuestIp())])
812835

813836

814837
def main(argv):
@@ -818,51 +841,66 @@ def main(argv):
818841
format=config.get_format())
819842
config.set_address()
820843

844+
logging.debug("Configuring ip addresses")
821845
# IP configuration
822846
config.address().compare()
823847
config.address().process()
824848

849+
logging.debug("Configuring vmpassword")
825850
password = CsPassword("vmpassword", config)
826851
password.process()
827852

853+
logging.debug("Configuring vmdata")
828854
metadata = CsVmMetadata('vmdata', config)
829855
metadata.process()
830856

857+
logging.debug("Configuring networkacl")
831858
acls = CsAcl('networkacl', config)
832859
acls.process()
833860

861+
logging.debug("Configuring firewall rules")
834862
acls = CsAcl('firewallrules', config)
835863
acls.process()
836864

865+
logging.debug("Configuring PF rules")
837866
fwd = CsForwardingRules("forwardingrules", config)
838867
fwd.process()
839868

840869
red = CsRedundant(config)
841870
red.set()
842871

872+
logging.debug("Configuring s2s vpn")
843873
vpns = CsSite2SiteVpn("site2sitevpn", config)
844874
vpns.process()
845875

876+
logging.debug("Configuring remote access vpn")
846877
#remote access vpn
847878
rvpn = CsRemoteAccessVpn("remoteaccessvpn", config)
848879
rvpn.process()
849880

881+
logging.debug("Configuring vpn users list")
850882
#remote access vpn users
851883
vpnuser = CsVpnUser("vpnuserlist", config)
852884
vpnuser.process()
853885

886+
logging.debug("Configuring dhcp entry")
854887
dhcp = CsDhcp("dhcpentry", config)
855888
dhcp.process()
856889

890+
logging.debug("Configuring load balancer")
857891
lb = CsLoadBalancer("loadbalancer", config)
858892
lb.process()
859893

894+
logging.debug("Configuring monitor service")
860895
mon = CsMonitor("monitorservice", config)
861896
mon.process()
862897

898+
logging.debug("Configuring iptables rules .....")
863899
nf = CsNetfilters()
864900
nf.compare(config.get_fw())
865901

902+
logging.debug("Configuring iptables rules done ...saving rules")
903+
866904
# Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local
867905
CsHelper.save_iptables("iptables-save", "/etc/iptables/router_rules.v4")
868906
CsHelper.save_iptables("ip6tables-save", "/etc/iptables/router_rules.v6")

0 commit comments

Comments
 (0)