Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grab the iptables lock before running iptables-restore. #1491

Merged
merged 1 commit into from
Jul 14, 2017

Conversation

fasaxc
Copy link
Member

@fasaxc fasaxc commented Jun 27, 2017

Description

To avoid conflicts with kube-proxy (and others), take the iptables lock before running iptables-restore.

See #1470

Todos

  • Unit tests (full coverage)
  • Integration tests (delete as appropriate) Done
  • Double check license requirements

Release Note

Felix now acquires the iptables lock while manipulating iptables.  This prevents conflicts 
with other applications, such as kube-proxy (as long as they also honor the lock).  
Upgrade note: to be effective if Felix is running in a container, this feature requires the 
directory containing the iptables lock file, `/run`, to be mounted into the container.  

@fasaxc
Copy link
Member Author

fasaxc commented Jul 11, 2017

retest this please

Copy link
Member

@nelljerram nelljerram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few nits.

err = p.parseFailed(raw, "invalid float")
return
}
result = time.Duration(millis * float64(time.Millisecond))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this cast needed? I'm curious to understand, if so.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is. I want to allow the input to be a float, so you could say 1.2 (milliseconds). Go's casting rules are very strict so you can't do float * duration (which is really an int64 number of nanoseconds) without a cast. Then I need to cast back to time.Duration at the end.

Casting millis to time.Duration first then multiplying doesn't work because that would lose precision.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense - thanks.

forceDataplaneRefresh bool
cleanupPending bool
doneFirstApply bool
// dataplaneNeedsSync is set if the dataplane is dirty in some way, I.e. we need to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lowercase "i.e."?

iptablesNATOptions.ExtraCleanupRegexPattern = rules.HistoricInsertedNATRuleRegex

// Create the shared iptables lock. This allows us to block other processes from
// manipulating iptables but it still allows us to do our work in parallel.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the "... in parallel" clause means here.

iptables/lock.go Outdated
})
countLockTimeouts = prometheus.NewCounter(prometheus.CounterOpts{
Name: "felix_iptables_lock_timeouts",
Help: "Number of lock timeouts while waiting for hte iptables lock(s).",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"hte"

iptables/lock.go Outdated
return nil, Err14LockTimeout
}
time.Sleep(probeInterval)
countLockRetries.Inc()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like it would be useful for the 14 and 16 metrics to be distinct - perhaps with labels. In a failing system, it's probably going to be one of them in particular that is problematic.

err = p.parseFailed(raw, "invalid float")
return
}
result = time.Duration(millis * float64(time.Millisecond))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this cast needed? I'm curious to understand, if so.

iptablesNATOptions.ExtraCleanupRegexPattern = rules.HistoricInsertedNATRuleRegex

// Create the shared iptables lock. This allows us to block other processes from
// manipulating iptables but it still allows us to do our work in parallel.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't understand the last clause on first reading this. Perhaps "but it still allows our own goroutines to modify iptables in parallel - which is OK because they are operating on different tables"?

Copy link
Member

@nelljerram nelljerram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of queries about the new testing.

Makefile Outdated
@@ -324,6 +330,16 @@ ut combined.coverprofile: vendor/.up-to-date $(FELIX_GO_FILES)
@echo Running Go UTs.
$(DOCKER_GO_BUILD) ./utils/run-coverage

bin/fv.test: vendor/.up-to-date $(FELIX_GO_FILES)
$(DOCKER_GO_BUILD) go test ./fv -c --tags fvtests -o bin/fv.test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I added the k8sfv directory, I needed to exclude it from some of the infrastructure for running UTs:

./utils/run-coverage:11:	      grep -vE '/vendor/|\./proto/|.glide|/k8sfv/' | \
./utils/run-coverage:24:ginkgo -cover -covermode=count -coverpkg=${go_dirs} -r -skipPackage k8sfv
./Makefile:352:	$(DOCKER_GO_BUILD) ginkgo -r -skipPackage k8sfv $(GINKGO_OPTIONS)
./Makefile:357:	$(DOCKER_GO_BUILD) ginkgo watch -r -skipPackage k8sfv $(GINKGO_OPTIONS)

Do you need to do that for fv as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw a neat trick in that Cloudflare article: using a build tag to identify which tests to build/run and I went for that approach. WDYT?

BeforeEach(func() {
containerName = fmt.Sprintf("felix-fv-%d-%d", os.Getpid(), containerIdx)
containerIdx++
felixDir, err := os.Getwd()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these tests need felixDir to be correct? I would expect Getwd() here to give <reporoot>/fv, not <reporoot> - and I'm not sure that is what you intend with the name felixDir.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it works from the makefile due to the way we run it. Maybe I should be tolerant to that though, so that ginkgo watch does the right thing.

- Copy and adapt kube-proxy's iptables lock implementation.
- Implement a shared iptables lock that allows for writes to
  different tables (which are orthogonal).
- Add a test executable that grabs the lock for a specified
  length of time along with FV tests that test correct blocking
  of iptables -w.

These are the Felix changes required for #1470.
@fasaxc fasaxc merged commit ebfc5f5 into projectcalico:master Jul 14, 2017
@fasaxc fasaxc deleted the iptables-lock branch July 14, 2017 17:09
@caseydavenport
Copy link
Member

caseydavenport commented Jul 25, 2017

@fasaxc I think we've got duplicated release note information coming from this PR and projectcalico/calico#935. Can we remove the label from this one? (Or maybe we just leave it and say that's OK?)

@fasaxc
Copy link
Member Author

fasaxc commented Jul 25, 2017

Sure.

song-jiang pushed a commit to song-jiang/felix that referenced this pull request Aug 30, 2017
Grab the iptables lock before running iptables-restore.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants