Skip to content

Commit 03e0447

Browse files
add L1VH IB support on CNI (#2762)
* add L1VH IB support on CNI * fix IB issues * fix UT errors * fix linter issues * add win 2025 support for cni image build * add and comments * fix a logic bug * disable endpoint creation and deletion if it's IB NIC * fix a linter issue * add UTs * add UTs for powershell * enhance Test_getInterfaceInfoKey test case * remove windows 2025 build from pipeline * fix some issues * add an UT to test pnpID * fix an issue * fix an ut * add double quotes * unblock a brunch of issues * remove unnecessary codes * upgradelatest upstream cnii build * fix a log * add windows build on pipeline temporarily * remove backendNIC check for findMasterInterface * add ut to confirm IB does not create endpoint * fix linter issue that use %q * format network.go * add more uts to cover powershell commands * remove windows2025 pipeline build * enhance logs * fix cniResult format * add getPnpidstate func * fix the issue for infraNIC routes * fix the issue for infraNIC routes * fix gateway ip address * add get-pnpdevice UT * add accelnetNIC support for L1VH * enhance logic for accelnet nic netowrk flag * enhance network windows uts * fix bitmask operator * use another PR for accelnet PR * gofumpt files * fix comments for functional codes * add uts * add more uts * fix uts * fix functional codes comments * Update cni/network/network.go Co-authored-by: tamilmani1989 <[email protected]> Signed-off-by: Paul Yu <[email protected]> * fix latest comments * fix an UT * fix invoker_cns_test.go * fix ut bugs * fix ut with SkipDefaultRoutes * add combination ut * add combination ut * add ncGateway address to ut * fix an ut bug * fix ut bug * add unhappy test cases * add endpoint add and deletion cases * push mock network creation hns api test cases * remove network creation hns call * add uts to mock hns network and endpoint calls * fix ut linter issues * add infraNIC only invoker test case * add unhappy path test case * remove infraNIC only case * remove unhappy test case * re-archetect cni ib codes and test * remove unnecessary logs * save endpoint state * save endpoint object for IB * fix linter issue * fix a brunch of linter issues * fix linter issues * fix linter issue * fix ut for returned error msg * temporary add manifest build for CNS/CNI to pipeline * feedback fix * fix linter issue * add ut to get networkName and networkID * remove Ankit's PR to build cns image * revert Ankit's changes back * remove win2025 build from pipeline * log error for invalid mac address * revert convertInterfaceInfoToCniResult impl * fix feedback * add crd changes to test * add win2025 yaml to build image * pass containerID to cns * revert changes back for review * revert changes back for review * gofumpt endpoint.go * remove comment * add latest comments * Update network/endpoint_windows.go Co-authored-by: tamilmani1989 <[email protected]> Signed-off-by: Paul Yu <[email protected]> * fix a linter issue * add error check * add error check * gofumpt endpoint windows test file --------- Signed-off-by: Paul Yu <[email protected]> Co-authored-by: tamilmani1989 <[email protected]>
1 parent 67b5827 commit 03e0447

21 files changed

+886
-75
lines changed

cni/azure-windows-swift.conflist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"cniVersion": "0.3.0",
2+
"cniVersion": "1.0.0",
33
"name": "azure",
44
"adapterName" : "",
55
"plugins": [

cni/cni.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const (
3232
)
3333

3434
// Supported CNI versions.
35-
var supportedVersions = []string{"0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0"}
35+
var supportedVersions = []string{"0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0"}
3636

3737
// CNI contract.
3838
type PluginApi interface {

cni/network/invoker_cns.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type IPResultInfo struct {
5353
macAddress string
5454
skipDefaultRoutes bool
5555
routes []cns.Route
56+
pnpID string
5657
}
5758

5859
func (i IPResultInfo) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
@@ -143,6 +144,7 @@ func (invoker *CNSIPAMInvoker) Add(addConfig IPAMAddConfig) (IPAMAddResult, erro
143144

144145
addResult := IPAMAddResult{interfaceInfo: make(map[string]network.InterfaceInfo)}
145146
numInterfacesWithDefaultRoutes := 0
147+
146148
for i := 0; i < len(response.PodIPInfo); i++ {
147149
info := IPResultInfo{
148150
podIPAddress: response.PodIPInfo[i].PodIPConfig.IPAddress,
@@ -156,6 +158,7 @@ func (invoker *CNSIPAMInvoker) Add(addConfig IPAMAddConfig) (IPAMAddResult, erro
156158
macAddress: response.PodIPInfo[i].MacAddress,
157159
skipDefaultRoutes: response.PodIPInfo[i].SkipDefaultRoutes,
158160
routes: response.PodIPInfo[i].Routes,
161+
pnpID: response.PodIPInfo[i].PnPID,
159162
}
160163

161164
logger.Info("Received info for pod",
@@ -167,7 +170,7 @@ func (invoker *CNSIPAMInvoker) Add(addConfig IPAMAddConfig) (IPAMAddResult, erro
167170
key := invoker.getInterfaceInfoKey(info.nicType, info.macAddress)
168171
switch info.nicType {
169172
case cns.DelegatedVMNIC:
170-
// only handling single v4 PodIPInfo for Frontend NICs at the moment, will have to update once v6 gets added
173+
// only handling single v4 PodIPInfo for DelegatedVMNIC at the moment, will have to update once v6 gets added
171174
if !info.skipDefaultRoutes {
172175
numInterfacesWithDefaultRoutes++
173176
}
@@ -180,6 +183,12 @@ func (invoker *CNSIPAMInvoker) Add(addConfig IPAMAddConfig) (IPAMAddResult, erro
180183
if err := configureSecondaryAddResult(&info, &addResult, &response.PodIPInfo[i].PodIPConfig, key); err != nil {
181184
return IPAMAddResult{}, err
182185
}
186+
case cns.BackendNIC:
187+
// TODO: check whether setting default route on IB interface
188+
// handle ipv4 PodIPInfo for BackendNIC
189+
if err := addBackendNICToResult(&info, &addResult, key); err != nil {
190+
return IPAMAddResult{}, err
191+
}
183192
case cns.InfraNIC, "":
184193
// if we change from legacy cns, the nicType will be empty, so we assume it is infra nic
185194
info.nicType = cns.InfraNIC
@@ -464,6 +473,7 @@ func configureSecondaryAddResult(info *IPResultInfo, addResult *IPAMAddResult, p
464473

465474
macAddress, err := net.ParseMAC(info.macAddress)
466475
if err != nil {
476+
logger.Error("Invalid mac address", zap.Error(err))
467477
return errors.Wrap(err, "Invalid mac address")
468478
}
469479

@@ -491,8 +501,31 @@ func configureSecondaryAddResult(info *IPResultInfo, addResult *IPAMAddResult, p
491501
return nil
492502
}
493503

504+
func addBackendNICToResult(info *IPResultInfo, addResult *IPAMAddResult, key string) error {
505+
macAddress, err := net.ParseMAC(info.macAddress)
506+
if err != nil {
507+
logger.Error("Invalid mac address", zap.Error(err))
508+
return errors.Wrap(err, "Invalid mac address")
509+
}
510+
511+
// return error if pnp id is missing in cns goalstate
512+
if info.pnpID == "" {
513+
logger.Error("pnp id is not received from cns")
514+
return errors.Wrap(err, "pnp id is not received from cns")
515+
}
516+
517+
addResult.interfaceInfo[key] = network.InterfaceInfo{
518+
NICType: info.nicType,
519+
MacAddress: macAddress,
520+
SkipDefaultRoutes: info.skipDefaultRoutes,
521+
PnPID: info.pnpID,
522+
}
523+
524+
return nil
525+
}
526+
494527
func (invoker *CNSIPAMInvoker) getInterfaceInfoKey(nicType cns.NICType, macAddress string) string {
495-
if nicType == cns.DelegatedVMNIC {
528+
if nicType == cns.DelegatedVMNIC || nicType == cns.BackendNIC {
496529
return macAddress
497530
}
498531
return string(nicType)

cni/network/invoker_cns_test.go

Lines changed: 210 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func TestCNSIPAMInvoker_Add_Overlay(t *testing.T) {
245245
wantErr: false,
246246
},
247247
{
248-
name: "Test happy CNI add with multitenant result",
248+
name: "Test happy CNI add with InfraNIC + DelegatedNIC interfaces",
249249
fields: fields{
250250
podName: testPodInfo.PodName,
251251
podNamespace: testPodInfo.PodNamespace,
@@ -496,7 +496,7 @@ func TestCNSIPAMInvoker_Add_Overlay(t *testing.T) {
496496
if ifInfo.NICType == cns.DelegatedVMNIC {
497497
fmt.Printf("want:%+v\nrest:%+v\n", tt.wantSecondaryInterfacesInfo, ifInfo)
498498
if len(tt.wantSecondaryInterfacesInfo.IPConfigs) > 0 {
499-
require.EqualValues(tt.wantSecondaryInterfacesInfo, ifInfo, "incorrect multitenant response")
499+
require.EqualValues(tt.wantSecondaryInterfacesInfo, ifInfo, "incorrect response for delegatedNIC")
500500
}
501501
}
502502
if ifInfo.NICType == cns.InfraNIC {
@@ -1444,7 +1444,8 @@ func Test_getInterfaceInfoKey(t *testing.T) {
14441444
require.Equal(string(cns.InfraNIC), inv.getInterfaceInfoKey(cns.InfraNIC, dummyMAC))
14451445
require.Equal(dummyMAC, inv.getInterfaceInfoKey(cns.DelegatedVMNIC, dummyMAC))
14461446
require.Equal("", inv.getInterfaceInfoKey(cns.DelegatedVMNIC, ""))
1447-
require.Equal(string(cns.NodeNetworkInterfaceBackendNIC), inv.getInterfaceInfoKey(cns.NodeNetworkInterfaceBackendNIC, dummyMAC))
1447+
require.Equal(dummyMAC, inv.getInterfaceInfoKey(cns.BackendNIC, dummyMAC))
1448+
require.Equal("", inv.getInterfaceInfoKey(cns.BackendNIC, ""))
14481449
}
14491450

14501451
func TestCNSIPAMInvoker_Add_SwiftV2(t *testing.T) {
@@ -1453,6 +1454,11 @@ func TestCNSIPAMInvoker_Add_SwiftV2(t *testing.T) {
14531454
macAddress := "12:34:56:78:9a:bc"
14541455
parsedMacAddress, _ := net.ParseMAC(macAddress)
14551456

1457+
ibMacAddress := "bc:9a:78:56:34:12"
1458+
ibParsedMacAddress, _ := net.ParseMAC(ibMacAddress)
1459+
1460+
pnpID := "PCI\\VEN_15B3&DEV_101C&SUBSYS_000715B3&REV_00\\5&8c5acce&0&0"
1461+
14561462
type fields struct {
14571463
podName string
14581464
podNamespace string
@@ -1470,11 +1476,12 @@ func TestCNSIPAMInvoker_Add_SwiftV2(t *testing.T) {
14701476
name string
14711477
fields fields
14721478
args args
1479+
wantDefaultResult network.InterfaceInfo
14731480
wantSecondaryInterfacesInfo map[string]network.InterfaceInfo
14741481
wantErr bool
14751482
}{
14761483
{
1477-
name: "Test happy CNI add with swiftv2 multitenant result",
1484+
name: "Test happy CNI add delegatedVMNIC type",
14781485
fields: fields{
14791486
podName: testPodInfo.PodName,
14801487
podNamespace: testPodInfo.PodNamespace,
@@ -1535,6 +1542,190 @@ func TestCNSIPAMInvoker_Add_SwiftV2(t *testing.T) {
15351542
},
15361543
wantErr: false,
15371544
},
1545+
{
1546+
name: "Test happy CNI add with DelegatedNIC + BackendNIC interfaces",
1547+
fields: fields{
1548+
podName: testPodInfo.PodName,
1549+
podNamespace: testPodInfo.PodNamespace,
1550+
cnsClient: &MockCNSClient{
1551+
require: require,
1552+
requestIPs: requestIPsHandler{
1553+
ipconfigArgument: cns.IPConfigsRequest{
1554+
PodInterfaceID: "testcont-testifname1",
1555+
InfraContainerID: "testcontainerid1",
1556+
OrchestratorContext: marshallPodInfo(testPodInfo),
1557+
},
1558+
result: &cns.IPConfigsResponse{
1559+
PodIPInfo: []cns.PodIpInfo{
1560+
{
1561+
PodIPConfig: cns.IPSubnet{
1562+
IPAddress: "10.1.1.10",
1563+
PrefixLength: 24,
1564+
},
1565+
HostPrimaryIPInfo: cns.HostIPInfo{
1566+
Gateway: "10.0.0.1",
1567+
PrimaryIP: "10.0.0.2",
1568+
Subnet: "10.0.0.1/24",
1569+
},
1570+
NICType: cns.DelegatedVMNIC,
1571+
MacAddress: macAddress,
1572+
SkipDefaultRoutes: false,
1573+
},
1574+
{
1575+
MacAddress: ibMacAddress,
1576+
NICType: cns.BackendNIC,
1577+
PnPID: pnpID,
1578+
},
1579+
},
1580+
Response: cns.Response{
1581+
ReturnCode: 0,
1582+
Message: "",
1583+
},
1584+
},
1585+
err: nil,
1586+
},
1587+
},
1588+
},
1589+
args: args{
1590+
nwCfg: &cni.NetworkConfig{},
1591+
args: &cniSkel.CmdArgs{
1592+
ContainerID: "testcontainerid1",
1593+
Netns: "testnetns1",
1594+
IfName: "testifname1",
1595+
},
1596+
hostSubnetPrefix: getCIDRNotationForAddress("10.0.0.1/24"),
1597+
options: map[string]interface{}{},
1598+
},
1599+
wantSecondaryInterfacesInfo: map[string]network.InterfaceInfo{
1600+
macAddress: {
1601+
IPConfigs: []*network.IPConfig{
1602+
{
1603+
Address: *getCIDRNotationForAddress("10.1.1.10/24"),
1604+
},
1605+
},
1606+
Routes: []network.RouteInfo{},
1607+
NICType: cns.DelegatedVMNIC,
1608+
MacAddress: parsedMacAddress,
1609+
},
1610+
ibMacAddress: {
1611+
NICType: cns.BackendNIC,
1612+
MacAddress: ibParsedMacAddress,
1613+
PnPID: pnpID,
1614+
},
1615+
},
1616+
wantErr: false,
1617+
},
1618+
{
1619+
name: "Test happy CNI add with InfraNIC + DelegatedNIC + BackendNIC interfaces",
1620+
fields: fields{
1621+
podName: testPodInfo.PodName,
1622+
podNamespace: testPodInfo.PodNamespace,
1623+
cnsClient: &MockCNSClient{
1624+
require: require,
1625+
requestIPs: requestIPsHandler{
1626+
ipconfigArgument: cns.IPConfigsRequest{
1627+
PodInterfaceID: "testcont-testifname1",
1628+
InfraContainerID: "testcontainerid1",
1629+
OrchestratorContext: marshallPodInfo(testPodInfo),
1630+
},
1631+
result: &cns.IPConfigsResponse{
1632+
PodIPInfo: []cns.PodIpInfo{
1633+
{
1634+
PodIPConfig: cns.IPSubnet{
1635+
IPAddress: "10.0.1.10",
1636+
PrefixLength: 24,
1637+
},
1638+
NetworkContainerPrimaryIPConfig: cns.IPConfiguration{
1639+
IPSubnet: cns.IPSubnet{
1640+
IPAddress: "10.0.1.0",
1641+
PrefixLength: 24,
1642+
},
1643+
DNSServers: nil,
1644+
GatewayIPAddress: "10.0.0.1",
1645+
},
1646+
HostPrimaryIPInfo: cns.HostIPInfo{
1647+
Gateway: "10.0.0.1",
1648+
PrimaryIP: "10.0.0.1",
1649+
Subnet: "10.0.0.0/24",
1650+
},
1651+
NICType: cns.InfraNIC,
1652+
SkipDefaultRoutes: true,
1653+
},
1654+
{
1655+
PodIPConfig: cns.IPSubnet{
1656+
IPAddress: "20.1.1.10",
1657+
PrefixLength: 24,
1658+
},
1659+
HostPrimaryIPInfo: cns.HostIPInfo{
1660+
Gateway: "20.0.0.1",
1661+
PrimaryIP: "20.0.0.2",
1662+
Subnet: "20.0.0.1/24",
1663+
},
1664+
NICType: cns.DelegatedVMNIC,
1665+
MacAddress: macAddress,
1666+
SkipDefaultRoutes: false,
1667+
},
1668+
{
1669+
MacAddress: ibMacAddress,
1670+
NICType: cns.BackendNIC,
1671+
PnPID: pnpID,
1672+
},
1673+
},
1674+
Response: cns.Response{
1675+
ReturnCode: 0,
1676+
Message: "",
1677+
},
1678+
},
1679+
err: nil,
1680+
},
1681+
},
1682+
},
1683+
args: args{
1684+
nwCfg: &cni.NetworkConfig{},
1685+
args: &cniSkel.CmdArgs{
1686+
ContainerID: "testcontainerid1",
1687+
Netns: "testnetns1",
1688+
IfName: "testifname1",
1689+
},
1690+
hostSubnetPrefix: getCIDRNotationForAddress("10.0.0.1/24"),
1691+
options: map[string]interface{}{},
1692+
},
1693+
wantDefaultResult: network.InterfaceInfo{
1694+
IPConfigs: []*network.IPConfig{
1695+
{
1696+
Address: *getCIDRNotationForAddress("10.0.1.10/24"),
1697+
Gateway: net.ParseIP("10.0.0.1"),
1698+
},
1699+
},
1700+
Routes: []network.RouteInfo{
1701+
{
1702+
Dst: network.Ipv4DefaultRouteDstPrefix,
1703+
Gw: net.ParseIP("10.0.0.1"),
1704+
},
1705+
},
1706+
NICType: cns.InfraNIC,
1707+
SkipDefaultRoutes: true,
1708+
HostSubnetPrefix: *parseCIDR("10.0.0.0/24"),
1709+
},
1710+
wantSecondaryInterfacesInfo: map[string]network.InterfaceInfo{
1711+
macAddress: {
1712+
IPConfigs: []*network.IPConfig{
1713+
{
1714+
Address: *getCIDRNotationForAddress("20.1.1.10/24"),
1715+
},
1716+
},
1717+
Routes: []network.RouteInfo{},
1718+
NICType: cns.DelegatedVMNIC,
1719+
MacAddress: parsedMacAddress,
1720+
},
1721+
ibMacAddress: {
1722+
NICType: cns.BackendNIC,
1723+
MacAddress: ibParsedMacAddress,
1724+
PnPID: pnpID,
1725+
},
1726+
},
1727+
wantErr: false,
1728+
},
15381729
}
15391730
for _, tt := range tests {
15401731
tt := tt
@@ -1551,9 +1742,21 @@ func TestCNSIPAMInvoker_Add_SwiftV2(t *testing.T) {
15511742
require.NoError(err)
15521743
}
15531744

1554-
fmt.Printf("want:%+v\nrest:%+v\n", tt.wantSecondaryInterfacesInfo, ipamAddResult.interfaceInfo)
1555-
if len(tt.wantSecondaryInterfacesInfo[macAddress].IPConfigs) > 0 {
1556-
require.EqualValues(tt.wantSecondaryInterfacesInfo, ipamAddResult.interfaceInfo, "incorrect multitenant response")
1745+
for _, ifInfo := range ipamAddResult.interfaceInfo {
1746+
if ifInfo.NICType == cns.InfraNIC {
1747+
fmt.Printf("want:%+v\nrest:%+v\n", tt.wantDefaultResult, ifInfo)
1748+
require.Equalf(tt.wantDefaultResult, ifInfo, "incorrect ipv4 response")
1749+
}
1750+
1751+
if ifInfo.NICType == cns.BackendNIC {
1752+
fmt.Printf("want:%+v\nrest:%+v\n", tt.wantSecondaryInterfacesInfo, ipamAddResult.interfaceInfo[ibMacAddress])
1753+
require.EqualValues(tt.wantSecondaryInterfacesInfo[ibMacAddress], ipamAddResult.interfaceInfo[ibMacAddress], "incorrect multitenant response for IB")
1754+
}
1755+
1756+
if ifInfo.NICType == cns.DelegatedVMNIC {
1757+
fmt.Printf("want:%+v\nrest:%+v\n", tt.wantSecondaryInterfacesInfo[macAddress], ipamAddResult.interfaceInfo[macAddress])
1758+
require.EqualValues(tt.wantSecondaryInterfacesInfo[macAddress], ipamAddResult.interfaceInfo[macAddress], "incorrect multitenant response for Delegated")
1759+
}
15571760
}
15581761
})
15591762
}

0 commit comments

Comments
 (0)