Skip to content

Commit f4ddc1e

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 f4ddc1e

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed

pkg/sdn/plugin/controller.go

+29-17
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,9 +461,18 @@ 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 := fmt.Sprintf(", priority=100, actions=load:%d->NXM_NX_REG1[], load:2->NXM_NX_REG2[], goto_table:80", netID)
465+
466+
// Add blanket rule allowing subsequent IP fragments
467+
otx.AddFlow(generateBaseServiceRule(service.Spec.ClusterIP) + ", ip_frag=later" + action)
468+
460469
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 {
470+
baseRule, err := generateBaseAddServiceRule(service.Spec.ClusterIP, port.Protocol, int(port.Port))
471+
if err == nil {
472+
otx.AddFlow(baseRule + action)
473+
err = otx.EndTransaction()
474+
}
475+
if err != nil {
463476
glog.Errorf("Error adding OVS flows for service %v, netid %d: %v", service, netID, err)
464477
}
465478
}
@@ -469,23 +482,22 @@ func (plugin *OsdnNode) DeleteServiceRules(service *kapi.Service) {
469482
glog.V(5).Infof("DeleteServiceRules for %v", service)
470483

471484
otx := plugin.ovs.NewTransaction()
472-
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-
}
477-
}
485+
otx.DeleteFlows(generateBaseServiceRule(service.Spec.ClusterIP))
486+
otx.EndTransaction()
478487
}
479488

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)
489+
func generateBaseServiceRule(IP string) string {
490+
return fmt.Sprintf("table=60, ip, nw_dst=%s", IP)
482491
}
483492

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)
487-
}
488-
489-
func generateDeleteServiceRule(IP string, protocol kapi.Protocol, port int) string {
490-
return generateBaseServiceRule(IP, protocol, port)
493+
func generateBaseAddServiceRule(IP string, protocol kapi.Protocol, port int) (string, error) {
494+
var dst string
495+
if protocol == kapi.ProtocolUDP {
496+
dst = fmt.Sprintf(", udp, udp_dst=%d", port)
497+
} else if protocol == kapi.ProtocolTCP {
498+
dst = fmt.Sprintf(", tcp, tcp_dst=%d", port)
499+
} else {
500+
return "", fmt.Errorf("unhandled protocol %v", protocol)
501+
}
502+
return generateBaseServiceRule(IP) + dst, nil
491503
}

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)