1 package PVE
::Network
::SDN
::VxlanPlugin
;
5 use PVE
::Network
::SDN
::Plugin
;
6 use PVE
::Tools
qw($IPV4RE);
9 use base
('PVE::Network::SDN::Plugin');
11 PVE
::JSONSchema
::register_format
('pve-sdn-vxlanrange', \
&pve_verify_sdn_vxlanrange
);
12 sub pve_verify_sdn_vxlanrange
{
15 PVE
::Network
::SDN
::Plugin
::parse_tag_number_or_range
($vxlanstr, '16777216');
20 PVE
::JSONSchema
::register_format
('ipv4-multicast', \
&parse_ipv4_multicast
);
21 sub parse_ipv4_multicast
{
22 my ($ipv4, $noerr) = @_;
24 if ($ipv4 !~ m/^(?:$IPV4RE)$/) {
25 return undef if $noerr;
26 die "value does not look like a valid multicast IPv4 address\n";
29 if ($ipv4 =~ m/^(\d+)\.\d+.\d+.\d+/) {
30 if($1 < 224 || $1 > 239) {
31 return undef if $noerr;
32 die "value does not look like a valid multicast IPv4 address\n";
52 type
=> 'string', format
=> 'pve-sdn-vxlanrange',
53 description
=> "Allowed vlan range",
55 'multicast-address' => {
56 description
=> "Multicast address.",
57 type
=> 'string', format
=> 'ipv4-multicast'
59 'unicast-address' => {
60 description
=> "Unicast peers address ip list.",
61 type
=> 'string', format
=> 'ip-list'
69 'uplink-id' => { optional
=> 0 },
70 'multicast-address' => { optional
=> 1 },
71 'unicast-address' => { optional
=> 1 },
72 'vxlan-allowed' => { optional
=> 1 },
76 # Plugin implementation
77 sub generate_sdn_config
{
78 my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_;
80 my $tag = $vnet->{tag
};
81 my $alias = $vnet->{alias
};
82 my $ipv4 = $vnet->{ipv4
};
83 my $ipv6 = $vnet->{ipv6
};
84 my $mac = $vnet->{mac
};
85 my $multicastaddress = $plugin_config->{'multicast-address'};
86 my @unicastaddress = split(',', $plugin_config->{'unicast-address'}) if $plugin_config->{'unicast-address'};
88 my $uplink = $plugin_config->{'uplink-id'};
89 my $vxlanallowed = $plugin_config->{'vxlan-allowed'};
91 die "missing vxlan tag" if !$tag;
92 my $iface = "uplink$uplink";
95 if($uplinks->{$uplink}->{name
}) {
96 $iface = $uplinks->{$uplink}->{name
};
97 $ifaceip = PVE
::Network
::SDN
::Plugin
::get_first_local_ipv4_from_interface
($iface);
101 $mtu = $uplinks->{$uplink}->{mtu
} - 50 if $uplinks->{$uplink}->{mtu
};
102 $mtu = $vnet->{mtu
} if $vnet->{mtu
};
105 my @iface_config = ();
106 push @iface_config, "vxlan-id $tag";
108 if($multicastaddress) {
109 push @iface_config, "vxlan-svcnodeip $multicastaddress";
110 push @iface_config, "vxlan-physdev $iface";
111 } elsif (@unicastaddress) {
113 foreach my $address (@unicastaddress) {
114 next if $address eq $ifaceip;
115 push @iface_config, "vxlan_remoteip $address";
119 push @iface_config, "mtu $mtu" if $mtu;
120 push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"};
124 push @iface_config, "address $ipv4" if $ipv4;
125 push @iface_config, "address $ipv6" if $ipv6;
126 push @iface_config, "hwaddress $mac" if $mac;
127 push @iface_config, "bridge_ports vxlan$vnetid";
128 push @iface_config, "bridge_stp off";
129 push @iface_config, "bridge_fd 0";
130 push @iface_config, "mtu $mtu" if $mtu;
131 push @iface_config, "alias $alias" if $alias;
132 push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid};
138 my ($class, $transportid, $sdn_cfg) = @_;
140 # verify that no vnet are associated to this transport
141 foreach my $id (keys %{$sdn_cfg->{ids
}}) {
142 my $sdn = $sdn_cfg->{ids
}->{$id};
143 die "transport $transportid is used by vnet $id"
144 if ($sdn->{type
} eq 'vnet' && defined($sdn->{transportzone
}) && $sdn->{transportzone
} eq $transportid);
149 my ($class, $transportid, $sdn_cfg) = @_;
151 my $transport = $sdn_cfg->{ids
}->{$transportid};
153 # verify that vxlan-allowed don't conflict with another vxlan-allowed transport
155 # verify that vxlan-allowed is matching currently vnet tag in this transport
156 my $vxlanallowed = $transport->{'vxlan-allowed'};
158 foreach my $id (keys %{$sdn_cfg->{ids
}}) {
159 my $sdn = $sdn_cfg->{ids
}->{$id};
160 if ($sdn->{type
} eq 'vnet' && defined($sdn->{tag
})) {
161 if(defined($sdn->{transportzone
}) && $sdn->{transportzone
} eq $transportid) {
162 my $tag = $sdn->{tag
};
164 PVE
::Network
::SDN
::Plugin
::parse_tag_number_or_range
($vxlanallowed, '16777216', $tag);
167 die "vnet $id - vlan $tag is not allowed in transport $transportid";
174 # verify that router exist
175 if (defined($sdn_cfg->{ids
}->{$transportid}->{router
})) {
176 my $router = $sdn_cfg->{ids
}->{$transportid}->{router
};
177 if (!defined($sdn_cfg->{ids
}->{$router})) {
178 die "router $router don't exist";
180 die "$router is not a router type" if $sdn_cfg->{ids
}->{$router}->{type
} ne 'frr';
183 #vrf && vrf-vxlan need to be defined with router
184 my $vrf = $sdn_cfg->{ids
}->{$transportid}->{vrf
};
185 if (!defined($vrf)) {
186 die "missing vrf option";
188 # verify that vrf is not already declared in another transport
189 foreach my $id (keys %{$sdn_cfg->{ids
}}) {
190 next if $id eq $transportid;
191 die "vrf $vrf is already declared in $id"
192 if (defined($sdn_cfg->{ids
}->{$id}->{vrf
}) && $sdn_cfg->{ids
}->{$id}->{vrf
} eq $vrf);
196 my $vrfvxlan = $sdn_cfg->{ids
}->{$transportid}->{'vrf-vxlan'};
197 if (!defined($vrfvxlan)) {
198 die "missing vrf-vxlan option";
200 # verify that vrf-vxlan is not already declared in another transport
201 foreach my $id (keys %{$sdn_cfg->{ids
}}) {
202 next if $id eq $transportid;
203 die "vrf-vxlan $vrfvxlan is already declared in $id"
204 if (defined($sdn_cfg->{ids
}->{$id}->{'vrf-vxlan'}) && $sdn_cfg->{ids
}->{$id}->{'vrf-vxlan'} eq $vrfvxlan);