@@ -46,6 +46,7 @@ use transceiver_controller::{
4646} ;
4747
4848mod v1;
49+ mod v2;
4950
5051api_versions ! ( [
5152 // WHEN CHANGING THE API (part 1 of 2):
@@ -59,6 +60,8 @@ api_versions!([
5960 // | example for the next person.
6061 // v
6162 // (next_int, IDENT),
63+ ( 6 , CONSOLIDATED_V4_ROUTES ) ,
64+ ( 5 , UPLINK_PORTS ) ,
6265 ( 4 , V4_OVER_V6_ROUTES ) ,
6366 ( 3 , ATTACHED_SUBNETS ) ,
6467 ( 2 , DUAL_STACK_NAT_WORKFLOW ) ,
@@ -377,6 +380,34 @@ pub trait DpdApi {
377380 #[ endpoint {
378381 method = POST ,
379382 path = "/route/ipv4" ,
383+ versions = ..VERSION_CONSOLIDATED_V4_ROUTES
384+ } ]
385+ async fn route_ipv4_add_v1 (
386+ rqctx : RequestContext < Self :: Context > ,
387+ update : TypedBody < v2:: Ipv4RouteUpdate > ,
388+ ) -> Result < HttpResponseUpdatedNoContent , HttpError > {
389+ let route = update. into_inner ( ) ;
390+ Self :: route_ipv4_add (
391+ rqctx,
392+ TypedBody :: from ( Ipv4RouteUpdate {
393+ cidr : route. cidr ,
394+ target : RouteTarget :: V4 ( route. target ) ,
395+ replace : route. replace ,
396+ } ) ,
397+ )
398+ . await
399+ }
400+
401+ /**
402+ * Route an IPv4 subnet to a link and a nexthop gateway (IPv4 or IPv6).
403+ *
404+ * This call can be used to create a new single-path route or to add new targets
405+ * to a multipath route.
406+ */
407+ #[ endpoint {
408+ method = POST ,
409+ path = "/route/ipv4" ,
410+ versions = VERSION_CONSOLIDATED_V4_ROUTES ..
380411 } ]
381412 async fn route_ipv4_add (
382413 rqctx : RequestContext < Self :: Context > ,
@@ -392,12 +423,23 @@ pub trait DpdApi {
392423 #[ endpoint {
393424 method = POST ,
394425 path = "/route/ipv4-over-ipv6" ,
395- versions = VERSION_V4_OVER_V6_ROUTES ..,
426+ versions = VERSION_V4_OVER_V6_ROUTES ..VERSION_CONSOLIDATED_V4_ROUTES ,
396427 } ]
397428 async fn route_ipv4_over_ipv6_add (
398429 rqctx : RequestContext < Self :: Context > ,
399430 update : TypedBody < Ipv4OverIpv6RouteUpdate > ,
400- ) -> Result < HttpResponseUpdatedNoContent , HttpError > ;
431+ ) -> Result < HttpResponseUpdatedNoContent , HttpError > {
432+ let route = update. into_inner ( ) ;
433+ Self :: route_ipv4_add (
434+ rqctx,
435+ TypedBody :: from ( Ipv4RouteUpdate {
436+ cidr : route. cidr ,
437+ target : RouteTarget :: V6 ( route. target ) ,
438+ replace : route. replace ,
439+ } ) ,
440+ )
441+ . await
442+ }
401443
402444 /**
403445 * Route an IPv4 subnet to a link and a nexthop gateway.
@@ -408,6 +450,34 @@ pub trait DpdApi {
408450 #[ endpoint {
409451 method = PUT ,
410452 path = "/route/ipv4" ,
453+ versions = ..VERSION_CONSOLIDATED_V4_ROUTES
454+ } ]
455+ async fn route_ipv4_set_v1 (
456+ rqctx : RequestContext < Self :: Context > ,
457+ update : TypedBody < v2:: Ipv4RouteUpdate > ,
458+ ) -> Result < HttpResponseUpdatedNoContent , HttpError > {
459+ let route = update. into_inner ( ) ;
460+ Self :: route_ipv4_set (
461+ rqctx,
462+ TypedBody :: from ( Ipv4RouteUpdate {
463+ cidr : route. cidr ,
464+ target : RouteTarget :: V4 ( route. target ) ,
465+ replace : route. replace ,
466+ } ) ,
467+ )
468+ . await
469+ }
470+
471+ /**
472+ * Route an IPv4 subnet to a link and a nexthop gateway (IPv4 or IPv6).
473+ *
474+ * This call can be used to create a new single-path route or to replace any
475+ * existing routes with a new single-path route.
476+ */
477+ #[ endpoint {
478+ method = PUT ,
479+ path = "/route/ipv4" ,
480+ versions = VERSION_CONSOLIDATED_V4_ROUTES ..
411481 } ]
412482 async fn route_ipv4_set (
413483 rqctx : RequestContext < Self :: Context > ,
@@ -423,12 +493,23 @@ pub trait DpdApi {
423493 #[ endpoint {
424494 method = PUT ,
425495 path = "/route/ipv4-over-ipv6" ,
426- versions = VERSION_V4_OVER_V6_ROUTES ..,
496+ versions = VERSION_V4_OVER_V6_ROUTES ..VERSION_CONSOLIDATED_V4_ROUTES ,
427497 } ]
428498 async fn route_ipv4_over_ipv6_set (
429499 rqctx : RequestContext < Self :: Context > ,
430500 update : TypedBody < Ipv4OverIpv6RouteUpdate > ,
431- ) -> Result < HttpResponseUpdatedNoContent , HttpError > ;
501+ ) -> Result < HttpResponseUpdatedNoContent , HttpError > {
502+ let route = update. into_inner ( ) ;
503+ Self :: route_ipv4_set (
504+ rqctx,
505+ TypedBody :: from ( Ipv4RouteUpdate {
506+ cidr : route. cidr ,
507+ target : RouteTarget :: V6 ( route. target ) ,
508+ replace : route. replace ,
509+ } ) ,
510+ )
511+ . await
512+ }
432513
433514 /**
434515 * Remove all targets for the given subnet
@@ -448,6 +529,32 @@ pub trait DpdApi {
448529 #[ endpoint {
449530 method = DELETE ,
450531 path = "/route/ipv4/{cidr}/{port_id}/{link_id}/{tgt_ip}" ,
532+ versions = ..VERSION_CONSOLIDATED_V4_ROUTES
533+ } ]
534+ async fn route_ipv4_delete_target_v1 (
535+ rqctx : RequestContext < Self :: Context > ,
536+ path : Path < v2:: RouteTargetIpv4Path > ,
537+ ) -> Result < HttpResponseDeleted , HttpError > {
538+ let p = path. into_inner ( ) ;
539+ Self :: route_ipv4_delete_target (
540+ rqctx,
541+ Path :: from ( RouteTargetIpv4Path {
542+ cidr : p. cidr ,
543+ port_id : p. port_id ,
544+ link_id : p. link_id ,
545+ tgt_ip : IpAddr :: V4 ( p. tgt_ip ) ,
546+ } ) ,
547+ )
548+ . await
549+ }
550+
551+ /**
552+ * Remove a single target for the given IPv4 subnet (IPv4 or IPv6 next hop)
553+ */
554+ #[ endpoint {
555+ method = DELETE ,
556+ path = "/route/ipv4/{cidr}/{port_id}/{link_id}/{tgt_ip}" ,
557+ versions = VERSION_CONSOLIDATED_V4_ROUTES ..
451558 } ]
452559 async fn route_ipv4_delete_target (
453560 rqctx : RequestContext < Self :: Context > ,
@@ -988,21 +1095,50 @@ pub trait DpdApi {
9881095 #[ endpoint {
9891096 method = GET ,
9901097 path = "/ports/{port_id}/links/{link_id}/nat_only" ,
1098+ versions = ..VERSION_UPLINK_PORTS
9911099 } ]
9921100 async fn link_nat_only_get (
9931101 rqctx : RequestContext < Self :: Context > ,
9941102 path : Path < LinkPath > ,
1103+ ) -> Result < HttpResponseOk < bool > , HttpError > {
1104+ Self :: link_uplink_get ( rqctx, path) . await
1105+ }
1106+
1107+ /// Return whether a port is intended to carry uplink traffic
1108+ #[ endpoint {
1109+ method = GET ,
1110+ path = "/ports/{port_id}/links/{link_id}/uplink" ,
1111+ versions = VERSION_UPLINK_PORTS ..
1112+ } ]
1113+ async fn link_uplink_get (
1114+ rqctx : RequestContext < Self :: Context > ,
1115+ path : Path < LinkPath > ,
9951116 ) -> Result < HttpResponseOk < bool > , HttpError > ;
9961117
9971118 /// Set whether a port is configured to use drop non-nat traffic
9981119 #[ endpoint {
9991120 method = PUT ,
10001121 path = "/ports/{port_id}/links/{link_id}/nat_only" ,
1122+ versions = ..VERSION_UPLINK_PORTS
10011123 } ]
10021124 async fn link_nat_only_set (
10031125 rqctx : RequestContext < Self :: Context > ,
10041126 path : Path < LinkPath > ,
10051127 body : TypedBody < bool > ,
1128+ ) -> Result < HttpResponseUpdatedNoContent , HttpError > {
1129+ Self :: link_uplink_set ( rqctx, path, body) . await
1130+ }
1131+
1132+ /// Set whether a port is intended to carry uplink traffic
1133+ #[ endpoint {
1134+ method = PUT ,
1135+ path = "/ports/{port_id}/links/{link_id}/uplink" ,
1136+ versions = VERSION_UPLINK_PORTS ..
1137+ } ]
1138+ async fn link_uplink_set (
1139+ rqctx : RequestContext < Self :: Context > ,
1140+ path : Path < LinkPath > ,
1141+ body : TypedBody < bool > ,
10061142 ) -> Result < HttpResponseUpdatedNoContent , HttpError > ;
10071143
10081144 /// Get the event history for the given link.
@@ -2083,15 +2219,15 @@ impl TryFrom<RouteTarget> for Ipv6Route {
20832219 }
20842220}
20852221
2086- /// Represents a new or replacement mapping of a subnet to a single IPv4
2087- /// RouteTarget nexthop target.
2222+ /// Represents a new or replacement mapping of an IPv4 subnet to a single
2223+ /// RouteTarget nexthop target, which may be either IPv4 or IPv6 .
20882224#[ derive( Debug , Clone , Deserialize , Serialize , JsonSchema ) ]
20892225pub struct Ipv4RouteUpdate {
20902226 /// Traffic destined for any address within the CIDR block is routed using
20912227 /// this information.
20922228 pub cidr : Ipv4Net ,
20932229 /// A single Route associated with this CIDR
2094- pub target : Ipv4Route ,
2230+ pub target : RouteTarget ,
20952231 /// Should this route replace any existing route? If a route exists and
20962232 /// this parameter is false, then the call will fail.
20972233 pub replace : bool ,
@@ -2198,7 +2334,8 @@ pub struct SubnetPath {
21982334 pub subnet : IpNet ,
21992335}
22002336
2201- /// Represents a single subnet->target route entry
2337+ /// Represents a single subnet->target route entry with an IPv4 or IPv6
2338+ /// next hop.
22022339#[ derive( Deserialize , Serialize , JsonSchema ) ]
22032340pub struct RouteTargetIpv4Path {
22042341 /// The subnet being routed
@@ -2207,8 +2344,8 @@ pub struct RouteTargetIpv4Path {
22072344 pub port_id : PortId ,
22082345 /// The link to which packets should be sent
22092346 pub link_id : LinkId ,
2210- /// The next hop in the IPv4 route
2211- pub tgt_ip : Ipv4Addr ,
2347+ /// The next hop in the route ( IPv4 or IPv6)
2348+ pub tgt_ip : IpAddr ,
22122349}
22132350
22142351#[ derive( Deserialize , Serialize , JsonSchema ) ]
0 commit comments