---
# System prepended metadata

title: Using dedicated networks for OpenShift Data Foundation
tags: [network]

---

# Using dedicated networks for OpenShift Data Foundation

TODO - explain why I'm writing this. In short, I'm writing this in order to provide additional context to the official documentation.


[Planning Doc - 8.2 Multi network plug-in (Multus) support](https://docs.redhat.com/en/documentation/red_hat_openshift_data_foundation/4.18/html-single/planning_your_deployment/index#multi-network-plugin-multus-support_rhodf)
[Managing Doc - 7 Creating Multus networks](https://docs.redhat.com/en/documentation/red_hat_openshift_data_foundation/4.18/html-single/managing_and_allocating_storage_resources/index#creating-multus-networks_rhodf)

TODO - Add a visual diagram that shows overlapping and non-overlapping CIDRs/routes

TODO - Add these test commands below. Using these commands you can create Pods/Containers that simulate the OpenShift Data Foundation deployment and verify that you can `ping` between services running on different nodes and also verify that the Pods/Containers can ping the host (and vice-versa)
```bash
oc run -n openshift-storage jcall-test-pod --image=registry.redhat.io/rhel9/support-tools --annotations k8s.v1.cni.cncf.io/networks=odf-public -it --restart=Never 

oc run -n openshift-storage jcall-test-pod --image=registry.redhat.io/rhel9/support-tools --annotations k8s.v1.cni.cncf.io/networks=odf-public -it --restart=Never --command -- ip route list

# optionally add a nodeSelector override
 --overrides='{"spec": {"nodeSelector": {"kubernetes.io/hostname": "dell-r760-01"}}}'
```

:::info
Ian mentioned today that it may be possible to simplify the host configuration (NNCP) by setting the netmask to /17 instead of /24. This would eliminiate the need for a static route, when the smaller Node network is a part of the larger Pod network
:::

## Example using bonded NICs instead of a single NIC

### Node configuration (via NodeNetworkConfigurationPolicy)

The nodes need to connect with the pods...
Make note of the static route that allows the nodes to connect with the pods

```yaml=
# Node network: 192.168.255.0/24  (exclude from NetworkAttachmentDefintion's whereabouts)
# Pod  network: 192.168.128.0/17  (see NetworkAttachmentDefinition)
---
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
  name: rhclient1-odf-public-net  # [1]
spec:
  nodeSelector:
    kubernetes.io/hostname: rhclient1.dota-lab.iad.redhat.com  # [2]
  desiredState:
    interfaces:
    - name: bridge-data
      description: Used by VMs (via net-attach-def) to access VLAN 999 (172.31.255.0/24)
      state: up
      type: linux-bridge
      mtu: 9000
      bridge:
        options:
          stp:
            enabled: true
        port:
        - name: bond-data
      ipv4:
        enabled: false
      ipv6:
        enabled: false

    - name: bond-data
      description: LACP bond to arctica-data1
      # 172.16.1.0/24    not used by guacamole
      # 192.168.128.0/17 used by ODF pods
      # 192.168.255.0/24 used by ODF nodes
      # VLAN 999 (172.31.255.0/24) used by VMs
      state: up
      type: bond
      mtu: 9000
      link-aggregation:
        mode: 802.3ad
        port:
        - ens2f0
        - ens2f1
      ipv4:
        enabled: false
      ipv6:
        enabled: false
      lldp:
        enabled: true

    - name: odf-public-shim  # [3]
      description: Used to connect each node to OpenShift Data Foundations' public multus network
      type: mac-vlan  # [4]
      state: up
      mtu: 9000
      mac-vlan:
        base-iface: bridge-data  # [5]
        mode: bridge
        promiscuous: true
      ipv4:  # [6]
        enabled: true
        dhcp: false
        address:
        - ip: 192.168.255.101  # [7] STATIC IP FOR node-1
          prefix-length: 24

    routes:  # [8]
      config:
      - destination: 192.168.128.0/17  # [9]
        next-hop-interface: odf-public-shim

#1. For static IP management, each node must have a unique NodeNetworkConfigurationPolicy.
#2. Select individual nodes via hostname to configure static IPs.
#3. A “shim” interface is used to connect nodes to the Pods' multus public network.
#4. The node’s “shim” interface type must be the same as the Pod's NetworkAttachmentDefinition.
#5. The base-iface must match the Multus public network's parent/master interface (typically eth0 or bond0.)
#6. The ipv4 (or ipv6`) section configures node IP addresses on the Multus public network.
#7. Unique IP address assigned to this node. Don’t forget to change the IP for each node.
#8. The routes section instructs nodes how to reach pods on the Multus public network.
#9. The route destination(s) of the Pods' CIDR range.

```


### Pod configuration (via NetworkAttachmentDefinition)

https://docs.redhat.com/en/documentation/red_hat_openshift_data_foundation/4.16/html/planning_your_deployment/network-requirements_rhodf#multus-examples_rhodf

#### Option 1 - When Node network is a part of the larger Pod network

The ODF Pods need to connect with the Nodes. This "just works" if the (smaller CIDR) Node network is within the Pod's network (larger CIDR)
**Each Ceph service (mon, osd, etc...) gets an IP address from here**

```yaml=
# Node network: 192.168.255.0/24  (exclude from NetworkAttachmentDefintion's whereabouts)
# Pod  network: 192.168.128.0/17  (see NetworkAttachmentDefinition)

---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
 name: odf-public
 namespace: openshift-storage
spec:
 config: '{
     "cniVersion": "0.3.1",
     "type": "macvlan",               # [1]
     "master": "bridge-data",         # [2]
     "mode": "bridge",
     "mtu": 9000,                     # Omit unless switch config allows this
     "ipam": {
       "type": "whereabouts",         # [3]
       "range": "192.168.128.0/17",   # [4]
       "exclude": [
          "192.168.255.0/24"          # [5]
       ]
     }
   }'

#1. Pods must attach to the parent/master using the same interface type (macvlan) configured via NodeNetworkConfigurationPolicies
#2. The net-attach-def's parent/master interface must match the NNCP (typically eth0 or bond0)
#3. Using whereabouts instead of DHCP for simplicity. OpenShift will be responsible for address assignment
#4. Pods will be assigned IPs in the range 192.168.0.0/16 with the exception of a range allocated to nodes (see 5)
#5. Exclude the range assigned to nodes via NNCP
#6. The routes section instructs pods how to reach nodes on the Multus public network. A corresponding route should exist in the NNCP
#7. The route destination (dst) must match the CIDR range planned for nodes
```

#### Option 2 - When the Node network is not a part of the Pod network

But if the node network is outside of the pod CIDR, create a dedicated / static route.
I'm not sure why this makes sense, but I had to do it once before...
Please note, the Node configuration (NNCP) needs to define a statci route to the Pod network as well *(change #9 of NNCP above)*
**Each Ceph service (mon, osd, etc...) gets an IP address from here**

```yaml=
# Node network: 192.168.255.0/24  (add static route to Pods' NetworkAttachmentDefintion)
# Pod  network:   10.252.15.0/24  (add static route to Nodes' NodeNetworkConfigurationPolicies)

---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
 name: odf-public
 namespace: openshift-storage
spec:
 config: '{
     "cniVersion": "0.3.1",
     "type": "macvlan",               # [1]
     "master": "bridge-data",         # [2]
     "mode": "bridge",
     "mtu": 9000,                     # Omit unless switch config allows this
     "ipam": {
       "type": "whereabouts",         # [3]
       "range": "10.252.15.0/24",     # [4]
       "routes": [                    # [6]
         {"dst": "192.168.255.0/24"}  # [7]
       ]
     }
   }'

#1. Pods must attach to the parent/master using the same interface type (macvlan) configured via NodeNetworkConfigurationPolicies
#2. The net-attach-def's parent/master interface must match the NNCP (typically eth0 or bond0)
#3. Using whereabouts instead of DHCP for simplicity. OpenShift will be responsible for address assignment
#4. Pods will be assigned IPs in the range 192.168.0.0/16 with the exception of a range allocated to nodes (see 5)
#5. Exclude the range assigned to nodes via NNCP
#6. The routes section instructs pods how to reach nodes on the Multus public network. A corresponding route should exist in the NNCP
#7. The route destination (dst) must match the CIDR range planned for nodes
```


# Validation tool

Download the tool from here: https://access.redhat.com/articles/7014721

Run the tool like this:

```bash
./rook multus validation config --help
./rook multus validation config converged > my-config
vi my-config  #add public network, and cluster network if applicable

./rook multus validation run --help
./rook multus validation run --config my-config

```

**Caveat - don't upgrade to 4.17 until the "holder" pods are gone**
https://access.redhat.com/articles/7078648


## Example using single NIC instead of bonded NICs

### Node configuration (via NodeNetworkConfigurationPolicy)

Servers need static IP addresses. Only showing control-plane0. Please also create copies (with unique IP addresses) for other nodes.

```yaml=
# Node network: 192.168.255.0/24  (exclude from NetworkAttachmentDefintion's whereabouts)
# Pod  network: 192.168.128.0/17  (see NetworkAttachmentDefinition)

---
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
 name: control-plane0-odf-public-shim
spec:
 nodeSelector:
   kubernetes.io/hostname: control-plane0.example.com  ### HOSTNAME
 desiredState:
   interfaces:
     - name: odf-public-shim
       description: Shim interface used to connect host to OpenShift Data Foundation public Multus network
       type: mac-vlan
       state: up
       mac-vlan:
         base-iface: enp129s0f1
         mode: bridge
         promiscuous: true
       ipv4:
         enabled: true
         dhcp: false
         address:
           - ip: 192.168.255.100  ### STATIC IP
             prefix-length: 24

     - name: enp129s0f1  ## This interface section can be omitted if you don't care about LLDP
       type: ethernet
       state: up
       lldp:
         enabled: true   ## I love LLDP!
       ipv4:
         enabled: false
       ipv6:
         enabled: false

   routes:
     config:
       - destination: 192.168.128.0/17
         next-hop-interface: odf-public-shim
```

### Pod configuration (via NetworkAttachmentDefinition)

**Each Ceph service (mon, osd, etc...) gets an IP address from here**

```yaml=
# https://docs.redhat.com/en/documentation/red_hat_openshift_data_foundation/4.16/html/planning_your_deployment/network-requirements_rhodf#multus-examples_rhodf

# Node network: 192.168.255.0/24  (exclude from NetworkAttachmentDefintion's whereabouts)
# Pod  network: 192.168.128.0/17  (see NetworkAttachmentDefinition)

# JCALL - the block below doesn't declare any static routes. I assume this is when the node network is within the pod/public/multus network
---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
 name: odf-public
 namespace: openshift-storage
spec:
 config: '{
     "cniVersion": "0.3.1",
     "type": "macvlan",               # [1]
     "master": "enp129s0f1",          # [2]
     "mode": "bridge",
     "ipam": {
       "type": "whereabouts",         # [3]
       "range": "192.168.128.0/17",   # [4]
       "exclude": [
          "192.168.255.0/24"          # [5]
       ]
     }
   }'

#1. Pods must attach to the parent/master using the same interface type (macvlan) configured via NodeNetworkConfigurationPolicies
#2. The net-attach-def's parent/master interface must match the NNCP (typically eth0 or bond0)
#3. Using whereabouts instead of DHCP for simplicity. OpenShift will be responsible for address assignment
#4. Pods will be assigned IPs in the range 192.168.0.0/16 with the exception of a range allocated to nodes (see 5)
#5. Exclude the range assigned to nodes via NNCP
#6. The routes section instructs pods how to reach nodes on the Multus public network. A corresponding route should exist in the NNCP
#7. The route destination (dst) must match the CIDR range planned for nodes
```

## Example using VLAN tags (non-overlapping)

### Node configuration (via NodeNetworkConfigurationPolicy)

```yaml=
# Node network: 192.168.252.0/24  (add static route to Pods' NetworkAttachmentDefintion)
# Pod  network:   10.252.16.0/24  (add static route to Nodes' NodeNetworkConfigurationPolicies)

---
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
 name: control-plane-0-odf-public-shim-via-vlan-252
spec:
 nodeSelector:
   kubernetes.io/hostname: control-plane0.example.com  ### HOSTNAME
 desiredState:
   interfaces:
   - name: eth0.252
     type: vlan
     state: up
     ipv4:
       enabled: false
     ipv6:
       enabled: false
     lldp:
       enabled: true
     vlan:
       base-iface: eth0
       id: 252
       protocol: 802.1q
       
   - name: odf-public-shim
     type: mac-vlan
     state: up
     ipv4:
       enabled: true
       dhcp: false
       address:
       - ip: 192.168.252.11   ### Node network
         prefix-length: 24
     ipv6:
       enabled: false
     mac-vlan:
       base-iface: eth0.252
       mode: bridge
       promiscuous: true
       
   routes:
     config:
     - destination: 10.252.16.0/24    ### Pod network
       next-hop-interface: odf-public-shim
```

### Pod configuration (via NetworkAttachmentDefinition)

```yaml=
# Node network: 192.168.252.0/24  (add static route to Pods' NetworkAttachmentDefintion)
# Pod  network:   10.252.16.0/24  (add static route to Nodes' NodeNetworkConfigurationPolicies)

---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
 name: odf-public
 namespace: openshift-storage
spec:
 config: '{
     "cniVersion": "0.3.1",
     "type": "macvlan",
     "master": "eth0.252",
     "mode": "bridge",
     "mtu": 9000,       ### Omit MTU unless switch config allows this
     "ipam": {
       "type": "whereabouts",
       "range": "10.252.16.0/24",     ### Pod network
       "routes": [
         {"dst": "192.168.252.0/24"}  ### Node network
       ]
     }
   }'
```