Skip to content

Commit 16199a8

Browse files
committed
sdn: handle offset>0 fragments when validating service traffic
By default (set-frag normal) all fragments of a fragmented packet have a port number of 0. This is quite unhelpful; to get the right port number for all fragments requires un-fragmenting the packet with OVS's contrack capability, but this interacts badly with iptables' contrack capability. Instead, use the 'nx-match' mode which keeps the port numbers in the first fragment of a fragmented packet, and add rules to allow subsequent fragments (with port=0) to pass through. Assume that the destination IP stack will reject offset>0 fragments that arrive without a corresponding offset=0 first fragment. We can't just drop the port checking because services can be manually created with a static service IP address, and perhaps users rely on creating two distinct services with the same service IP address, but differentiated via port numbers. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1419692
1 parent 1a03d2f commit 16199a8

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

pkg/sdn/plugin/controller.go

+40-15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
utildbus "k8s.io/kubernetes/pkg/util/dbus"
2020
kexec "k8s.io/kubernetes/pkg/util/exec"
2121
"k8s.io/kubernetes/pkg/util/iptables"
22+
"k8s.io/kubernetes/pkg/util/sets"
2223
"k8s.io/kubernetes/pkg/util/sysctl"
2324
utilwait "k8s.io/kubernetes/pkg/util/wait"
2425
)
@@ -225,6 +226,10 @@ func (plugin *OsdnNode) SetupSDN() (bool, error) {
225226
if err != nil {
226227
return false, err
227228
}
229+
err = plugin.ovs.SetFrags("nx-match")
230+
if err != nil {
231+
return false, err
232+
}
228233
_ = plugin.ovs.DeletePort(VXLAN)
229234
_, err = plugin.ovs.AddPort(VXLAN, 1, "type=vxlan", `options:remote_ip="flow"`, `options:key="flow"`)
230235
if err != nil {
@@ -456,36 +461,56 @@ func (plugin *OsdnNode) DeleteHostSubnetRules(subnet *osapi.HostSubnet) {
456461
func (plugin *OsdnNode) AddServiceRules(service *kapi.Service, netID uint32) {
457462
glog.V(5).Infof("AddServiceRules for %v", service)
458463

464+
// Use a set to de-duplicate frag rules
465+
fragRules := sets.NewString()
466+
459467
otx := plugin.ovs.NewTransaction()
460468
for _, port := range service.Spec.Ports {
461-
otx.AddFlow(generateAddServiceRule(netID, service.Spec.ClusterIP, port.Protocol, int(port.Port)))
462-
if err := otx.EndTransaction(); err != nil {
463-
glog.Errorf("Error adding OVS flows for service %v, netid %d: %v", service, netID, err)
464-
}
469+
portRule, fragRule := generateAddServiceRules(netID, service.Spec.ClusterIP, port.Protocol, int(port.Port))
470+
fragRules.Insert(fragRule)
471+
otx.AddFlow(portRule)
472+
}
473+
for _, rule := range fragRules.List() {
474+
otx.AddFlow(rule)
475+
}
476+
if err := otx.EndTransaction(); err != nil {
477+
glog.Errorf("Error adding OVS flows for service %v, netid %d: %v", service, netID, err)
465478
}
466479
}
467480

468481
func (plugin *OsdnNode) DeleteServiceRules(service *kapi.Service) {
469482
glog.V(5).Infof("DeleteServiceRules for %v", service)
470483

484+
// Use a set to de-duplicate frag rules
485+
fragRules := sets.NewString()
486+
471487
otx := plugin.ovs.NewTransaction()
472488
for _, port := range service.Spec.Ports {
473-
otx.DeleteFlows(generateDeleteServiceRule(service.Spec.ClusterIP, port.Protocol, int(port.Port)))
474-
if err := otx.EndTransaction(); err != nil {
475-
glog.Errorf("Error deleting OVS flows for service %v: %v", service, err)
476-
}
489+
portRule, fragRule := generateDeleteServiceRule(service.Spec.ClusterIP, port.Protocol, int(port.Port))
490+
fragRules.Insert(fragRule)
491+
otx.DeleteFlows(portRule)
492+
}
493+
for _, rule := range fragRules.List() {
494+
otx.DeleteFlows(rule)
495+
}
496+
if err := otx.EndTransaction(); err != nil {
497+
glog.Errorf("Error deleting OVS flows for service %v: %v", service, err)
477498
}
478499
}
479500

480-
func generateBaseServiceRule(IP string, protocol kapi.Protocol, port int) string {
481-
return fmt.Sprintf("table=60, %s, nw_dst=%s, tp_dst=%d", strings.ToLower(string(protocol)), IP, port)
501+
func generateBaseServiceRules(IP string, protocol kapi.Protocol, port int) (string, string) {
502+
baseMatch := fmt.Sprintf("table=60, %s, nw_dst=%s", strings.ToLower(string(protocol)), IP)
503+
portRule := baseMatch + fmt.Sprintf(", tp_dst=%d", port)
504+
fragRule := baseMatch + ", ip_frag=later"
505+
return portRule, fragRule
482506
}
483507

484-
func generateAddServiceRule(netID uint32, IP string, protocol kapi.Protocol, port int) string {
485-
baseRule := generateBaseServiceRule(IP, protocol, port)
486-
return fmt.Sprintf("%s, priority=100, actions=load:%d->NXM_NX_REG1[], load:2->NXM_NX_REG2[], goto_table:80", baseRule, netID)
508+
func generateAddServiceRules(netID uint32, IP string, protocol kapi.Protocol, port int) (string, string) {
509+
portRule, fragRule := generateBaseServiceRules(IP, protocol, port)
510+
actions := fmt.Sprintf(", priority=100, actions=load:%d->NXM_NX_REG1[], load:2->NXM_NX_REG2[], goto_table:80", netID)
511+
return portRule + actions, fragRule + actions
487512
}
488513

489-
func generateDeleteServiceRule(IP string, protocol kapi.Protocol, port int) string {
490-
return generateBaseServiceRule(IP, protocol, port)
514+
func generateDeleteServiceRule(IP string, protocol kapi.Protocol, port int) (string, string) {
515+
return generateBaseServiceRules(IP, protocol, port)
491516
}

pkg/util/ovs/ovs.go

+5
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ func (ovsif *Interface) DeletePort(port string) error {
144144
return err
145145
}
146146

147+
func (ovsif *Interface) SetFrags(mode string) error {
148+
_, err := ovsif.exec(OVS_OFCTL, "set-frags", ovsif.bridge, mode)
149+
return err
150+
}
151+
147152
type Transaction struct {
148153
ovsif *Interface
149154
err error

0 commit comments

Comments
 (0)