]>
Commit | Line | Data |
---|---|---|
f5eabba0 | 1 | package PVE::Network::SDN::Zones::QinQPlugin; |
20e19696 AD |
2 | |
3 | use strict; | |
4 | use warnings; | |
3dfdc684 | 5 | use PVE::Network::SDN::Zones::Plugin; |
20e19696 | 6 | |
3dfdc684 | 7 | use base('PVE::Network::SDN::Zones::Plugin'); |
20e19696 AD |
8 | |
9 | sub type { | |
10 | return 'qinq'; | |
11 | } | |
12 | ||
20e19696 AD |
13 | sub properties { |
14 | return { | |
1c95991c TL |
15 | tag => { |
16 | type => 'integer', | |
17 | minimum => 0, | |
18 | description => "Service-VLAN Tag", | |
19 | }, | |
823f2e2a AD |
20 | mtu => { |
21 | type => 'integer', | |
1c95991c | 22 | description => "MTU", |
823f2e2a AD |
23 | optional => 1, |
24 | }, | |
3dfdc684 AD |
25 | 'vlan-protocol' => { |
26 | type => 'string', | |
27 | enum => ['802.1q', '802.1ad'], | |
28 | default => '802.1q', | |
29 | optional => 1, | |
30 | } | |
20e19696 AD |
31 | }; |
32 | } | |
33 | ||
34 | sub options { | |
35 | ||
36 | return { | |
c2b9c173 | 37 | nodes => { optional => 1}, |
20e19696 | 38 | 'tag' => { optional => 0 }, |
938ebef7 | 39 | 'bridge' => { optional => 0 }, |
823f2e2a | 40 | 'mtu' => { optional => 1 }, |
3dfdc684 | 41 | 'vlan-protocol' => { optional => 1 }, |
20e19696 AD |
42 | }; |
43 | } | |
44 | ||
45 | # Plugin implementation | |
46 | sub generate_sdn_config { | |
ba7ac021 | 47 | my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_; |
20e19696 | 48 | |
3dfdc684 | 49 | my $stag = $plugin_config->{tag}; |
938ebef7 AD |
50 | my $mtu = $plugin_config->{mtu}; |
51 | my $bridge = $plugin_config->{'bridge'}; | |
3dfdc684 AD |
52 | my $vlanprotocol = $plugin_config->{'vlan-protocol'}; |
53 | my $ctag = $vnet->{tag}; | |
54 | my $alias = $vnet->{alias}; | |
20e19696 | 55 | |
3dfdc684 AD |
56 | my $vlan_aware = PVE::Tools::file_read_firstline("/sys/class/net/$bridge/bridge/vlan_filtering"); |
57 | my $is_ovs = 1 if !-d "/sys/class/net/$bridge/brif"; | |
20e19696 | 58 | |
3dfdc684 AD |
59 | my @iface_config = (); |
60 | my $vnet_bridge_ports = ""; | |
61 | ||
62 | if($is_ovs) { | |
63 | ||
64 | #ovs--->ovsintport(dot1q-tunnel tag)------->vlanawarebrige-----(tag)--->vnet | |
65 | ||
66 | $vlanprotocol = "802.1q" if !$vlanprotocol; | |
67 | my $svlan_iface = "sv_".$zoneid; | |
68 | my $zone = "z_$zoneid"; | |
69 | ||
70 | #ovs dot1q-tunnel port | |
71 | @iface_config = (); | |
72 | push @iface_config, "ovs_type OVSIntPort"; | |
73 | push @iface_config, "ovs_bridge $bridge"; | |
74 | push @iface_config, "ovs_options vlan_mode=dot1q-tunnel tag=$stag other_config:qinq-ethtype=$vlanprotocol"; | |
75 | push(@{$config->{$svlan_iface}}, @iface_config) if !$config->{$svlan_iface}; | |
76 | ||
77 | ||
78 | #zone vlan aware bridge | |
79 | @iface_config = (); | |
938ebef7 AD |
80 | push @iface_config, "mtu $mtu" if $mtu; |
81 | push @iface_config, "bridge-stp off"; | |
3dfdc684 | 82 | push @iface_config, "bridge-ports $svlan_iface"; |
938ebef7 AD |
83 | push @iface_config, "bridge-fd 0"; |
84 | push @iface_config, "bridge-vlan-aware yes"; | |
85 | push @iface_config, "bridge-vids 2-4094"; | |
3dfdc684 AD |
86 | push(@{$config->{$zone}}, @iface_config) if !$config->{$zone}; |
87 | ||
88 | $vnet_bridge_ports = "$zone.$ctag"; | |
89 | ||
90 | } elsif ($vlan_aware) { | |
91 | ||
92 | #vlanawarebrige-(tag)----->vlanwarebridge-(tag)----->vnet | |
938ebef7 | 93 | |
3dfdc684 AD |
94 | my $zone = "z_$zoneid"; |
95 | ||
96 | if($vlanprotocol) { | |
97 | @iface_config = (); | |
98 | push @iface_config, "bridge-vlan-protocol $vlanprotocol"; | |
99 | push(@{$config->{$bridge}}, @iface_config) if !$config->{$bridge}; | |
100 | } | |
101 | ||
102 | #zone vlan bridge | |
938ebef7 | 103 | @iface_config = (); |
3dfdc684 AD |
104 | push @iface_config, "mtu $mtu" if $mtu; |
105 | push @iface_config, "bridge-stp off"; | |
106 | push @iface_config, "bridge-ports $bridge.$stag"; | |
107 | push @iface_config, "bridge-fd 0"; | |
108 | push @iface_config, "bridge-vlan-aware yes"; | |
109 | push @iface_config, "bridge-vids 2-4094"; | |
110 | push(@{$config->{$zone}}, @iface_config) if !$config->{$zone}; | |
111 | ||
112 | $vnet_bridge_ports = "$zone.$ctag"; | |
113 | ||
114 | } else { | |
115 | ||
116 | #eth--->eth.x(svlan)--->eth.x.y(cvlan)---->vnet | |
117 | ||
118 | my @bridge_ifaces = (); | |
119 | my $dir = "/sys/class/net/$bridge/brif"; | |
120 | PVE::Tools::dir_glob_foreach($dir, '(((eth|bond)\d+|en[^.]+)(\.\d+)?)', sub { | |
121 | push @bridge_ifaces, $_[0]; | |
122 | }); | |
123 | ||
124 | foreach my $bridge_iface (@bridge_ifaces) { | |
125 | ||
126 | # use named vlan interface to avoid too long names | |
127 | my $svlan_iface = "sv_$vnetid"; | |
128 | my $cvlan_iface = "cv_$vnetid"; | |
129 | ||
130 | #svlan | |
131 | @iface_config = (); | |
132 | push @iface_config, "vlan-raw-device $bridge_iface"; | |
133 | push @iface_config, "vlan-id $stag"; | |
134 | push @iface_config, "vlan-protocol $vlanprotocol" if $vlanprotocol; | |
135 | push(@{$config->{$svlan_iface}}, @iface_config) if !$config->{$svlan_iface}; | |
136 | ||
137 | #cvlan | |
138 | @iface_config = (); | |
139 | push @iface_config, "vlan-raw-device $svlan_iface"; | |
140 | push @iface_config, "vlan-id $ctag"; | |
141 | push(@{$config->{$cvlan_iface}}, @iface_config) if !$config->{$cvlan_iface}; | |
142 | ||
143 | $vnet_bridge_ports .= " $cvlan_iface"; | |
144 | } | |
145 | } | |
146 | ||
147 | #vnet bridge | |
148 | @iface_config = (); | |
149 | push @iface_config, "bridge_ports $vnet_bridge_ports"; | |
150 | push @iface_config, "bridge_stp off"; | |
151 | push @iface_config, "bridge_fd 0"; | |
912fb443 AD |
152 | if($vnet->{vlanaware}) { |
153 | push @iface_config, "bridge-vlan-aware yes"; | |
154 | push @iface_config, "bridge-vids 2-4094"; | |
155 | } | |
3dfdc684 AD |
156 | push @iface_config, "mtu $mtu" if $mtu; |
157 | push @iface_config, "alias $alias" if $alias; | |
158 | push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid}; | |
159 | ||
20e19696 AD |
160 | } |
161 | ||
58433186 AD |
162 | sub status { |
163 | my ($class, $plugin_config, $zone, $id, $vnet, $err_config, $status, $vnet_status, $zone_status) = @_; | |
164 | ||
165 | my $bridge = $plugin_config->{bridge}; | |
166 | $vnet_status->{$id}->{zone} = $zone; | |
167 | $zone_status->{$zone}->{status} = 'available' if !defined($zone_status->{$zone}->{status}); | |
168 | ||
169 | if($err_config) { | |
170 | $vnet_status->{$id}->{status} = 'pending'; | |
171 | $vnet_status->{$id}->{statusmsg} = $err_config; | |
172 | $zone_status->{$zone}->{status} = 'pending'; | |
173 | } elsif ($status->{$bridge}->{status} && $status->{$bridge}->{status} eq 'pass') { | |
174 | $vnet_status->{$id}->{status} = 'available'; | |
175 | } else { | |
176 | $vnet_status->{$id}->{status} = 'error'; | |
177 | $vnet_status->{$id}->{statusmsg} = 'missing bridge'; | |
178 | $zone_status->{$zone}->{status} = 'error'; | |
179 | } | |
180 | } | |
181 | ||
20e19696 AD |
182 | 1; |
183 | ||
184 |