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

netpol: Add dual-stack support #1280

Closed

Conversation

vadorovsky
Copy link
Contributor

This change allows to define two cluster CIDRs for compatibility with
Kubernetes dual-stack, with an assumption that two CIDRs are usually
IPv4 and IPv6.

Signed-off-by: Michal Rostecki [email protected]

@@ -56,6 +56,8 @@ Usage of kube-router:
--disable-source-dest-check Disable the source-dest-check attribute for AWS EC2 instances. When this option is false, it must be set some other way. (default true)
--enable-cni Enable CNI plugin. Disable if you want to use kube-router features alongside another CNI plugin. (default true)
--enable-ibgp Enables peering with nodes with the same ASN, if disabled will only peer with external BGP peers (default true)
--enable-ipv4 Enables IPv4 support (default true)
--enable-ipv6 Enables IPv6 support (default true)
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we enable this by default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can disable it by default, if you want.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm just wondering on implications to existing systems that don't use ipv6 currently. Maybe introduce as disabled and enable later?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright, changed to false

Copy link
Collaborator

Choose a reason for hiding this comment

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

@vadorovsky it looks like this is still set to enabled by default. Given that it's going to fail to initialize the NPC if IPv6 is enabled and there is not an IPv6 address on the node in the Kubernetes API, I think that enabling IPv6 is too risky as a default.

@aauren
Copy link
Collaborator

aauren commented Apr 7, 2022

@vadorovsky Thanks for submitting, will try to look at it tomorrow.

@aauren
Copy link
Collaborator

aauren commented Apr 11, 2022

@vadorovsky apologies for not getting to this on Friday like I wanted to!

This is a big PR and so I want to give it the time it deserves to review and test. Had a bunch of work stuff come up last week that is continuing into this week, but I wanted to let you know this is still on my radar and still very much something that I want to get into this week.

This change allows to define two cluster CIDRs for compatibility with
Kubernetes dual-stack, with an assumption that two CIDRs are usually
IPv4 and IPv6.

Signed-off-by: Michal Rostecki <[email protected]>
@vadorovsky vadorovsky marked this pull request as ready for review April 19, 2022 11:34
Copy link
Collaborator

@aauren aauren left a comment

Choose a reason for hiding this comment

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

@vadorovsky Again, sorry that it took so long to finish this review. I had to take it in parts because this change is so large.

First off, thanks very much for being willing to work on such a sizable change. Just reviewing your refactor here made my head hurt a bit, so I can imagine it was difficult to put all this together from scratch and keep all the pieces straight.

I think that almost all of my comments are minor things, so try not to get disappointed by the ~30 changes I'm requesting here. On the whole this seems very well done.

So far this review only covers the code changes, I haven't gotten a chance to run this. I intend to do so over the next couple of days and put it through its paces, but in the meantime I wanted to get you feedback as soon as possible.

A request, when you work on updates, please don't squash or amend them to the existing commit, please leave them as a separate commit so that I can compare the original work against the requested changes. It will really help the final approval go much faster.

Again, thanks for your work!

@@ -184,8 +188,39 @@ func (kr *KubeRouter) Run() error {
}

if kr.Config.RunFirewall {
iptablesCmdHandlers := make(map[v1core.IPFamily]utils.IPTablesHandler, 2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It doesn't seem like there a particular need to move iptables and ipset logic up here into the command handler. If not, it would be better to sink this down into the NPC, into the NewNetworkPolicyController() initializer.

)

var hasWait bool

// Interface based on the IPTables struct from github.com/coreos/go-iptables
// which allows to mock it.
type IPTablesHandler interface {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Its a pity that the upstream package doesn't provide this interface for us. 😞 Thanks for creating it.

buffer.WriteString(ruleStr)
}

type IPTablesSaveRestore struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you see any reason not to make this an interface as well? It would essentially just expose the SaveInto and Restore functions, that way we could mock it other places in the NPC as well if needed?

func GetNodeIPDualStack(node *apiv1.Node, enableIPv4, enableIPv6 bool) (net.IP, net.IP, error) {
var ipAddrv4, ipAddrv6 net.IP
addresses := node.Status.Addresses
addressesPerType := make(addressMap)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems like this would be a good opportunity to refactor GetNodeIP() as well, and consolidate it to use this same logic.

Perhaps the add() method above could be changed into more of a GetNodeAddressesByType() method, and then it could do the iteration over addresses and just return the entire map to both GetNodeIP and GetNodeIPDualStack?

if _, ok := m[address.Type]; ok {
m[address.Type] = append(m[address.Type], address)
} else {
// There can be at most 2 addresses of the same type.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain what you mean by this comment and the 2 sizing? Is this something that the Kubernetes API guarantees?

for _, obj := range npc.podLister.List() {
pod := obj.(*api.Pod)
// ignore the pods running on the different node and pods that are not actionable
if strings.Compare(pod.Status.HostIP, nodeIP) != 0 || !isNetPolActionable(pod) {
continue
}
localPods[pod.Status.PodIP] = podInfo{ip: pod.Status.PodIP,
localPods[pod.Status.PodIP] = podInfo{ips: pod.Status.PodIPs,
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comment above, but it might be beneficial to load both the ip as well as ips for the pod object here.

@@ -8,6 +8,8 @@ import (

"github.com/cloudnativelabs/kube-router/pkg/utils"
api "k8s.io/api/core/v1"
"k8s.io/klog/v2"
utilsnet "k8s.io/utils/net"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can fix the imports to consistently use either netutils or utilsnet across all the imports? It makes it a little easier to understand.

activePolicyChains := make(map[string]bool)
activePolicyIPSets := make(map[string]bool)

// for ipFamily, ipset := range npc.ipSetHandlers {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can probably be removed.

for _, podIP := range currentPodIPs[ipFamily] {
setEntries = append(setEntries, []string{podIP, utils.OptionTimeout, "0"})
}
ipset.RefreshSet(targetDestPodIPSetName, setEntries, utils.TypeHashIP)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a reason not to use createGenericHashIPSet() here rather than building the entries yourself? It already accepts ipFamily as a parameter, so you would just pass that and it would end up in the correct set.

for _, podIP := range currentPodIPs[ipFamily] {
setEntries = append(setEntries, []string{podIP, utils.OptionTimeout, "0"})
}
ipset.RefreshSet(targetSourcePodIPSetName, setEntries, utils.TypeHashIP)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here on using createGenericHashIPSet()

@aauren
Copy link
Collaborator

aauren commented Aug 6, 2022

Closed in favor of #1343

@aauren aauren closed this Aug 6, 2022
@aauren aauren mentioned this pull request Oct 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants