]>
Commit | Line | Data |
---|---|---|
1 | package PVE::Network::SDN::Zones::VxlanPlugin; | |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use PVE::Network::SDN::Zones::Plugin; | |
6 | use PVE::Tools qw($IPV4RE); | |
7 | use PVE::INotify; | |
8 | ||
9 | use base('PVE::Network::SDN::Zones::Plugin'); | |
10 | ||
11 | PVE::JSONSchema::register_format('pve-sdn-vxlanrange', \&pve_verify_sdn_vxlanrange); | |
12 | sub pve_verify_sdn_vxlanrange { | |
13 | my ($vxlanstr) = @_; | |
14 | ||
15 | PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vxlanstr, '16777216'); | |
16 | ||
17 | return $vxlanstr; | |
18 | } | |
19 | ||
20 | PVE::JSONSchema::register_format('ipv4-multicast', \&parse_ipv4_multicast); | |
21 | sub parse_ipv4_multicast { | |
22 | my ($ipv4, $noerr) = @_; | |
23 | ||
24 | if ($ipv4 !~ m/^(?:$IPV4RE)$/) { | |
25 | return undef if $noerr; | |
26 | die "value does not look like a valid multicast IPv4 address\n"; | |
27 | } | |
28 | ||
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"; | |
33 | } | |
34 | } | |
35 | ||
36 | return $ipv4; | |
37 | } | |
38 | ||
39 | sub type { | |
40 | return 'vxlan'; | |
41 | } | |
42 | ||
43 | sub properties { | |
44 | return { | |
45 | 'multicast-address' => { | |
46 | description => "Multicast address.", | |
47 | type => 'string', format => 'ipv4-multicast' | |
48 | }, | |
49 | 'unicast-address' => { | |
50 | description => "Unicast peers address ip list.", | |
51 | type => 'string', format => 'ip-list' | |
52 | }, | |
53 | }; | |
54 | } | |
55 | ||
56 | sub options { | |
57 | ||
58 | return { | |
59 | nodes => { optional => 1}, | |
60 | 'uplink-id' => { optional => 0 }, | |
61 | 'multicast-address' => { optional => 1 }, | |
62 | 'unicast-address' => { optional => 1 }, | |
63 | }; | |
64 | } | |
65 | ||
66 | # Plugin implementation | |
67 | sub generate_sdn_config { | |
68 | my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_; | |
69 | ||
70 | my $tag = $vnet->{tag}; | |
71 | my $alias = $vnet->{alias}; | |
72 | my $ipv4 = $vnet->{ipv4}; | |
73 | my $ipv6 = $vnet->{ipv6}; | |
74 | my $mac = $vnet->{mac}; | |
75 | my $multicastaddress = $plugin_config->{'multicast-address'}; | |
76 | my @unicastaddress = split(',', $plugin_config->{'unicast-address'}) if $plugin_config->{'unicast-address'}; | |
77 | ||
78 | my $uplink = $plugin_config->{'uplink-id'}; | |
79 | ||
80 | die "missing vxlan tag" if !$tag; | |
81 | my $iface = "uplink$uplink"; | |
82 | my $ifaceip = ""; | |
83 | ||
84 | if($uplinks->{$uplink}->{name}) { | |
85 | $iface = $uplinks->{$uplink}->{name}; | |
86 | $ifaceip = PVE::Network::SDN::Zones::Plugin::get_first_local_ipv4_from_interface($iface); | |
87 | } | |
88 | ||
89 | my $mtu = 1450; | |
90 | $mtu = $uplinks->{$uplink}->{mtu} - 50 if $uplinks->{$uplink}->{mtu}; | |
91 | $mtu = $vnet->{mtu} if $vnet->{mtu}; | |
92 | ||
93 | #vxlan interface | |
94 | my @iface_config = (); | |
95 | push @iface_config, "vxlan-id $tag"; | |
96 | ||
97 | if($multicastaddress) { | |
98 | push @iface_config, "vxlan-svcnodeip $multicastaddress"; | |
99 | push @iface_config, "vxlan-physdev $iface"; | |
100 | } elsif (@unicastaddress) { | |
101 | ||
102 | foreach my $address (@unicastaddress) { | |
103 | next if $address eq $ifaceip; | |
104 | push @iface_config, "vxlan_remoteip $address"; | |
105 | } | |
106 | } | |
107 | ||
108 | push @iface_config, "mtu $mtu" if $mtu; | |
109 | push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"}; | |
110 | ||
111 | #vnet bridge | |
112 | @iface_config = (); | |
113 | push @iface_config, "address $ipv4" if $ipv4; | |
114 | push @iface_config, "address $ipv6" if $ipv6; | |
115 | push @iface_config, "hwaddress $mac" if $mac; | |
116 | push @iface_config, "bridge_ports vxlan$vnetid"; | |
117 | push @iface_config, "bridge_stp off"; | |
118 | push @iface_config, "bridge_fd 0"; | |
119 | push @iface_config, "mtu $mtu" if $mtu; | |
120 | push @iface_config, "alias $alias" if $alias; | |
121 | push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; | |
122 | ||
123 | return $config; | |
124 | } | |
125 | ||
126 | sub on_delete_hook { | |
127 | my ($class, $transportid, $sdn_cfg) = @_; | |
128 | ||
129 | # verify that no vnet are associated to this transport | |
130 | foreach my $id (keys %{$sdn_cfg->{ids}}) { | |
131 | my $sdn = $sdn_cfg->{ids}->{$id}; | |
132 | die "transport $transportid is used by vnet $id" | |
133 | if ($sdn->{type} eq 'vnet' && defined($sdn->{zone}) && $sdn->{zone} eq $transportid); | |
134 | } | |
135 | } | |
136 | ||
137 | 1; | |
138 | ||
139 |