Skip to content

Commit c12e138

Browse files
fmaximusyadvr
authored andcommitted
CLOUDSTACK-10127: For OVS to work use dev/nic id based on mac address for KVM (#2304)
This uses mac address based referencing for nic/dev id for KVM. This fixes openvswitch (ovs) regression.
1 parent f250b3a commit c12e138

File tree

2 files changed

+284
-11
lines changed

2 files changed

+284
-11
lines changed

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,27 +1596,20 @@ protected ExecutionResult prepareNetworkElementCommand(final IpAssocVpcCommand c
15961596
final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
15971597

15981598
try {
1599-
conn = LibvirtConnection.getConnectionByVmName(routerName);
1599+
conn = getLibvirtUtilitiesHelper().getConnectionByVmName(routerName);
16001600
final IpAddressTO[] ips = cmd.getIpAddresses();
16011601
Integer devNum = 0;
1602-
final Map<String, Integer> broadcastUriToNicNum = new HashMap<String, Integer>();
16031602
final List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
1603+
final Map<String, Integer> macAddressToNicNum = new HashMap<>(pluggedNics.size());
16041604

16051605
for (final InterfaceDef pluggedNic : pluggedNics) {
16061606
final String pluggedVlan = pluggedNic.getBrName();
1607-
if (pluggedVlan.equalsIgnoreCase(_linkLocalBridgeName)) {
1608-
broadcastUriToNicNum.put("LinkLocal", devNum);
1609-
} else if (pluggedVlan.equalsIgnoreCase(_publicBridgeName) || pluggedVlan.equalsIgnoreCase(_privBridgeName) ||
1610-
pluggedVlan.equalsIgnoreCase(_guestBridgeName)) {
1611-
broadcastUriToNicNum.put(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString(), devNum);
1612-
} else {
1613-
broadcastUriToNicNum.put(getBroadcastUriFromBridge(pluggedVlan), devNum);
1614-
}
1607+
macAddressToNicNum.put(pluggedNic.getMacAddress(), devNum);
16151608
devNum++;
16161609
}
16171610

16181611
for (final IpAddressTO ip : ips) {
1619-
ip.setNicDevId(broadcastUriToNicNum.get(ip.getBroadcastUri()));
1612+
ip.setNicDevId(macAddressToNicNum.get(ip.getVifMacAddress()));
16201613
}
16211614

16221615
return new ExecutionResult(true, null);
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
package com.cloud.hypervisor.kvm.resource.wrapper;
20+
21+
import static org.junit.Assert.assertEquals;
22+
import static org.mockito.Matchers.anyString;
23+
import static org.mockito.Mockito.doReturn;
24+
import static org.mockito.Mockito.mock;
25+
import static org.mockito.Mockito.spy;
26+
import static org.mockito.Mockito.when;
27+
28+
import javax.naming.ConfigurationException;
29+
30+
import org.junit.Before;
31+
import org.junit.Test;
32+
import org.libvirt.Connect;
33+
import org.libvirt.Domain;
34+
import org.libvirt.LibvirtException;
35+
36+
import com.cloud.agent.api.routing.IpAssocVpcCommand;
37+
import com.cloud.agent.api.routing.NetworkElementCommand;
38+
import com.cloud.agent.api.to.IpAddressTO;
39+
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
40+
import com.cloud.network.Networks;
41+
import com.cloud.utils.ExecutionResult;
42+
43+
public class LibvirtNetworkElementCommandWrapperTest {
44+
private static final String fullfile = "<domain type='kvm' id='143'>\n"
45+
+ " <name>r-3-VM</name>\n"
46+
+ " <uuid>8825b180-468f-4227-beb7-6b06fd342116</uuid>\n"
47+
+ " <description>CentOS 5.5 (64-bit)</description>\n"
48+
+ " <memory unit='KiB'>262144</memory>\n"
49+
+ " <currentMemory unit='KiB'>262144</currentMemory>\n"
50+
+ " <vcpu placement='static'>1</vcpu>\n"
51+
+ " <cputune>\n"
52+
+ " <shares>256</shares>\n"
53+
+ " </cputune>\n"
54+
+ " <sysinfo type='smbios'>\n"
55+
+ " <system>\n"
56+
+ " <entry name='manufacturer'>Apache Software Foundation</entry>\n"
57+
+ " <entry name='product'>CloudStack KVM Hypervisor</entry>\n"
58+
+ " <entry name='uuid'>8825b180-468f-4227-beb7-6b06fd342116</entry>\n"
59+
+ " </system>\n"
60+
+ " </sysinfo>\n"
61+
+ " <os>\n"
62+
+ " <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>\n"
63+
+ " <boot dev='cdrom'/>\n"
64+
+ " <boot dev='hd'/>\n"
65+
+ " <smbios mode='sysinfo'/>\n"
66+
+ " </os>\n"
67+
+ " <features>\n"
68+
+ " <acpi/>\n"
69+
+ " <apic/>\n"
70+
+ " <pae/>\n"
71+
+ " </features>\n"
72+
+ " <clock offset='utc'>\n"
73+
+ " <timer name='kvmclock'/>\n"
74+
+ " </clock>\n"
75+
+ " <on_poweroff>destroy</on_poweroff>\n"
76+
+ " <on_reboot>restart</on_reboot>\n"
77+
+ " <on_crash>destroy</on_crash>\n"
78+
+ " <devices>\n"
79+
+ " <emulator>/usr/libexec/qemu-kvm</emulator>\n"
80+
+ " <disk type='file' device='disk'>\n"
81+
+ " <driver name='qemu' type='qcow2' cache='none'/>\n"
82+
+ " <source file='/mnt/4436eeec-abec-3ef8-b733-c9541df20361/0c4aae69-2652-4a04-b460-1abb5a1a695c'/>\n"
83+
+ " <backingStore type='file' index='1'>\n"
84+
+ " <format type='raw'/>\n"
85+
+ " <source file='/mnt/4436eeec-abec-3ef8-b733-c9541df20361/d9ce07e5-9e13-11e7-816b-faac09070700'/>\n"
86+
+ " <backingStore/>\n"
87+
+ " </backingStore>\n"
88+
+ " <target dev='vda' bus='virtio'/>\n"
89+
+ " <serial>0c4aae6926524a04b460</serial>\n"
90+
+ " <alias name='virtio-disk0'/>\n"
91+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>\n"
92+
+ " </disk>\n"
93+
+ " <disk type='file' device='cdrom'>\n"
94+
+ " <driver name='qemu' type='raw' cache='none'/>\n"
95+
+ " <backingStore/>\n"
96+
+ " <target dev='hdc' bus='ide'/>\n"
97+
+ " <readonly/>\n"
98+
+ " <alias name='ide0-1-0'/>\n"
99+
+ " <address type='drive' controller='0' bus='1' target='0' unit='0'/>\n"
100+
+ " </disk>\n"
101+
+ " <controller type='usb' index='0'>\n"
102+
+ " <alias name='usb'/>\n"
103+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>\n"
104+
+ " </controller>\n"
105+
+ " <controller type='pci' index='0' model='pci-root'>\n"
106+
+ " <alias name='pci.0'/>\n"
107+
+ " </controller>\n"
108+
+ " <controller type='ide' index='0'>\n"
109+
+ " <alias name='ide'/>\n"
110+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>\n"
111+
+ " </controller>\n"
112+
+ " <controller type='virtio-serial' index='0'>\n"
113+
+ " <alias name='virtio-serial0'/>\n"
114+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>\n"
115+
+ " </controller>\n"
116+
+ " <interface type='bridge'>\n"
117+
+ " <mac address='02:00:7c:98:00:01'/>\n"
118+
+ " <source bridge='cloud0'/>\n"
119+
+ " <bandwidth>\n"
120+
+ " <inbound average='25600' peak='25600'/>\n"
121+
+ " <outbound average='25600' peak='25600'/>\n"
122+
+ " </bandwidth>\n"
123+
+ " <target dev='vnet1'/>\n"
124+
+ " <model type='virtio'/>\n"
125+
+ " <virtualport type='openvswitch'>\n"
126+
+ " </virtualport>\n"
127+
+ " <link state='up'/>\n"
128+
+ " <alias name='net0'/>\n"
129+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>\n"
130+
+ " </interface>\n"
131+
+ " <interface type='bridge'>\n"
132+
+ " <mac address='02:00:7c:98:00:02'/>\n"
133+
+ " <source bridge='publicbr'/>\n"
134+
+ " <bandwidth>\n"
135+
+ " <inbound average='25600' peak='25600'/>\n"
136+
+ " <outbound average='25600' peak='25600'/>\n"
137+
+ " </bandwidth>\n"
138+
+ " <target dev='vnet2'/>\n"
139+
+ " <model type='virtio'/>\n"
140+
+ " <virtualport type='openvswitch'>\n"
141+
+ " </virtualport>\n"
142+
+ " <link state='up'/>\n"
143+
+ " <alias name='net1'/>\n"
144+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>\n"
145+
+ " </interface>\n"
146+
+ " <interface type='bridge'>\n"
147+
+ " <mac address='02:00:7c:98:00:03'/>\n"
148+
+ " <source bridge='guestbr-100'/>\n"
149+
+ " <bandwidth>\n"
150+
+ " <inbound average='25600' peak='25600'/>\n"
151+
+ " <outbound average='25600' peak='25600'/>\n"
152+
+ " </bandwidth>\n"
153+
+ " <target dev='vnet3'/>\n"
154+
+ " <model type='virtio'/>\n"
155+
+ " <virtualport type='openvswitch'>\n"
156+
+ " </virtualport>\n"
157+
+ " <link state='up'/>\n"
158+
+ " <alias name='net2'/>\n"
159+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>\n"
160+
+ " </interface>\n"
161+
+ " <interface type='bridge'>\n"
162+
+ " <mac address='02:00:7c:98:00:04'/>\n"
163+
+ " <source bridge='guestbr-101'/>\n"
164+
+ " <bandwidth>\n"
165+
+ " <inbound average='25600' peak='25600'/>\n"
166+
+ " <outbound average='25600' peak='25600'/>\n"
167+
+ " </bandwidth>\n"
168+
+ " <target dev='vnet4'/>\n"
169+
+ " <model type='virtio'/>\n"
170+
+ " <virtualport type='openvswitch'>\n"
171+
+ " </virtualport>\n"
172+
+ " <link state='up'/>\n"
173+
+ " <alias name='net3'/>\n"
174+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>\n"
175+
+ " </interface>\n"
176+
+ " <serial type='pty'>\n"
177+
+ " <source path='/dev/pts/4'/>\n"
178+
+ " <target port='0'/>\n"
179+
+ " <alias name='serial0'/>\n"
180+
+ " </serial>\n"
181+
+ " <console type='pty' tty='/dev/pts/4'>\n"
182+
+ " <source path='/dev/pts/4'/>\n"
183+
+ " <target type='serial' port='0'/>\n"
184+
+ " <alias name='serial0'/>\n"
185+
+ " </console>\n"
186+
+ " <channel type='unix'>\n"
187+
+ " <source mode='bind' path='/var/lib/libvirt/qemu/i-85-285-VM.org.qemu.guest_agent.0'/>\n"
188+
+ " <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/>\n"
189+
+ " <alias name='channel0'/>\n"
190+
+ " <address type='virtio-serial' controller='0' bus='0' port='1'/>\n"
191+
+ " </channel>\n"
192+
+ " <input type='tablet' bus='usb'>\n"
193+
+ " <alias name='input0'/>\n"
194+
+ " </input>\n"
195+
+ " <input type='mouse' bus='ps2'/>\n"
196+
+ " <input type='keyboard' bus='ps2'/>\n"
197+
+ " <graphics type='vnc' port='5903' autoport='yes' listen='10.100.100.11'>\n"
198+
+ " <listen type='address' address='10.100.100.11'/>\n"
199+
+ " </graphics>\n"
200+
+ " <video>\n"
201+
+ " <model type='cirrus' vram='16384' heads='1'/>\n"
202+
+ " <alias name='video0'/>\n"
203+
+ " <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>\n"
204+
+ " </video>\n"
205+
+ " <memballoon model='none'>\n"
206+
+ " <alias name='balloon0'/>\n"
207+
+ " </memballoon>\n"
208+
+ " </devices>\n"
209+
+ "</domain>\n";
210+
211+
private LibvirtComputingResource res;
212+
private final Domain _domain = mock(Domain.class);
213+
214+
@Before
215+
public void setUp() throws LibvirtException, ConfigurationException {
216+
// Use a spy because we only want to override getVifDriverClass
217+
LibvirtComputingResource resReal = new LibvirtComputingResource() {
218+
{
219+
_linkLocalBridgeName = "cloud0";
220+
_guestBridgeName = "guestbr";
221+
_publicBridgeName = "publicbr";
222+
_privBridgeName = "mgmtbr";
223+
}
224+
};
225+
226+
res = spy(resReal);
227+
228+
Connect conn = mock(Connect.class);
229+
LibvirtUtilitiesHelper helper = mock(LibvirtUtilitiesHelper.class);
230+
231+
when(_domain.getXMLDesc(0)).thenReturn(fullfile);
232+
when(conn.domainLookupByName(anyString())).thenReturn(_domain);
233+
when(helper.getConnectionByVmName(anyString())).thenReturn(conn);
234+
235+
doReturn(helper).when(res).getLibvirtUtilitiesHelper();
236+
}
237+
238+
@Test
239+
public void testPrepareIpAssocVpcCommand() throws LibvirtException {
240+
IpAddressTO ip = new IpAddressTO(1, "171.31.1.3",
241+
true, false, false,
242+
"vlan://untagged",
243+
"172.31.1.1",
244+
"255.255.0.0",
245+
"02:00:7c:98:00:02",
246+
0,
247+
true);
248+
ip.setTrafficType(Networks.TrafficType.Public);
249+
IpAddressTO[] ips = new IpAddressTO[] {
250+
ip
251+
};
252+
final IpAssocVpcCommand command = new IpAssocVpcCommand(ips);
253+
command.setAccessDetail(NetworkElementCommand.ROUTER_IP, "127.0.0.1");
254+
ExecutionResult result = res.prepareCommand(command);
255+
256+
assertEquals(1, ips[0].getNicDevId().intValue());
257+
}
258+
259+
@Test
260+
public void testVpcPrivateGateway() throws LibvirtException {
261+
IpAddressTO ip = new IpAddressTO(1, "171.31.1.3",
262+
true, false, false,
263+
"vlan://untagged",
264+
"172.31.1.1",
265+
"255.255.0.0",
266+
"02:00:7c:98:00:03",
267+
0,
268+
false);
269+
ip.setTrafficType(Networks.TrafficType.Guest);
270+
IpAddressTO[] ips = new IpAddressTO[] {
271+
ip
272+
};
273+
final IpAssocVpcCommand command = new IpAssocVpcCommand(ips);
274+
command.setAccessDetail(NetworkElementCommand.ROUTER_IP, "127.0.0.1");
275+
ExecutionResult result = res.prepareCommand(command);
276+
277+
assertEquals(2, ips[0].getNicDevId().intValue());
278+
}
279+
280+
}

0 commit comments

Comments
 (0)