]>
Commit | Line | Data |
---|---|---|
f23633dc AD |
1 | package PVE::Network::SDN::Controllers::BgpPlugin; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::INotify; | |
7 | use PVE::JSONSchema qw(get_standard_option); | |
8 | use PVE::Tools qw(run_command file_set_contents file_get_contents); | |
9 | ||
10 | use PVE::Network::SDN::Controllers::Plugin; | |
11 | use PVE::Network::SDN::Zones::Plugin; | |
12 | use Net::IP; | |
13 | ||
14 | use base('PVE::Network::SDN::Controllers::Plugin'); | |
15 | ||
16 | sub type { | |
17 | return 'bgp'; | |
18 | } | |
19 | ||
20 | sub properties { | |
21 | return { | |
1262519c AD |
22 | 'bgp-multipath-as-path-relax' => { |
23 | type => 'boolean', | |
24 | optional => 1, | |
25 | }, | |
f23633dc AD |
26 | ebgp => { |
27 | type => 'boolean', | |
28 | optional => 1, | |
29 | description => "Enable ebgp. (remote-as external)", | |
30 | }, | |
4083537b AD |
31 | 'ebgp-multihop' => { |
32 | type => 'integer', | |
33 | optional => 1, | |
34 | }, | |
f23633dc AD |
35 | loopback => { |
36 | description => "source loopback interface.", | |
37 | type => 'string' | |
38 | }, | |
39 | node => get_standard_option('pve-node'), | |
40 | }; | |
41 | } | |
42 | ||
43 | sub options { | |
44 | return { | |
45 | 'node' => { optional => 0 }, | |
46 | 'asn' => { optional => 0 }, | |
47 | 'peers' => { optional => 0 }, | |
1262519c | 48 | 'bgp-multipath-as-path-relax' => { optional => 1 }, |
f23633dc | 49 | 'ebgp' => { optional => 1 }, |
4083537b | 50 | 'ebgp-multihop' => { optional => 1 }, |
f23633dc AD |
51 | 'loopback' => { optional => 1 }, |
52 | }; | |
53 | } | |
54 | ||
55 | # Plugin implementation | |
56 | sub generate_controller_config { | |
57 | my ($class, $plugin_config, $controller, $id, $uplinks, $config) = @_; | |
58 | ||
59 | my @peers; | |
60 | @peers = PVE::Tools::split_list($plugin_config->{'peers'}) if $plugin_config->{'peers'}; | |
61 | ||
62 | my $asn = $plugin_config->{asn}; | |
63 | my $ebgp = $plugin_config->{ebgp}; | |
4083537b | 64 | my $ebgp_multihop = $plugin_config->{'ebgp-multihop'}; |
f23633dc | 65 | my $loopback = $plugin_config->{loopback}; |
1262519c AD |
66 | my $multipath_relax = $plugin_config->{'bgp-multipath-as-path-relax'}; |
67 | ||
f23633dc AD |
68 | my $local_node = PVE::INotify::nodename(); |
69 | ||
70 | ||
71 | return if !$asn; | |
72 | return if $local_node ne $plugin_config->{node}; | |
73 | ||
74 | my $bgp = $config->{frr}->{router}->{"bgp $asn"} //= {}; | |
75 | ||
76 | my ($ifaceip, $interface) = PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback); | |
77 | ||
78 | my $remoteas = $ebgp ? "external" : $asn; | |
79 | ||
80 | #global options | |
81 | my @controller_config = ( | |
82 | "bgp router-id $ifaceip", | |
83 | "no bgp default ipv4-unicast", | |
3a46bcb1 | 84 | "coalesce-time 1000" |
f23633dc AD |
85 | ); |
86 | ||
87 | push(@{$bgp->{""}}, @controller_config) if keys %{$bgp} == 0; | |
88 | ||
89 | @controller_config = (); | |
90 | if($ebgp) { | |
f23633dc AD |
91 | push @controller_config, "bgp disable-ebgp-connected-route-check" if $loopback; |
92 | } | |
93 | ||
1262519c AD |
94 | push @controller_config, "bgp bestpath as-path multipath-relax" if $multipath_relax; |
95 | ||
f23633dc AD |
96 | #BGP neighbors |
97 | if(@peers) { | |
98 | push @controller_config, "neighbor BGP peer-group"; | |
99 | push @controller_config, "neighbor BGP remote-as $remoteas"; | |
100 | push @controller_config, "neighbor BGP bfd"; | |
4083537b | 101 | push @controller_config, "neighbor BGP ebgp-multihop $ebgp_multihop" if $ebgp && $ebgp_multihop; |
f23633dc AD |
102 | } |
103 | ||
104 | # BGP peers | |
105 | foreach my $address (@peers) { | |
106 | push @controller_config, "neighbor $address peer-group BGP"; | |
107 | } | |
108 | push(@{$bgp->{""}}, @controller_config); | |
109 | ||
110 | # address-family unicast | |
111 | if (@peers) { | |
112 | my $ipversion = Net::IP::ip_is_ipv6($ifaceip) ? "ipv6" : "ipv4"; | |
113 | my $mask = Net::IP::ip_is_ipv6($ifaceip) ? "/128" : "32"; | |
114 | ||
115 | push(@{$bgp->{"address-family"}->{"$ipversion unicast"}}, "network $ifaceip/$mask") if $loopback; | |
116 | push(@{$bgp->{"address-family"}->{"$ipversion unicast"}}, "neighbor BGP activate"); | |
117 | push(@{$bgp->{"address-family"}->{"$ipversion unicast"}}, "neighbor BGP soft-reconfiguration inbound"); | |
118 | } | |
119 | ||
bbf4e4b1 AD |
120 | if ($loopback) { |
121 | push(@{$config->{frr}->{''}}, "ip prefix-list loopbacks_ips seq 10 permit 0.0.0.0/0 le 32"); | |
122 | push(@{$config->{frr}->{''}}, "ip protocol bgp route-map correct_src"); | |
847f5144 AD |
123 | |
124 | my $routemap_config = []; | |
125 | push @{$routemap_config}, "match ip address prefix-list loopbacks_ips"; | |
126 | push @{$routemap_config}, "set src $ifaceip"; | |
127 | push(@{$config->{frr_routemap}->{'correct_src'}}, $routemap_config); | |
bbf4e4b1 AD |
128 | } |
129 | ||
f23633dc AD |
130 | return $config; |
131 | } | |
132 | ||
133 | sub generate_controller_zone_config { | |
134 | my ($class, $plugin_config, $controller, $controller_cfg, $id, $uplinks, $config) = @_; | |
135 | ||
136 | } | |
137 | ||
138 | sub on_delete_hook { | |
139 | my ($class, $controllerid, $zone_cfg) = @_; | |
140 | ||
141 | # verify that zone is associated to this controller | |
142 | foreach my $id (keys %{$zone_cfg->{ids}}) { | |
143 | my $zone = $zone_cfg->{ids}->{$id}; | |
144 | die "controller $controllerid is used by $id" | |
145 | if (defined($zone->{controller}) && $zone->{controller} eq $controllerid); | |
146 | } | |
147 | } | |
148 | ||
149 | sub on_update_hook { | |
150 | my ($class, $controllerid, $controller_cfg) = @_; | |
151 | ||
152 | # we can only have 1 bgp controller by node | |
153 | my $local_node = PVE::INotify::nodename(); | |
154 | my $controllernb = 0; | |
155 | foreach my $id (keys %{$controller_cfg->{ids}}) { | |
156 | next if $id eq $controllerid; | |
157 | my $controller = $controller_cfg->{ids}->{$id}; | |
158 | next if $controller->{type} ne "bgp"; | |
159 | next if $controller->{node} ne $local_node; | |
160 | $controllernb++; | |
161 | die "only 1 bgp controller can be defined" if $controllernb > 1; | |
162 | } | |
163 | } | |
164 | ||
9cef13e9 AD |
165 | sub generate_controller_rawconfig { |
166 | my ($class, $plugin_config, $config) = @_; | |
167 | return ""; | |
168 | } | |
169 | ||
f23633dc AD |
170 | sub write_controller_config { |
171 | my ($class, $plugin_config, $config) = @_; | |
172 | return; | |
173 | } | |
174 | ||
175 | sub reload_controller { | |
176 | my ($class) = @_; | |
177 | return; | |
178 | } | |
179 | ||
180 | 1; | |
181 | ||
182 |