Skip to content

Commit

Permalink
label node with host subnet selector name to specify specific subnet …
Browse files Browse the repository at this point in the history
…range

To specify specic subnet range for a specific node, first in the
ovn-config configmap, define multiple subnet cidrs in net_cidr with the
format of <cidr1>,<cidr2>@<selector_name>...; then label the node that that
needs specific subnet range with label
k8s.ovn.org/subnet_selector_name=<selector_name>.

Signed-off-by: Yun Zhou <[email protected]>
  • Loading branch information
cathy-zhou committed May 12, 2020
1 parent d306b78 commit 2b2f588
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 80 deletions.
12 changes: 9 additions & 3 deletions go-controller/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const DefaultEncapPort = 6081

const DefaultAPIServer = "http://localhost:8443"

// DefaultNodeSubnetSelectorName captures default name for the node subnet selector
const DefaultNodeSubnetSelectorName = "default"

// IP address range from which subnet is allocated for per-node join switch
const (
V4JoinSubnet = "100.64.0.0/16"
Expand Down Expand Up @@ -145,9 +148,12 @@ type DefaultConfig struct {
// RawClusterSubnets holds the unparsed cluster subnets. Should only be
// used inside config module.
RawClusterSubnets string `gcfg:"cluster-subnets"`
// ClusterSubnets holds parsed cluster subnet entries and may be used
// ClusterSubnets holds all parsed cluster subnet entries and may be used
// outside the config module.
ClusterSubnets []CIDRNetworkEntry
// ClusterSubnetsBySelector holds all parsed cluster subnet entries keyed by selectorName
// and may be used outside the config module.
ClusterSubnetsBySelector map[string][]CIDRNetworkEntry
}

// LoggingConfig holds logging-related parsed config file parameters and command-line overrides
Expand Down Expand Up @@ -1040,7 +1046,7 @@ func buildHybridOverlayConfig(ctx *cli.Context, cli, file *config, allSubnets *c

if HybridOverlay.Enabled {
var err error
HybridOverlay.ClusterSubnets, err = ParseClusterSubnetEntries(HybridOverlay.RawClusterSubnets)
_, HybridOverlay.ClusterSubnets, err = ParseClusterSubnetEntries(HybridOverlay.RawClusterSubnets)
if err != nil {
return fmt.Errorf("hybrid overlay cluster subnet invalid: %v", err)
}
Expand Down Expand Up @@ -1070,7 +1076,7 @@ func buildDefaultConfig(cli, file *config, allSubnets *configSubnets) error {
}

var err error
Default.ClusterSubnets, err = ParseClusterSubnetEntries(Default.RawClusterSubnets)
Default.ClusterSubnetsBySelector, Default.ClusterSubnets, err = ParseClusterSubnetEntries(Default.RawClusterSubnets)
if err != nil {
return fmt.Errorf("cluster subnet invalid: %v", err)
}
Expand Down
35 changes: 26 additions & 9 deletions go-controller/pkg/config/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,37 @@ func (e CIDRNetworkEntry) HostBits() uint32 {
// ParseClusterSubnetEntries returns the parsed set of CIDRNetworkEntries passed by the user on the command line
// These entries define the clusters network space by specifying a set of CIDR and netmasks the SDN can allocate
// addresses from.
func ParseClusterSubnetEntries(clusterSubnetCmd string) ([]CIDRNetworkEntry, error) {
func ParseClusterSubnetEntries(clusterSubnetCmd string) (map[string][]CIDRNetworkEntry, []CIDRNetworkEntry, error) {
var parsedClusterListMap map[string][]CIDRNetworkEntry
var parsedClusterList []CIDRNetworkEntry
ipv6 := false
clusterEntriesList := strings.Split(clusterSubnetCmd, ",")

for _, clusterEntry := range clusterEntriesList {
parsedClusterListMap = make(map[string][]CIDRNetworkEntry)
for _, clusterEntryWithSelector := range clusterEntriesList {
var parsedClusterEntry CIDRNetworkEntry

clusterEntryInfo := strings.SplitN(clusterEntryWithSelector, "@", 2)

// if no selector name is specified, assign the default selector name
selectorName := DefaultNodeSubnetSelectorName
if len(clusterEntryInfo) == 2 {
selectorName = strings.TrimSpace(clusterEntryInfo[1])
if len(selectorName) == 0 {
return nil, nil, fmt.Errorf("invalid selector name %s for %q", selectorName, clusterEntryWithSelector)
}
}
clusterEntry := clusterEntryInfo[0]
splitClusterEntry := strings.Split(clusterEntry, "/")

if len(splitClusterEntry) < 2 || len(splitClusterEntry) > 3 {
return nil, fmt.Errorf("CIDR %q not properly formatted", clusterEntry)
return nil, nil, fmt.Errorf("CIDR %q not properly formatted", clusterEntry)
}

var err error
_, parsedClusterEntry.CIDR, err = net.ParseCIDR(fmt.Sprintf("%s/%s", splitClusterEntry[0], splitClusterEntry[1]))
if err != nil {
return nil, err
return nil, nil, err
}

if utilnet.IsIPv6(parsedClusterEntry.CIDR.IP) {
Expand All @@ -52,12 +65,12 @@ func ParseClusterSubnetEntries(clusterSubnetCmd string) ([]CIDRNetworkEntry, err
if len(splitClusterEntry) == 3 {
tmp, err := strconv.ParseUint(splitClusterEntry[2], 10, 32)
if err != nil {
return nil, err
return nil, nil, err
}
parsedClusterEntry.HostSubnetLength = uint32(tmp)

if ipv6 && parsedClusterEntry.HostSubnetLength != 64 {
return nil, fmt.Errorf("IPv6 only supports /64 host subnets")
return nil, nil, fmt.Errorf("IPv6 only supports /64 host subnets")
}
} else {
if ipv6 {
Expand All @@ -69,18 +82,22 @@ func ParseClusterSubnetEntries(clusterSubnetCmd string) ([]CIDRNetworkEntry, err
}

if parsedClusterEntry.HostSubnetLength <= uint32(entryMaskLength) {
return nil, fmt.Errorf("cannot use a host subnet length mask shorter than or equal to the cluster subnet mask. "+
return nil, nil, fmt.Errorf("cannot use a host subnet length mask shorter than or equal to the cluster subnet mask. "+
"host subnet length: %d, cluster subnet length: %d", parsedClusterEntry.HostSubnetLength, entryMaskLength)
}

if _, ok := parsedClusterListMap[selectorName]; !ok {
parsedClusterListMap[selectorName] = []CIDRNetworkEntry{}
}
parsedClusterListMap[selectorName] = append(parsedClusterListMap[selectorName], parsedClusterEntry)
parsedClusterList = append(parsedClusterList, parsedClusterEntry)
}

if len(parsedClusterList) == 0 {
return nil, fmt.Errorf("failed to parse any CIDRs from %q", clusterSubnetCmd)
return nil, nil, fmt.Errorf("failed to parse any CIDRs from %q", clusterSubnetCmd)
}

return parsedClusterList, nil
return parsedClusterListMap, parsedClusterList, nil
}

type configSubnetType string
Expand Down
2 changes: 1 addition & 1 deletion go-controller/pkg/config/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func TestParseClusterSubnetEntries(t *testing.T) {

for _, tc := range tests {

parsedList, err := ParseClusterSubnetEntries(tc.cmdLineArg)
_, parsedList, err := ParseClusterSubnetEntries(tc.cmdLineArg)
if err != nil && !tc.expectedErr {
t.Errorf("Test case \"%s\" expected no errors, got %v", tc.name, err)
}
Expand Down
18 changes: 14 additions & 4 deletions go-controller/pkg/ovn/gateway_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,34 @@ func gatewayInit(nodeName string, clusterIPSubnet []*net.IPNet, hostSubnets []*n
var gwLRPIPs, drLRPIPs []net.IP
var gwLRPAddrs, drLRPAddrs []string

joinSwitch := joinSwitchPrefix + nodeName
cmdArgs := []string{"--", "--may-exist", "ls-add", joinSwitch}
for _, joinSubnet := range joinSubnets {
prefixLen, _ := joinSubnet.Mask.Size()
gwLRPIP := util.NextIP(joinSubnet.IP)

gwLRPIPs = append(gwLRPIPs, gwLRPIP)
gwLRPAddrs = append(gwLRPAddrs, fmt.Sprintf("%s/%d", gwLRPIP.String(), prefixLen))
drLRPIP := util.NextIP(gwLRPIP)
drLRPIPs = append(drLRPIPs, drLRPIP)
drLRPAddrs = append(drLRPAddrs, fmt.Sprintf("%s/%d", drLRPIP.String(), prefixLen))

if gwLRPMAC == nil || !utilnet.IsIPv6(gwLRPIP) {
isIPv6 := utilnet.IsIPv6(gwLRPIP)
if isIPv6 {
cmdArgs = append(cmdArgs, []string{"--", "set", "logical_switch", joinSwitch,
"other-config:ipv6_prefix=" + joinSubnet.IP.String()}...)
} else {
cmdArgs = append(cmdArgs, []string{"--", "set", "logical_switch", joinSwitch,
"other-config:subnet=" + joinSubnet.String()}...)
}
if gwLRPMAC == nil || !isIPv6 {
gwLRPMAC = util.IPAddrToHWAddr(gwLRPIP)
drLRPMAC = util.IPAddrToHWAddr(drLRPIP)
}
}

joinSwitch := joinSwitchPrefix + nodeName
// create the per-node join switch
stdout, stderr, err = util.RunOVNNbctl("--", "--may-exist", "ls-add", joinSwitch)
stdout, stderr, err = util.RunOVNNbctl(cmdArgs...)
if err != nil {
return fmt.Errorf("failed to create logical switch %q, stdout: %q, stderr: %q, error: %v",
joinSwitch, stdout, stderr, err)
Expand Down Expand Up @@ -189,7 +199,7 @@ func gatewayInit(nodeName string, clusterIPSubnet []*net.IPNet, hostSubnets []*n
// Add external interface as a logical port to external_switch.
// This is a learning switch port with "unknown" address. The external
// world is accessed via this port.
cmdArgs := []string{
cmdArgs = []string{
"--", "--may-exist", "lsp-add", externalSwitch, l3GatewayConfig.InterfaceID,
"--", "lsp-set-addresses", l3GatewayConfig.InterfaceID, "unknown",
"--", "lsp-set-type", l3GatewayConfig.InterfaceID, "localnet",
Expand Down
6 changes: 3 additions & 3 deletions go-controller/pkg/ovn/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ node4 chassis=912d592c-904c-40cd-9ef1-c2e5b49a33dd lb_force_snat_ip=100.64.0.4`,

fexec.AddFakeCmdsNoOutputNoError([]string{
"ovn-nbctl --timeout=15 -- --may-exist lr-add GR_test-node -- set logical_router GR_test-node options:chassis=SYSTEM-ID external_ids:physical_ip=169.254.33.2 external_ids:physical_ips=169.254.33.2",
"ovn-nbctl --timeout=15 -- --may-exist ls-add join_test-node",
"ovn-nbctl --timeout=15 -- --may-exist ls-add join_test-node -- set logical_switch join_test-node other-config:subnet=100.64.0.0/29",
"ovn-nbctl --timeout=15 -- --may-exist lsp-add join_test-node jtor-GR_test-node -- set logical_switch_port jtor-GR_test-node type=router options:router-port=rtoj-GR_test-node addresses=router",
"ovn-nbctl --timeout=15 -- --if-exists lrp-del rtoj-GR_test-node -- lrp-add GR_test-node rtoj-GR_test-node 0a:58:64:40:00:01 100.64.0.1/29",
"ovn-nbctl --timeout=15 -- --may-exist lsp-add join_test-node jtod-test-node -- set logical_switch_port jtod-test-node type=router options:router-port=dtoj-test-node addresses=router",
Expand Down Expand Up @@ -140,7 +140,7 @@ node4 chassis=912d592c-904c-40cd-9ef1-c2e5b49a33dd lb_force_snat_ip=100.64.0.4`,

fexec.AddFakeCmdsNoOutputNoError([]string{
"ovn-nbctl --timeout=15 -- --may-exist lr-add GR_test-node -- set logical_router GR_test-node options:chassis=SYSTEM-ID external_ids:physical_ip=fd99::2 external_ids:physical_ips=fd99::2",
"ovn-nbctl --timeout=15 -- --may-exist ls-add join_test-node",
"ovn-nbctl --timeout=15 -- --may-exist ls-add join_test-node -- set logical_switch join_test-node other-config:ipv6_prefix=fd98::",
"ovn-nbctl --timeout=15 -- --may-exist lsp-add join_test-node jtor-GR_test-node -- set logical_switch_port jtor-GR_test-node type=router options:router-port=rtoj-GR_test-node addresses=router",
"ovn-nbctl --timeout=15 -- --if-exists lrp-del rtoj-GR_test-node -- lrp-add GR_test-node rtoj-GR_test-node 0a:58:fd:98:00:01 fd98::1/125",
"ovn-nbctl --timeout=15 -- --may-exist lsp-add join_test-node jtod-test-node -- set logical_switch_port jtod-test-node type=router options:router-port=dtoj-test-node addresses=router",
Expand Down Expand Up @@ -221,7 +221,7 @@ node4 chassis=912d592c-904c-40cd-9ef1-c2e5b49a33dd lb_force_snat_ip=100.64.0.4`,

fexec.AddFakeCmdsNoOutputNoError([]string{
"ovn-nbctl --timeout=15 -- --may-exist lr-add GR_test-node -- set logical_router GR_test-node options:chassis=SYSTEM-ID external_ids:physical_ip=169.254.33.2 external_ids:physical_ips=169.254.33.2,fd99::2",
"ovn-nbctl --timeout=15 -- --may-exist ls-add join_test-node",
"ovn-nbctl --timeout=15 -- --may-exist ls-add join_test-node -- set logical_switch join_test-node other-config:subnet=100.64.0.0/29 -- set logical_switch join_test-node other-config:ipv6_prefix=fd98::",
"ovn-nbctl --timeout=15 -- --may-exist lsp-add join_test-node jtor-GR_test-node -- set logical_switch_port jtor-GR_test-node type=router options:router-port=rtoj-GR_test-node addresses=router",
"ovn-nbctl --timeout=15 -- --if-exists lrp-del rtoj-GR_test-node -- lrp-add GR_test-node rtoj-GR_test-node 0a:58:64:40:00:01 100.64.0.1/29 fd98::1/125",
"ovn-nbctl --timeout=15 -- --may-exist lsp-add join_test-node jtod-test-node -- set logical_switch_port jtod-test-node type=router options:router-port=dtoj-test-node addresses=router",
Expand Down
Loading

0 comments on commit 2b2f588

Please sign in to comment.