Skip to content

Commit

Permalink
Merge branch 'eip-net-seg' into merge-ds-net-seg
Browse files Browse the repository at this point in the history
  • Loading branch information
martinkennelly committed Nov 20, 2024
2 parents 99c44e8 + 694381b commit a678c4f
Show file tree
Hide file tree
Showing 146 changed files with 17,051 additions and 3,207 deletions.
6 changes: 3 additions & 3 deletions contrib/kind-common
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,11 @@ install_kubevirt() {
done
fi

kubectl -n kubevirt patch kubevirt kubevirt --type=json --patch '[{"op":"add","path":"/spec/configuration/developerConfiguration","value":{"featureGates":[]}},{"op":"add","path":"/spec/configuration/developerConfiguration/featureGates/-","value":"NetworkBindingPlugins"}]'
kubectl -n kubevirt patch kubevirt kubevirt --type=json --patch '[{"op":"add","path":"/spec/configuration/developerConfiguration","value":{"featureGates":[]}},{"op":"add","path":"/spec/configuration/developerConfiguration/featureGates/-","value":"NetworkBindingPlugins"},{"op":"add","path":"/spec/configuration/developerConfiguration/featureGates/-","value":"DynamicPodInterfaceNaming"}]'

local kubevirt_stable_release_url=$(get_kubevirt_release_url "stable")
local passt_binding_image="quay.io/kubevirt/network-passt-binding:${kubevirt_stable_release_url##*/}"
kubectl -n kubevirt patch kubevirt kubevirt --type=json --patch '[{"op":"add","path":"/spec/configuration/network","value":{}},{"op":"add","path":"/spec/configuration/network/binding","value":{"passt":{"computeResourceOverhead":{"requests":{"memory":"500Mi"}},"migration":{"method":"link-refresh"},"networkAttachmentDefinition":"default/primary-udn-kubevirt-binding","sidecarImage":"'"${passt_binding_image}"'"}}}]'
kubectl -n kubevirt patch kubevirt kubevirt --type=json --patch '[{"op":"add","path":"/spec/configuration/network","value":{}},{"op":"add","path":"/spec/configuration/network/binding","value":{"passt":{"computeResourceOverhead":{"requests":{"memory":"500Mi"}},"migration":{"method":"link-refresh"},"networkAttachmentDefinition":"default/primary-udn-kubevirt-binding","sidecarImage":"'"${passt_binding_image}"'"},"managedTap":{"domainAttachmentType":"managedTap","migration":{}}}}]'

if [ ! -d "./bin" ]
then
Expand Down
2 changes: 1 addition & 1 deletion dist/images/Dockerfile.fedora
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ RUN INSTALL_PKGS=" \
python3-pip python3-pyyaml bind-utils procps-ng openssl numactl-libs firewalld-filesystem \
libpcap hostname kubernetes-client util-linux \
ovn ovn-central ovn-host python3-openvswitch tcpdump openvswitch-test python3-pyOpenSSL \
iptables iproute iputils strace socat koji \
iptables nftables iproute iputils strace socat koji \
libreswan openvswitch-ipsec \
" && \
dnf install --best --refresh -y --setopt=tsflags=nodocs $INSTALL_PKGS && \
Expand Down
2 changes: 1 addition & 1 deletion dist/images/Dockerfile.fedora.dev
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ FROM fedora:39

# Install needed dependencies.
RUN INSTALL_PKGS=" \
iptables iproute iputils hostname unbound-libs kubernetes-client kmod" && \
iptables nftables iproute iputils hostname unbound-libs kubernetes-client kmod" && \
dnf install --best --refresh -y --setopt=tsflags=nodocs $INSTALL_PKGS && \
dnf clean all && rm -rf /var/cache/dnf/*

Expand Down
2 changes: 1 addition & 1 deletion dist/images/Dockerfile.ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ FROM ubuntu:24.04

USER root

RUN apt-get update && apt-get install -y iproute2 curl software-properties-common util-linux
RUN apt-get update && apt-get install -y iproute2 curl software-properties-common util-linux nftables

RUN curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -

Expand Down
28 changes: 24 additions & 4 deletions docs/features/cluster-egress-controls/egress-ip.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ For more info, consider looking at the following links:
- [Assigning an egress IP address](https://docs.okd.io/latest/networking/ovn_kubernetes_network_provider/assigning-egress-ips-ovn.html)
- [Managing Egress IP in OpenShift 4 with OVN-Kubernetes](https://rcarrata.com/openshift/egress-ip-ovn/)


## Example

An example of EgressIP might look like this:
Expand All @@ -38,11 +37,16 @@ spec:
It specifies to use `172.18.0.33` or `172.18.0.44` egressIP for pods that are labeled with `app: web` that run in a namespace without `environment: development` label.
Both selectors use the [generic kubernetes label selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors).

## Traffic flows
## Layer 3 network
Supported network configs:
- Cluster default network
- Role primary user defined networks

### EgressIP IP is assigned to the primary host interface
If the Egress IP(s) are hosted on the OVN primary network then the implementation is redirecting the POD traffic
to an egress node where it is SNATed and sent out.

Using the example EgressIP and a matching pod with `10.244.1.3` IP, the following logical router policies are configured in `ovn_cluster_router`:
Using the example EgressIP and a matching pod attached to the cluster default network with `10.244.1.3` IP, the following logical router policies are configured in `ovn_cluster_router`:
```shell
Routing Policies
1004 inport == "rtos-ovn-control-plane" && ip4.dst == 172.18.0.4 /* ovn-control-plane */ reroute 10.244.0.2
Expand All @@ -59,7 +63,7 @@ Routing Policies
- Rules with `102` priority are added by OVN-Kubernetes when EgressIP feature is enabled, they ensure that east-west traffic is not using egress IPs.
- The rule with `100` priority is added for the pod matching `egressip-prod` EgressIP, and it redirects the traffic to one of the egress nodes (ECMP is used to balance the traffic between next hops).

Once the redirected traffic reaches one of the egress nodes it gets SNATed in the gateway router:
For a pod attached to the cluster default network and once the redirected traffic reaches one of the egress nodes it gets SNATed in the gateway router:
```shell
ovn-nbctl lr-nat-list GR_ovn-worker
TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT
Expand All @@ -71,6 +75,16 @@ TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGIC
snat 172.18.0.44 10.244.1.3
```

For a pod attached to a role primary user defined network "network1", there is no NAT entry for the pod attached to the egress OVN gateway and
instead a logical router policy is attached to the egress nodes OVN gateway router:
```shell
sh-5.2# ovn-nbctl lr-policy-list GR_network1_ovn-worker
Routing Policies
95 ip4.src == 10.128.1.3 && pkt.mark == 0 allow pkt_mark=50006
```

### EgressIP IP is assigned to a secondary host interface
Note that this is unsupported for user defined networks.
Lets now imagine the Egress IP(s) mentioned previously, are not hosted by the OVN primary network and is hosted
by a secondary host network which is assigned to a standard linux interface, a redirect to the egress-able node management port IP address:
```shell
Expand Down Expand Up @@ -140,6 +154,12 @@ is created within the chain `OVN-KUBE-EGRESS-IP-Multi-NIC` for each selected pod
egress-ing a particular interface. The routing table number `1111` is generated from the interface name.
Routes within the main routing table who's output interface share the same interface used for Egress IP are also cloned into the VRF 1111.

## Layer 2 network
Not supported

## Localnet
Not supported

### Pod to node IP traffic
When a cluster networked pod matched by an egress IP tries to connect to a non-local node IP it hits the following
logical router policy in `ovn_cluster_router`:
Expand Down
5 changes: 2 additions & 3 deletions go-controller/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
github.com/mdlayher/ndp v1.0.1
github.com/miekg/dns v1.1.31
github.com/mitchellh/copystructure v1.2.0
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.33.1
github.com/openshift/api v0.0.0-20231120222239-b86761094ee3
Expand Down Expand Up @@ -60,14 +61,12 @@ require (
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
kubevirt.io/api v1.0.0-alpha.0
sigs.k8s.io/controller-runtime v0.19.0
sigs.k8s.io/knftables v0.0.18
sigs.k8s.io/network-policy-api v0.1.5
sigs.k8s.io/structured-merge-diff/v4 v4.4.1
sigs.k8s.io/yaml v1.4.0
)

// OCPHACK
require sigs.k8s.io/knftables v0.0.16

require (
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go-controller/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1411,8 +1411,8 @@ sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hw
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/knftables v0.0.16 h1:ZpTfNsjnidgoXdxxzcZLdSctqkpSO3QB3jo3zQ4PXqM=
sigs.k8s.io/knftables v0.0.16/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk=
sigs.k8s.io/knftables v0.0.18 h1:6Duvmu0s/HwGifKrtl6G3AyAPYlWiZqTgS8bkVMiyaE=
sigs.k8s.io/knftables v0.0.18/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk=
sigs.k8s.io/network-policy-api v0.1.5 h1:xyS7VAaM9EfyB428oFk7WjWaCK6B129i+ILUF4C8l6E=
sigs.k8s.io/network-policy-api v0.1.5/go.mod h1:D7Nkr43VLNd7iYryemnj8qf0N/WjBzTZDxYA+g4u1/Y=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
Expand Down
4 changes: 2 additions & 2 deletions go-controller/pkg/allocator/id/allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ type idAllocator struct {
}

// NewIDAllocator returns an IDAllocator
func NewIDAllocator(name string, maxIds int) (Allocator, error) {
func NewIDAllocator(name string, maxIds int) Allocator {
idBitmap := bitmapallocator.NewRoundRobinAllocationMap(maxIds, name)

return &idAllocator{
nameIdMap: sync.Map{},
idBitmap: idBitmap,
}, nil
}
}

// AllocateID allocates an id for the resource 'name' and returns the id.
Expand Down
21 changes: 14 additions & 7 deletions go-controller/pkg/allocator/ip/subnet/allocator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import (

ipam "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/allocator/ip"
ovntest "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/testing"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"

"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
)

var _ = ginkgo.Describe("Subnet IP allocator operations", func() {
const subnetName = "subnet1"
var (
allocator Allocator
)
Expand All @@ -21,7 +23,6 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {

ginkgo.Context("when adding subnets", func() {
ginkgo.It("creates each IPAM and reserves IPs correctly", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
"2000::/64",
Expand All @@ -40,7 +41,6 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {
})

ginkgo.It("handles updates to the subnets correctly", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
"2000::/64",
Expand Down Expand Up @@ -69,7 +69,6 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {
})

ginkgo.It("excludes subnets correctly", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
}
Expand All @@ -93,7 +92,6 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {

ginkgo.Context("when allocating IP addresses", func() {
ginkgo.It("IPAM for each subnet allocates IPs contiguously", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
"2000::/64",
Expand All @@ -116,7 +114,6 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {
})

ginkgo.It("IPAM allocates, releases, and reallocates IPs correctly", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
}
Expand All @@ -141,8 +138,19 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {
}
})

ginkgo.It("fails to allocate multiple IPs from the same subnet", func() {
subnets := []string{"10.1.1.0/24", "2000::/64"}

gomega.Expect(allocator.AddOrUpdateSubnet(subnetName, ovntest.MustParseIPNets(subnets...))).To(gomega.Succeed())

ips, err := util.ParseIPNets([]string{"10.1.1.1/24", "10.1.1.2/24"})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(allocator.AllocateIPs(subnetName, ips)).To(gomega.MatchError(
"failed to allocate IP 10.1.1.2 for subnet1: attempted to reserve multiple IPs in the same IPAM instance",
))
})

ginkgo.It("releases IPs for other subnets when any other subnet allocation fails", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
"10.1.2.0/29",
Expand Down Expand Up @@ -184,7 +192,6 @@ var _ = ginkgo.Describe("Subnet IP allocator operations", func() {
})

ginkgo.It("fails correctly when trying to block a previously allocated IP", func() {
subnetName := "subnet1"
subnets := []string{
"10.1.1.0/24",
"2000::/64",
Expand Down
Loading

0 comments on commit a678c4f

Please sign in to comment.