Skip to content

Commit 2dfef0f

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 2dfef0f

File tree

2 files changed

+33
-9
lines changed

2 files changed

+33
-9
lines changed

pkg/sdn/plugin/controller.go

+28-9
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ func (plugin *OsdnNode) SetupSDN() (bool, error) {
225225
if err != nil {
226226
return false, err
227227
}
228+
err = plugin.ovs.SetFrags("nx-match")
229+
if err != nil {
230+
return false, err
231+
}
228232
_ = plugin.ovs.DeletePort(VXLAN)
229233
_, err = plugin.ovs.AddPort(VXLAN, 1, "type=vxlan", `options:remote_ip="flow"`, `options:key="flow"`)
230234
if err != nil {
@@ -457,8 +461,17 @@ func (plugin *OsdnNode) AddServiceRules(service *kapi.Service, netID uint32) {
457461
glog.V(5).Infof("AddServiceRules for %v", service)
458462

459463
otx := plugin.ovs.NewTransaction()
464+
action := getServiceRuleAction(netID)
465+
466+
// Add blanket rule allowing subsequent IP fragments
467+
if netID != osapi.GlobalVNID {
468+
baseFragRule := generateBaseServiceFragRule(service.Spec.ClusterIP)
469+
otx.AddFlow(baseFragRule + action)
470+
}
471+
460472
for _, port := range service.Spec.Ports {
461-
otx.AddFlow(generateAddServiceRule(netID, service.Spec.ClusterIP, port.Protocol, int(port.Port)))
473+
baseRule := generateBaseServiceRule(service.Spec.ClusterIP, port.Protocol, int(port.Port))
474+
otx.AddFlow(baseRule + action)
462475
if err := otx.EndTransaction(); err != nil {
463476
glog.Errorf("Error adding OVS flows for service %v, netid %d: %v", service, netID, err)
464477
}
@@ -468,24 +481,30 @@ func (plugin *OsdnNode) AddServiceRules(service *kapi.Service, netID uint32) {
468481
func (plugin *OsdnNode) DeleteServiceRules(service *kapi.Service) {
469482
glog.V(5).Infof("DeleteServiceRules for %v", service)
470483

484+
// Remove blanket rule allowing subsequent IP fragments; since we don't
485+
// have the service VNID here we have to ignore errors since this will
486+
// fail when removing services in the admin VNID
471487
otx := plugin.ovs.NewTransaction()
488+
otx.DeleteFlows(generateBaseServiceFragRule(service.Spec.ClusterIP))
489+
otx.EndTransaction()
490+
491+
otx = plugin.ovs.NewTransaction()
472492
for _, port := range service.Spec.Ports {
473-
otx.DeleteFlows(generateDeleteServiceRule(service.Spec.ClusterIP, port.Protocol, int(port.Port)))
493+
otx.DeleteFlows(generateBaseServiceRule(service.Spec.ClusterIP, port.Protocol, int(port.Port)))
474494
if err := otx.EndTransaction(); err != nil {
475495
glog.Errorf("Error deleting OVS flows for service %v: %v", service, err)
476496
}
477497
}
478498
}
479499

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)
500+
func generateBaseServiceFragRule(IP string) string {
501+
return fmt.Sprintf("table=60, ip, nw_dst=%s, ip_frag=later", IP)
482502
}
483503

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)
504+
func generateBaseServiceRule(IP string, protocol kapi.Protocol, port int) string {
505+
return fmt.Sprintf("table=60, %s, nw_dst=%s, tp_dst=%d", strings.ToLower(string(protocol)), IP, port)
487506
}
488507

489-
func generateDeleteServiceRule(IP string, protocol kapi.Protocol, port int) string {
490-
return generateBaseServiceRule(IP, protocol, port)
508+
func getServiceRuleAction(netID uint32) string {
509+
return fmt.Sprintf(", priority=100, actions=load:%d->NXM_NX_REG1[], load:2->NXM_NX_REG2[], goto_table:80", netID)
491510
}

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)