Skip to content

Commit 4be6b05

Browse files
committed
support pinning subinterfaces
The BPF fs does not allow dots (".") in filenames [1], which prevents subinterfaces to be pinned correctly. By translating these dots before writing to bpffs this allows pinning subinterfaces (e.g. vlans). [1] https://github.com/torvalds/linux/blob/6146a0f1dfae5d37442a9ddcba012add260bceb0/kernel/bpf/inode.c#L371-L381
1 parent 96727eb commit 4be6b05

File tree

5 files changed

+78
-1
lines changed

5 files changed

+78
-1
lines changed

pkg/ebpf/ingress_node_firewall_loader.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ func (infc *IngNodeFwController) IngressNodeFwAttach(ifacesName ...string) error
319319
}
320320
}
321321
// Pin the XDP program.
322-
lPinDir := path.Join(infc.pinPath, ifaceName+linkSuffix)
322+
lPinDir := sanitizePinDir(path.Join(infc.pinPath, ifaceName+linkSuffix))
323323
if err := l.Pin(lPinDir); err != nil {
324324
errors = append(errors, fmt.Errorf("failed to pin link to pinDir %s: %s", lPinDir, err))
325325
continue
@@ -477,6 +477,7 @@ func (infc *IngNodeFwController) loadPinnedLinks() error {
477477
for _, file := range files {
478478
if re.Match([]byte(file.Name())) {
479479
interfaceName := strings.TrimSuffix(file.Name(), linkSuffix)
480+
interfaceName = sanitizePinDir(interfaceName)
480481
if _, ok := infc.links[interfaceName]; !ok {
481482
l, err := link.LoadPinnedLink(path.Join(infc.pinPath, file.Name()), nil)
482483
if err != nil {
@@ -729,3 +730,14 @@ func (infc *IngNodeFwController) purgeKeys(keys []BpfLpmIpKeySt) error {
729730
}
730731
return nil
731732
}
733+
734+
// bpffs does not allow dots in filenames: https://github.com/torvalds/linux/blob/6146a0f1dfae5d37442a9ddcba012add260bceb0/kernel/bpf/inode.c#L371-L381
735+
// sanitizePinDir converts dots with a placeholder and vice-versa to support subinterface
736+
func sanitizePinDir(filename string) string {
737+
738+
if strings.Contains(filename, ".") {
739+
return strings.ReplaceAll(filename, ".", PinDirDotPlaceholder)
740+
}
741+
742+
return strings.ReplaceAll(filename, PinDirDotPlaceholder, ".")
743+
}

pkg/ebpf/ingress_node_firewall_loader_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,31 @@ func cleanup(t *testing.T) {
128128
t.Log(err)
129129
}
130130
}
131+
132+
func TestSanitizePinDir(t *testing.T) {
133+
tests := []struct {
134+
in string
135+
expected string
136+
}{
137+
{
138+
in: "eth0",
139+
expected: "eth0",
140+
},
141+
{
142+
in: "bond0.100",
143+
expected: "bond0_dot_100",
144+
},
145+
{
146+
in: "eth0_dot_100",
147+
expected: "eth0.100",
148+
},
149+
}
150+
151+
for _, tc := range tests {
152+
result := sanitizePinDir(tc.in)
153+
if result != tc.expected {
154+
t.Fatalf("Failed to sanitize, expected %s, got %s",
155+
tc.expected, result)
156+
}
157+
}
158+
}

pkg/ebpf/types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
*/
14+
15+
package nodefwloader
16+
17+
const (
18+
PinDirDotPlaceholder = "_dot_"
19+
)

pkg/webhook/webhook.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99

1010
ingressnodefwv1alpha1 "github.com/openshift/ingress-node-firewall/api/v1alpha1"
11+
nodefwloader "github.com/openshift/ingress-node-firewall/pkg/ebpf"
1112
"github.com/openshift/ingress-node-firewall/pkg/failsaferules"
1213
"github.com/openshift/ingress-node-firewall/pkg/utils"
1314

@@ -104,6 +105,11 @@ func validateINFInterfaces(ctx context.Context, infInterfaces []string, infName
104105
field.Invalid(field.NewPath("Spec").Child("interfaces").Index(index),
105106
infName, fmt.Sprintf("interface %q can't start with a number", inf)))
106107
}
108+
if strings.Contains(inf, nodefwloader.PinDirDotPlaceholder) {
109+
allErrs = append(allErrs,
110+
field.Invalid(field.NewPath("Spec").Child("interfaces").Index(index),
111+
infName, fmt.Sprintf("interface %q can't contain '%s'", inf, nodefwloader.PinDirDotPlaceholder)))
112+
}
107113
}
108114
return allErrs
109115
}

pkg/webhook/webhook_suite_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
. "github.com/onsi/ginkgo"
3333
. "github.com/onsi/gomega"
3434
admissionv1beta1 "k8s.io/api/admission/v1beta1"
35+
3536
//+kubebuilder:scaffold:imports
3637
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3738
"k8s.io/apimachinery/pkg/runtime"
@@ -179,6 +180,17 @@ var _ = Describe("Interfaces", func() {
179180
configInterfaces(inf, []string{"0th"})
180181
Expect(createIngressNodeFirewall(inf)).ToNot(Succeed())
181182
})
183+
It("interfaces config with interface name containing dot", func() {
184+
initCIDRICMPRule(inf, ipv4CIDR, validOrder, false, icmpTypeEchoReply, icmpTypeEchoReply, ingressnodefwv1alpha1.IngressNodeFirewallAllow)
185+
configInterfaces(inf, []string{"eth0.100"})
186+
Expect(createIngressNodeFirewall(inf)).To(Succeed())
187+
Expect(deleteIngressNodeFirewall(inf)).To(Succeed())
188+
})
189+
It("interfaces config with interface name containing dot placeholder", func() {
190+
initCIDRICMPRule(inf, ipv4CIDR, validOrder, false, icmpTypeEchoReply, icmpTypeEchoReply, ingressnodefwv1alpha1.IngressNodeFirewallAllow)
191+
configInterfaces(inf, []string{"eth0_dot_100"})
192+
Expect(createIngressNodeFirewall(inf)).ToNot(Succeed())
193+
})
182194
})
183195
})
184196

0 commit comments

Comments
 (0)