summaryrefslogtreecommitdiff
path: root/src/PVE/Network/SDN/VnetPlugin.pm
blob: 717438c22ab2d313dc0fe80c92259c8f3fd4091b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package PVE::Network::SDN::VnetPlugin;

use strict;
use warnings;

use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Exception qw(raise raise_param_exc);
use PVE::JSONSchema qw(get_standard_option);

use PVE::SectionConfig;
use base qw(PVE::SectionConfig);

PVE::Cluster::cfs_register_file(
    'sdn/vnets.cfg',
    sub { __PACKAGE__->parse_config(@_); },
    sub { __PACKAGE__->write_config(@_); },
);

PVE::JSONSchema::register_standard_option(
    'pve-sdn-vnet-id',
    {
        description => "The SDN vnet object identifier.",
        type => 'string',
        format => 'pve-sdn-vnet-id',
    },
);

PVE::JSONSchema::register_format('pve-sdn-vnet-id', \&parse_sdn_vnet_id);

sub parse_sdn_vnet_id {
    my ($id, $noerr) = @_;

    if ($id !~ m/^[a-z][a-z0-9]*[a-z0-9]$/i) {
        return undef if $noerr;
        die "vnet ID '$id' contains illegal characters\n";
    }
    die "vnet ID '$id' can't be more length than 8 characters\n" if length($id) > 8;
    return $id;
}

my $defaultData = {

    propertyList => {
        vnet => get_standard_option(
            'pve-sdn-vnet-id',
            { completion => \&PVE::Network::SDN::Vnets::complete_sdn_vnet },
        ),
    },
};

sub type {
    return 'vnet';
}

sub private {
    return $defaultData;
}

sub properties {
    return {
        zone => {
            type => 'string',
            description => 'Name of the zone this VNet belongs to.',
        },
        type => {
            type => 'string',
            enum => ['vnet'],
            description => 'Type of the VNet.',
            optional => 1,
        },
        tag => {
            type => 'integer',
            description =>
                'VLAN Tag (for VLAN or QinQ zones) or VXLAN VNI (for VXLAN or EVPN zones).',
            optional => 1,
            minimum => 1,
            maximum => 16777215,
        },
        vlanaware => {
            type => 'boolean',
            description => 'Allow VLANs to pass through this vnet.',
            optional => 1,
        },
        alias => {
            type => 'string',
            description => "Alias name of the VNet.",
            pattern => qr/[\(\)-_.\w\d\s]{0,256}/i,
            maxLength => 256,
            optional => 1,
        },
        'isolate-ports' => {
            type => 'boolean',
            description =>
                "If true, sets the isolated property for all interfaces on the bridge of this VNet.",
            optional => 1,
        },
    };
}

sub options {
    return {
        zone => { optional => 0 },
        tag => { optional => 1 },
        alias => { optional => 1 },
        vlanaware => { optional => 1 },
        'isolate-ports' => { optional => 1 },
    };
}

sub on_delete_hook {
    my ($class, $vnetid, $vnet_cfg) = @_;

    #verify if subnets are associated
    my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
    raise_param_exc({ vnet => "Can't delete vnet if subnets exists" }) if $subnets;
}

sub on_update_hook {
    my ($class, $vnetid, $vnet_cfg) = @_;

    my $vnet = $vnet_cfg->{ids}->{$vnetid};
    my $tag = $vnet->{tag};
    my $vlanaware = $vnet->{vlanaware};

    #don't allow vlanaware change if subnets are defined
    if ($vnet->{vlanaware}) {
        my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
        raise_param_exc({ vlanaware => "vlanaware vnet is not compatible with subnets" })
            if $subnets;
    }
}

1;