Skip to content

Commit fa5f15c

Browse files
authored
Don't add routes or advertise tunnel exit for down links (#514)
1 parent 9509eba commit fa5f15c

File tree

4 files changed

+88
-169
lines changed

4 files changed

+88
-169
lines changed

mg-lower/src/ddm.rs

Lines changed: 5 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,11 @@
44

55
use ddm_admin_client::types::TunnelOrigin;
66
use ddm_admin_client::Client;
7-
use oxnet::{IpNet, Ipv6Net};
8-
use rdb::db::Rib;
9-
use rdb::{Prefix, Prefix4, Prefix6, DEFAULT_ROUTE_PRIORITY};
7+
use oxnet::Ipv6Net;
108
use slog::{error, info, Logger};
11-
use std::{collections::HashSet, net::Ipv6Addr, sync::Arc};
9+
use std::{net::Ipv6Addr, sync::Arc};
1210

13-
use crate::dendrite::RouteHash;
14-
15-
const BOUNDARY_SERVICES_VNI: u32 = 99;
16-
17-
pub(crate) fn update_tunnel_endpoints(
18-
tep: Ipv6Addr, // tunnel endpoint address
19-
client: &Client,
20-
routes: &Rib,
21-
rt: Arc<tokio::runtime::Handle>,
22-
log: &Logger,
23-
) {
24-
let current: HashSet<TunnelOrigin> = match rt
25-
.block_on(async { client.get_originated_tunnel_endpoints().await })
26-
.map(|x| x.into_inner())
27-
{
28-
Ok(x) => x,
29-
Err(e) => {
30-
error!(log, "get originated tunnel endpoints: {e}");
31-
return;
32-
}
33-
}
34-
.into_iter()
35-
.collect();
36-
37-
let target: HashSet<TunnelOrigin> = routes
38-
.iter()
39-
.filter(|(_prefix, path)| !path.is_empty())
40-
.map(|(prefix, _path)| route_to_tunnel(tep, prefix))
41-
.collect();
42-
43-
let to_add = target.difference(&current);
44-
let to_remove = current.difference(&target);
45-
46-
add_tunnel_endpoints(tep, client, to_add.into_iter(), &rt, log);
47-
remove_tunnel_endpoints(client, to_remove.into_iter(), &rt, log);
48-
}
11+
pub(crate) const BOUNDARY_SERVICES_VNI: u32 = 99;
4912

5013
fn ensure_tep_underlay_origin(
5114
client: &Client,
@@ -79,60 +42,7 @@ fn ensure_tep_underlay_origin(
7942
};
8043
}
8144

82-
fn route_to_tunnel(tep: Ipv6Addr, prefix: &Prefix) -> TunnelOrigin {
83-
match prefix {
84-
Prefix::V4(p) => {
85-
TunnelOrigin {
86-
overlay_prefix: oxnet::Ipv4Net::new(p.value, p.length)
87-
.unwrap()
88-
.into(),
89-
boundary_addr: tep,
90-
vni: BOUNDARY_SERVICES_VNI, //TODO?
91-
metric: DEFAULT_ROUTE_PRIORITY, //TODO
92-
}
93-
}
94-
Prefix::V6(p) => {
95-
TunnelOrigin {
96-
overlay_prefix: oxnet::Ipv6Net::new(p.value, p.length)
97-
.unwrap()
98-
.into(),
99-
boundary_addr: tep,
100-
vni: BOUNDARY_SERVICES_VNI, //TODO?
101-
metric: DEFAULT_ROUTE_PRIORITY, //TODO
102-
}
103-
}
104-
}
105-
}
106-
107-
pub(crate) fn add_tunnel_routes(
108-
tep: Ipv6Addr, // tunnel endpoint address
109-
client: &Client,
110-
routes: &HashSet<RouteHash>,
111-
rt: Arc<tokio::runtime::Handle>,
112-
log: &Logger,
113-
) {
114-
let teps: Vec<TunnelOrigin> = routes
115-
.iter()
116-
.map(|rt| {
117-
let pfx = match rt.cidr {
118-
IpNet::V4(p) => Prefix4 {
119-
value: p.prefix(),
120-
length: p.width(),
121-
}
122-
.into(),
123-
IpNet::V6(p) => Prefix6 {
124-
value: p.prefix(),
125-
length: p.width(),
126-
}
127-
.into(),
128-
};
129-
route_to_tunnel(tep, &pfx)
130-
})
131-
.collect();
132-
add_tunnel_endpoints(tep, client, teps.iter(), &rt, log)
133-
}
134-
135-
pub(crate) fn add_tunnel_endpoints<'a, I: Iterator<Item = &'a TunnelOrigin>>(
45+
pub(crate) fn add_tunnel_routes<'a, I: Iterator<Item = &'a TunnelOrigin>>(
13646
tep: Ipv6Addr, // tunnel endpoint address
13747
client: &Client,
13848
routes: I,
@@ -151,38 +61,7 @@ pub(crate) fn add_tunnel_endpoints<'a, I: Iterator<Item = &'a TunnelOrigin>>(
15161
}
15262
}
15363

154-
pub(crate) fn remove_tunnel_routes(
155-
tep: Ipv6Addr, // tunnel endpoint address
156-
client: &Client,
157-
routes: &HashSet<RouteHash>,
158-
rt: Arc<tokio::runtime::Handle>,
159-
log: &Logger,
160-
) {
161-
let teps: Vec<TunnelOrigin> = routes
162-
.iter()
163-
.map(|rt| {
164-
let pfx = match rt.cidr {
165-
IpNet::V4(p) => Prefix4 {
166-
value: p.prefix(),
167-
length: p.width(),
168-
}
169-
.into(),
170-
IpNet::V6(p) => Prefix6 {
171-
value: p.prefix(),
172-
length: p.width(),
173-
}
174-
.into(),
175-
};
176-
route_to_tunnel(tep, &pfx)
177-
})
178-
.collect();
179-
remove_tunnel_endpoints(client, teps.iter(), &rt, log)
180-
}
181-
182-
pub(crate) fn remove_tunnel_endpoints<
183-
'a,
184-
I: Iterator<Item = &'a TunnelOrigin>,
185-
>(
64+
pub(crate) fn remove_tunnel_routes<'a, I: Iterator<Item = &'a TunnelOrigin>>(
18665
client: &Client,
18766
routes: I,
18867
rt: &Arc<tokio::runtime::Handle>,

mg-lower/src/dendrite.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -374,31 +374,6 @@ pub(crate) fn get_routes_for_prefix(
374374
if r.tag != MG_LOWER_TAG {
375375
continue;
376376
}
377-
match link_is_up(dpd, &r.port_id, &r.link_id, &rt) {
378-
Err(e) => {
379-
error!(
380-
log,
381-
"nexthop: {} failed to get link state for {:?}/{:?}: {e}",
382-
r.tgt_ip,
383-
r.port_id,
384-
r.link_id
385-
);
386-
continue;
387-
}
388-
Ok(false) => {
389-
warn!(
390-
log,
391-
"nexthop: {} link {:?}/{:?} is not up, \
392-
not installing route for {:?}",
393-
r.tgt_ip,
394-
r.port_id,
395-
r.link_id,
396-
prefix,
397-
);
398-
continue;
399-
}
400-
Ok(true) => {}
401-
}
402377
match RouteHash::new(
403378
cidr.into(),
404379
r.port_id.clone(),

mg-lower/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ pub enum Error {
77
#[error("dpd error {0}")]
88
Dpd(#[from] dpd_client::Error<dpd_client::types::Error>),
99

10+
#[error("ddm error {0}")]
11+
Ddm(#[from] ddm_admin_client::Error<ddm_admin_client::types::Error>),
12+
1013
#[error("tfport error {0}")]
1114
Tfport(String),
1215

mg-lower/src/lib.rs

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ use crate::dendrite::{
1212
use crate::error::Error;
1313
use ddm::{
1414
add_tunnel_routes, new_ddm_client, remove_tunnel_routes,
15-
update_tunnel_endpoints,
15+
BOUNDARY_SERVICES_VNI,
1616
};
17+
use ddm_admin_client::types::TunnelOrigin;
1718
use ddm_admin_client::Client as DdmClient;
18-
use dendrite::ensure_tep_addr;
19+
use dendrite::{ensure_tep_addr, link_is_up};
1920
use dpd_client::Client as DpdClient;
2021
use mg_common::stats::MgLowerStats as Stats;
2122
use rdb::db::Rib;
22-
use rdb::{Db, Prefix, PrefixChangeNotification};
23-
use slog::{error, info, Logger};
23+
use rdb::{Db, Prefix, PrefixChangeNotification, DEFAULT_ROUTE_PRIORITY};
24+
use slog::{error, info, warn, Logger};
2425
use std::collections::HashSet;
2526
use std::net::Ipv6Addr;
2627
use std::sync::mpsc::{channel, RecvTimeoutError};
@@ -129,13 +130,10 @@ fn full_sync(
129130
// Make sure our tunnel endpoint address is on the switch ASIC
130131
ensure_tep_addr(tep, dpd, rt.clone(), log);
131132

132-
// Announce tunnel endpoints via ddm
133-
update_tunnel_endpoints(tep, ddm, &rib, rt.clone(), log);
134-
135133
// Compute the bestpath for each prefix and synchronize the ASIC routing
136134
// tables with the chosen paths.
137135
for (prefix, _paths) in rib.iter() {
138-
sync_prefix(tep, db.loc_rib(), prefix, dpd, ddm, log, &rt)?;
136+
sync_prefix(tep, &db.loc_rib(), prefix, dpd, ddm, log, &rt)?;
139137
}
140138

141139
Ok(())
@@ -152,23 +150,31 @@ fn handle_change(
152150
rt: Arc<tokio::runtime::Handle>,
153151
) -> Result<(), Error> {
154152
for prefix in notification.changed.iter() {
155-
sync_prefix(tep, db.loc_rib(), prefix, dpd, ddm, log, &rt)?;
153+
sync_prefix(tep, &db.loc_rib(), prefix, dpd, ddm, log, &rt)?;
156154
}
157155

158156
Ok(())
159157
}
160158

161159
fn sync_prefix(
162160
tep: Ipv6Addr,
163-
rib_loc: Rib,
161+
rib_loc: &Rib,
164162
prefix: &Prefix,
165163
dpd: &DpdClient,
166164
ddm: &DdmClient,
167165
log: &Logger,
168166
rt: &Arc<tokio::runtime::Handle>,
169167
) -> Result<(), Error> {
170168
// The current routes that are on the ASIC.
171-
let current = get_routes_for_prefix(dpd, prefix, rt.clone(), log.clone())?;
169+
let dpd_current =
170+
get_routes_for_prefix(dpd, prefix, rt.clone(), log.clone())?;
171+
172+
// The current tunnel routes in ddm
173+
let ddm_current = rt
174+
.block_on(async { ddm.get_originated_tunnel_endpoints().await })?
175+
.into_inner()
176+
.into_iter()
177+
.collect::<HashSet<_>>();
172178

173179
// The best routes in the RIB
174180
let mut best: HashSet<RouteHash> = HashSet::new();
@@ -178,18 +184,74 @@ fn sync_prefix(
178184
}
179185
}
180186

187+
// Remove paths for which the link is down.
188+
best.retain(|x| match link_is_up(dpd, &x.port_id, &x.link_id, rt) {
189+
Err(e) => {
190+
error!(
191+
log,
192+
"sync_prefix: failed to get link state for {:?}/{:?} \
193+
not installing route {:?} -> {:?}: {e}",
194+
x.port_id,
195+
x.link_id,
196+
x.cidr,
197+
x.nexthop,
198+
);
199+
false
200+
}
201+
Ok(false) => {
202+
warn!(
203+
log,
204+
"sync_prefix: link {:?}/{:?} is not up, \
205+
not installing route {:?} -> {:?}",
206+
x.port_id,
207+
x.link_id,
208+
x.cidr,
209+
x.nexthop,
210+
);
211+
false
212+
}
213+
Ok(true) => true,
214+
});
215+
216+
//
217+
// Update the ASIC routing tables
218+
//
219+
181220
// Routes that are in the best set but not on the asic should be added.
182-
let add: HashSet<RouteHash> = best.difference(&current).cloned().collect();
221+
let add: HashSet<RouteHash> =
222+
best.difference(&dpd_current).cloned().collect();
183223

184224
// Routes that are on the asic but not in the best set should be removed.
185-
let del: HashSet<RouteHash> = current.difference(&best).cloned().collect();
225+
let del: HashSet<RouteHash> =
226+
dpd_current.difference(&best).cloned().collect();
186227

187-
// Update DDM tunnel routing
188-
add_tunnel_routes(tep, ddm, &add, rt.clone(), log);
189-
remove_tunnel_routes(tep, ddm, &del, rt.clone(), log);
190-
191-
// Update the ASIC routing tables
192228
update_dendrite(add.iter(), del.iter(), dpd, rt.clone(), log)?;
193229

230+
//
231+
// Update the ddm tunnel advertisements
232+
//
233+
234+
let best_tunnel = best
235+
.clone()
236+
.into_iter()
237+
.map(|x| TunnelOrigin {
238+
boundary_addr: tep,
239+
overlay_prefix: x.cidr,
240+
metric: DEFAULT_ROUTE_PRIORITY,
241+
vni: BOUNDARY_SERVICES_VNI,
242+
})
243+
.collect::<HashSet<_>>();
244+
245+
// Routes that are in the best set but not in ddm should be added.
246+
let add: HashSet<TunnelOrigin> =
247+
best_tunnel.difference(&ddm_current).cloned().collect();
248+
249+
// Routes that are in ddm but not in the best set should be removed.
250+
let del: HashSet<TunnelOrigin> =
251+
ddm_current.difference(&best_tunnel).cloned().collect();
252+
253+
add_tunnel_routes(tep, ddm, add.iter(), rt, log);
254+
remove_tunnel_routes(ddm, del.iter(), rt, log);
255+
194256
Ok(())
195257
}

0 commit comments

Comments
 (0)