Skip to content

Commit 40e65f2

Browse files
committed
add validation webhooks for netfilter nic selector
Signed-off-by: Sebastian Sch <sebassch@gmail.com>
1 parent 42d4fc0 commit 40e65f2

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

pkg/webhook/validate.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,27 @@ func staticValidateSriovNetworkNodePolicy(cr *sriovnetworkv1.SriovNetworkNodePol
153153
return false, fmt.Errorf("at least one of these parameters (vendor, deviceID, pfNames, rootDevices or netFilter) has to be defined in nicSelector in CR %s", cr.GetName())
154154
}
155155

156+
// NetFilter specific validations - must be checked early before other validations
157+
if cr.Spec.NicSelector.NetFilter != "" {
158+
// 1. do not allow to use any other nicSelector fields when NetFilter is specified
159+
if cr.Spec.NicSelector.Vendor != "" || cr.Spec.NicSelector.DeviceID != "" ||
160+
len(cr.Spec.NicSelector.PfNames) > 0 || len(cr.Spec.NicSelector.RootDevices) > 0 {
161+
return false, fmt.Errorf("nicSelector fields vendor, deviceID, pfNames, and rootDevices are not allowed when netFilter is specified")
162+
}
163+
// 2. do not support changing the EswitchMode when NetFilter is specified
164+
if cr.Spec.EswitchMode != "" {
165+
return false, fmt.Errorf("eSwitchMode is not supported when netFilter is specified")
166+
}
167+
// 3. do not allow Bridge when NetFilter is specified
168+
if !cr.Spec.Bridge.IsEmpty() {
169+
return false, fmt.Errorf("bridge configuration is not supported when netFilter is specified")
170+
}
171+
// 4. LinkType only "eth", "ETH" allowed when NetFilter is specified
172+
if cr.Spec.LinkType != "" && !strings.EqualFold(cr.Spec.LinkType, consts.LinkTypeETH) {
173+
return false, fmt.Errorf("linkType %q is not allowed when netFilter is specified, only 'eth' or 'ETH' are supported", cr.Spec.LinkType)
174+
}
175+
}
176+
156177
devMode := false
157178
if os.Getenv("DEV_MODE") == "TRUE" {
158179
devMode = true
@@ -233,6 +254,7 @@ func staticValidateSriovNetworkNodePolicy(cr *sriovnetworkv1.SriovNetworkNodePol
233254
if !cr.Spec.Bridge.IsEmpty() && cr.Spec.ExternallyManaged {
234255
return false, fmt.Errorf("software bridge management can't be used when the device externally managed")
235256
}
257+
236258
return true, nil
237259
}
238260

pkg/webhook/validate_test.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,177 @@ func TestValidatePolicyForNodeStateWithValidNetFilter(t *testing.T) {
11901190
g.Expect(interfaceSelected).To(Equal(true))
11911191
}
11921192

1193+
func TestStaticValidateSriovNetworkNodePolicyWithNetFilterAndOtherNicSelectors(t *testing.T) {
1194+
testCases := []struct {
1195+
name string
1196+
nicSelector SriovNetworkNicSelector
1197+
expectError string
1198+
}{
1199+
{
1200+
name: "netFilter with vendor",
1201+
nicSelector: SriovNetworkNicSelector{
1202+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1203+
Vendor: "8086",
1204+
},
1205+
expectError: "nicSelector fields vendor, deviceID, pfNames, and rootDevices are not allowed when netFilter is specified",
1206+
},
1207+
{
1208+
name: "netFilter with deviceID",
1209+
nicSelector: SriovNetworkNicSelector{
1210+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1211+
DeviceID: "158b",
1212+
},
1213+
expectError: "nicSelector fields vendor, deviceID, pfNames, and rootDevices are not allowed when netFilter is specified",
1214+
},
1215+
{
1216+
name: "netFilter with pfNames",
1217+
nicSelector: SriovNetworkNicSelector{
1218+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1219+
PfNames: []string{"ens803f0"},
1220+
},
1221+
expectError: "nicSelector fields vendor, deviceID, pfNames, and rootDevices are not allowed when netFilter is specified",
1222+
},
1223+
{
1224+
name: "netFilter with rootDevices",
1225+
nicSelector: SriovNetworkNicSelector{
1226+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1227+
RootDevices: []string{"0000:86:00.0"},
1228+
},
1229+
expectError: "nicSelector fields vendor, deviceID, pfNames, and rootDevices are not allowed when netFilter is specified",
1230+
},
1231+
}
1232+
1233+
for _, tc := range testCases {
1234+
t.Run(tc.name, func(t *testing.T) {
1235+
g := NewGomegaWithT(t)
1236+
policy := &SriovNetworkNodePolicy{
1237+
Spec: SriovNetworkNodePolicySpec{
1238+
DeviceType: "netdevice",
1239+
NicSelector: tc.nicSelector,
1240+
NumVfs: 1,
1241+
ResourceName: "p0",
1242+
},
1243+
}
1244+
ok, err := staticValidateSriovNetworkNodePolicy(policy)
1245+
g.Expect(err).To(MatchError(ContainSubstring(tc.expectError)))
1246+
g.Expect(ok).To(Equal(false))
1247+
})
1248+
}
1249+
}
1250+
1251+
func TestStaticValidateSriovNetworkNodePolicyWithNetFilterAndEswitchMode(t *testing.T) {
1252+
g := NewGomegaWithT(t)
1253+
policy := &SriovNetworkNodePolicy{
1254+
Spec: SriovNetworkNodePolicySpec{
1255+
DeviceType: "netdevice",
1256+
NicSelector: SriovNetworkNicSelector{
1257+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1258+
},
1259+
EswitchMode: "switchdev",
1260+
NumVfs: 1,
1261+
ResourceName: "p0",
1262+
},
1263+
}
1264+
ok, err := staticValidateSriovNetworkNodePolicy(policy)
1265+
g.Expect(err).To(MatchError(ContainSubstring("eSwitchMode is not supported when netFilter is specified")))
1266+
g.Expect(ok).To(Equal(false))
1267+
}
1268+
1269+
func TestStaticValidateSriovNetworkNodePolicyWithNetFilterAndBridge(t *testing.T) {
1270+
g := NewGomegaWithT(t)
1271+
policy := &SriovNetworkNodePolicy{
1272+
Spec: SriovNetworkNodePolicySpec{
1273+
DeviceType: "netdevice",
1274+
NicSelector: SriovNetworkNicSelector{
1275+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1276+
},
1277+
Bridge: Bridge{OVS: &OVSConfig{}},
1278+
NumVfs: 1,
1279+
ResourceName: "p0",
1280+
},
1281+
}
1282+
ok, err := staticValidateSriovNetworkNodePolicy(policy)
1283+
g.Expect(err).To(MatchError(ContainSubstring("bridge configuration is not supported when netFilter is specified")))
1284+
g.Expect(ok).To(Equal(false))
1285+
}
1286+
1287+
func TestStaticValidateSriovNetworkNodePolicyWithNetFilterAndInvalidLinkType(t *testing.T) {
1288+
testCases := []struct {
1289+
name string
1290+
linkType string
1291+
expectError bool
1292+
}{
1293+
{
1294+
name: "netFilter with linkType ib",
1295+
linkType: "ib",
1296+
expectError: true,
1297+
},
1298+
{
1299+
name: "netFilter with linkType IB",
1300+
linkType: "IB",
1301+
expectError: true,
1302+
},
1303+
{
1304+
name: "netFilter with linkType eth",
1305+
linkType: "eth",
1306+
expectError: false,
1307+
},
1308+
{
1309+
name: "netFilter with linkType ETH",
1310+
linkType: "ETH",
1311+
expectError: false,
1312+
},
1313+
{
1314+
name: "netFilter with empty linkType",
1315+
linkType: "",
1316+
expectError: false,
1317+
},
1318+
}
1319+
1320+
for _, tc := range testCases {
1321+
t.Run(tc.name, func(t *testing.T) {
1322+
g := NewGomegaWithT(t)
1323+
policy := &SriovNetworkNodePolicy{
1324+
Spec: SriovNetworkNodePolicySpec{
1325+
DeviceType: "netdevice",
1326+
NicSelector: SriovNetworkNicSelector{
1327+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1328+
},
1329+
LinkType: tc.linkType,
1330+
NumVfs: 1,
1331+
ResourceName: "p0",
1332+
},
1333+
}
1334+
ok, err := staticValidateSriovNetworkNodePolicy(policy)
1335+
if tc.expectError {
1336+
g.Expect(err).To(MatchError(ContainSubstring("linkType")))
1337+
g.Expect(err).To(MatchError(ContainSubstring("is not allowed when netFilter is specified")))
1338+
g.Expect(ok).To(Equal(false))
1339+
} else {
1340+
g.Expect(err).NotTo(HaveOccurred())
1341+
g.Expect(ok).To(Equal(true))
1342+
}
1343+
})
1344+
}
1345+
}
1346+
1347+
func TestStaticValidateSriovNetworkNodePolicyWithNetFilterOnly(t *testing.T) {
1348+
g := NewGomegaWithT(t)
1349+
policy := &SriovNetworkNodePolicy{
1350+
Spec: SriovNetworkNodePolicySpec{
1351+
DeviceType: "netdevice",
1352+
NicSelector: SriovNetworkNicSelector{
1353+
NetFilter: "openstack/NetworkID:ada9ec67-2c97-467c-b674-c47200e2f5da",
1354+
},
1355+
NumVfs: 1,
1356+
ResourceName: "p0",
1357+
},
1358+
}
1359+
ok, err := staticValidateSriovNetworkNodePolicy(policy)
1360+
g.Expect(err).NotTo(HaveOccurred())
1361+
g.Expect(ok).To(Equal(true))
1362+
}
1363+
11931364
func TestValidatePolicyForNodeStateWithValidVFAndNetFilter(t *testing.T) {
11941365
interfaceSelected = false
11951366
state := &SriovNetworkNodeState{

0 commit comments

Comments
 (0)