Skip to content

Commit adc8cdc

Browse files
committed
less malloc on the hot path
The main goal of this commit is to reduce the amount of allocation happening per-packet on the hot path (aka when we have a UFT hit). However, achieving that goal led to refactoring several bits of OPTE. I'm still not 100% happy with this code, but it does reduce allocation, and I do think it's simpler and more robust in some regards. new parsing strategy -------------------- One major refactor was to packet parsing. Up to this point OPTE used a generic parser which allowed either a single frame or a Geneve encapsulated frame. However, as it was part of the generic bits of OPTE, this parser had no way to know the shape of the traffic expected by the network implementation. For example, in the case of oxide-vpc, all outbound traffic is coming from an HVM guest. For such traffic, we only care about parsing one level of headers. The guest may be sending encapsulated packets for all we know, but that's not our concern. Our only concern is that the outermost headers map to a destination in the guest's VPC (or some other reachable network), and so only one level of headers should be parsed. In the old parser we would attempt to parse two levels, which could easily lead to connection issues, confusion, and maybe even some shenanigans. The generic parser also allowed nonsensical combinations. For example, one could pair TCP + Geneve in the outer header. The new parser/packet type limits those combinations a bit further to reduce the possibility of invalid combos. The new parser is inspired (but not equal to) the approach taken in P4: provide a custom parser tailored to your expected network traffic. The new parser provides a generic two-level packet structure: either you have a single frame with typical ARP/ICMP/ULP traffic, or you have said frame encapsulated. That generic structure is filled out by a network-implementation-specific parser. This is achieved by the `NetworkImpl` and `NetworkParser` traits. The `NetworkImpl` trait is meant as a callback mechanism in which the generic bits of OPTE can pass control flow to the network implementation to make decisions that are specific to it. The new parser uses the associated `Parser` type which maps to a `NetworkParser` implementation. This trait provides hooks for inbound/outbound packet parsing. The network implementation uses generic parsing routines provided by `Packet` and provides a `PacketInfo` value describing how it decided to parse the packet. out-of-band packet handling --------------------------- OPTE is highly inspired by Microsoft's VFP. You could even say it's basically a copy of VFP; and I wouldn't argue with you. That said, the entire point of VFP is really two tings: 1. To deal in flows, not packets. 2. To establish a hot path for active flows by caching the header transformations that take place in either direction of an active flow. At the end of the day, this really boils down to optimizing TCP/UDP flows as much as possible, and doing it in a manner that is amenable to pushing down into a more traditional MAT (match-action table). That's the point of the UFT, and the point of phrasing traffic in terms of flows. However, not all traffic needs the absolute best latency, or has high throughput demands. Attempting to shoehorn _all_ traffic into this flow-based model can be quite quirky; along with making the hot-path more complicated and brittle. For those reasons, I introduced a new out-of-band processing action intended for traffic that should be treated on a per-packet basis. This is the purpose of the `NetworkImpl::handle_pkt()` callback. To use it, you set the `Rule` action value to `Action::HandlePacket`. This immediately kicks control flow to the `handle_pkt()` implementation, upon which it can either allow (and modify) the packet, drop the packet, or produce a packet to be hairpinned back in the source's direction. Any rule that specifies this action does not create a flow, does not create a UFT entry, and is handled on a packet-by-packet basis. This has several benefits, including not using hot-path resources (limited UFT entries) for traffic that doesn't need it, and allows more flexible, deep inspection of the packet. The `handle_pkt()` callback _does_ have read access to the UFT tables. While the oxide-vpc implementation is not currently using those arguments, they will become necessary when implementation solutions for dealing with ICMP DU and TE messages, where one has to map a ICMP body to an existing flow. I migrated the ARP handling to this new method. I think this should be taken a step further, and `DataPredicate` should be fully removed and replaced by adding logic to `handle_pkt()`. That is, I think data predicates were probably a mistake, as they break the flow model that OPTE is based on. new header/meta types --------------------- A main alloc culprit revolved around my previous (read poor) decision around header parsing and emitting. In the old code we would use "raw" headers to essentially cast a sequence of bytes into a raw definition of the base header. We would then use this raw header to create a logical `Header` value. These logical values would live with the packet inside `HeaderGroup`. Along with these logical headers, we created header metadata types (e.g. Ipv4Meta), that provided a limited view into the header values. It's this data that is used to express header transformations throughout the Layer pipeline. At the end of processing the logical header values would be "unified" with the metadata values, and then emit new header bytes based on them. This final step was done via the `as_bytes()` method, which did it's job by creating a `Vec<u8>`. These bytes would then be copied into the new header segment. That's a lot of waste. The main fix here is to modify the emit stage to provide a slice of mutable bytes for the logical header type to write its raw bytes to. This eliminates any need to create a `Vec<u8>`. However, I went a bit beyond this and made a large refactor around how headers are dealt with. I'm not sure I'm 100% happy with how it turned out, and in some sense I just kind of shifted things around, but I did also managed to eliminate the unnecessary allocs. That said, it felt more important to land this commit than continue to noodle with this stuff. Here's what I did. First, I replaced the notion of the logical `Header` type with the metadata type. For example, `TcpHdr` is now subsumed by `TcpMeta`. The metadata type is derived from a raw version of the base header: `TcpHdrRaw`. Any options are stored as an array in the `TcpMeta` type. Port/Layer processing was modified to no longer act directly on this metadata, and instead now acts via `PushAction`/`ModifyAction` traits. E.g., TCP defines the `TcpPush` and `TcpMod` types, which allow the processing pipeline to create/modify the source/destination ports, but all other parts of the header are off limits. So during processing, the metadata types are modified based on the limited view of the `HeaderAction` type. At the end of processing, we now have metadata types that represent the logical values of the headers and we need to emit these to raw bytes. That is now done with `PacketSegWriter` and the `emit()` method on each metadata type. For each defined metadata type in the `PacketMeta` type, we attempt to get a mutable slice of the required length from the `PacketSegWriter`, and then call emit passing it that slice. Now, one might wonder: what's the point of creating all these logical values in the metadata type, which represent the various fields in the header type: e.g., why have things like IPv4 TTL or TCP window_size in their respective metadata types? Why not just reuse the bytes that are already in the mblk? We could, but it requires more complicated code. Technically, the network implementation could decide to drop/push/modify headers, and those changes can change the offsets of the headers in the packet. If the offsets don't change, then we can effectively just do a zero-copy form of modification on them, but we need a way to know they haven't shifted. If they have shifted, then we essentially have to copy anyways, and so perhaps doing it up front isn't the worst cost. reuse header mblk when possible ------------------------------- The other culprit of superfluous allocation was the invariable creation of a new mblk for the purpose of emitting the new headers. This commit adds the `hdr_seg()` function, which creates a new header segment only as needed. For oxide-vpc specifically, this avoids the additional allocation on ingress, as we are decaping and modifying, thus there is plenty of room to write the new headers in the existing segment. For the outbound case we still need to allocate, as we need to encapsulate. I think the best way to solve this issue is to have some way for a client of OPTE/xde to negotiate a prefix length. That is, a given network implementation could specify that it would like a certain amount of prefix margin for each outbound packet. The client, if it agrees, would then make sure that each header mblk contains said margin. With this contract negotiated, there would always be enough space in the first segment for writing the new headers. This type of capability would require both mac and viona changes. remove useless dbg calls ------------------------ Another source of wasteful allocation were various `opte::engine::dbg()` calls. These calls were useful when first developing the "external IP hack", but are effectively useless today (especially since the hack is going away). This situation was especially bad because even when `opte_debug` was set to zero, we still payed the allocation cost of `format!`. reduced cost of some SDT probes -------------------------------- Another issue we currently have is around SDT probes: we still do the work even if the probe is not enabled (AFAIK there is no "is enabled" parlance for SDT probes). This is especially painful for any probe site that creates a new CString on the fly (even more so because often it first allocates a String, and then allocates a new CString based on that). This issue is documented more in opte#259. I made the following changes to reduce the cost of SDT probes in the hot path. * Use an integer instead of string to pass `Direction` value, saving an alloc for each probe site. * Changed `Layer` names to `&'static str` to avoid unnecessary alloc when returning error. * Add `Layer.ft_cstr` and `Layer.rt_cstr` to avoid unnecessary alloc. * Removed the `ht_probe()` call from the processing hot-path (UFT hit). It was a bit redundant as you get the same info via the port-process probes; and it means less work in the hot path. replace Vec seg list with heapless Vec -------------------------------------- I replaced the `PacketSeg` vec with a heapless vec, eliminating an allocation per packet. At the moment this list is limited to 4 segments and there is some `unwrap()` that could cause crashes if this turns out not to be enough. misc. changes ------------- * Sprinkle various `#[inline]` attributes on hot functions based on some DTrace investigation. Some of these took, some didn't. * Drop the `state` field from `PacketReader`, it no longer serves any purpose. * Update `Protocol` and `EtherType` to not use `TryFrom`. Instead, they now represent either a protocol or ether type OPTE is interested in, or it's deemed "unknown" and the raw value is stored instead. * Rework the guest-loopback code in regards to the ext-ip-hack in order to save some redundant work. * Modified `RawHeader` trait to just have `new_mut()`: aka a zero-copy, mutable type over the underlying header bytes. * Replaced use of `EtherAddr` with `MacAddr` in some places. The goal is to eventually get rid of `EtherAddr`. * Modified `GeneveHdrRaw` to include it's associated UDP header as well. * Eliminated a bunch of unused macros.
1 parent 1704876 commit adc8cdc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+5499
-5477
lines changed

dtrace/common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@
4848
svar = strjoin(svar, substr(lltostr(evar[4], 16), 2)); \
4949
svar = strjoin(svar, ":"); \
5050
svar = strjoin(svar, substr(lltostr(evar[5], 16), 2));
51+
52+
/* Direction
53+
*
54+
* 1 = Inbound
55+
* 2 = Outbound
56+
*/
57+
#define DIR_STR(dir) ((dir) == 1 ? "IN" : "OUT")

dtrace/lib/common.d

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@ typedef struct flow_id_sdt_arg {
1515
typedef struct rule_match_sdt_arg {
1616
char *port;
1717
char *layer;
18-
char *dir;
18+
uintptr_t dir;
1919
flow_id_sdt_arg_t *flow;
2020
char *rule_type;
2121
} rule_match_sdt_arg_t;
2222

2323
typedef struct rule_no_match_sdt_arg {
2424
char *port;
2525
char *layer;
26-
char *dir;
26+
uintptr_t dir;
2727
flow_id_sdt_arg_t *flow;
2828
} rule_no_match_sdt_arg_t;
2929

3030
typedef struct ht_run_sdt_arg {
3131
char *port;
3232
char *loc;
33-
char *dir;
33+
uintptr_t dir;
3434
flow_id_sdt_arg_t *flow_before;
3535
flow_id_sdt_arg_t *flow_after;
3636
} ht_run_sdt_arg_t;

dtrace/opte-bad-packet.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ BEGIN {
1515

1616
bad-packet {
1717
this->port = stringof(arg0);
18-
this->dir = stringof(arg1);
18+
this->dir = DIR_STR(arg1);
1919
this->mblk = arg2;
2020
this->msg = stringof(arg3);
2121

dtrace/opte-gen-desc-fail.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ BEGIN {
1616
gen-desc-fail {
1717
this->port = stringof(arg0);
1818
this->layer = stringof(arg1);
19-
this->dir = stringof(arg2);
19+
this->dir = DIR_STR(arg2);
2020
this->flow = (flow_id_sdt_arg_t *)arg3;
2121
this->msg = stringof(arg4);
2222
this->af = this->flow->af;

dtrace/opte-gen-ht-fail.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ BEGIN {
1717
gen-ht-fail {
1818
this->port = stringof(arg0);
1919
this->layer = stringof(arg1);
20-
this->dir = stringof(arg2);
20+
this->dir = DIR_STR(arg2);
2121
this->flow = (flow_id_sdt_arg_t *)arg3;
2222
this->msg = stringof(arg4);
2323
this->af = this->flow->af;

dtrace/opte-ht.d

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
/*
22
* Track Header Transformations as they happen.
33
*
4+
* This only applies to header transformations which occur as part of
5+
* layer/rule processing. If you are interested in flow modification
6+
* in the hot path, see the opte-port-process script.
7+
*
48
* dtrace -L ./lib -I . -Cqs ./opte-ht.d
59
*/
610
#include "common.h"
@@ -15,7 +19,7 @@ BEGIN {
1519

1620
ht-run {
1721
this->ht = (ht_run_sdt_arg_t*)arg0;
18-
this->dir = stringof(this->ht->dir);
22+
this->dir = DIR_STR(this->ht->dir);
1923
this->port = stringof(this->ht->port);
2024
this->loc = stringof(this->ht->loc);
2125
this->before = this->ht->flow_before;

dtrace/opte-layer-process.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ BEGIN {
1818
}
1919

2020
layer-process-return {
21-
this->dir = stringof(arg0);
21+
this->dir = DIR_STR(arg0);
2222
this->port = stringof(arg1);
2323
this->layer = stringof(arg2);
2424
this->flow_before = (flow_id_sdt_arg_t *)arg3;

dtrace/opte-port-process.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ BEGIN {
1616
}
1717

1818
port-process-return {
19-
this->dir = stringof(arg0);
19+
this->dir = DIR_STR(arg0);
2020
this->name = stringof(arg1);
2121
this->flow_before = (flow_id_sdt_arg_t *)arg2;
2222
this->flow_after = (flow_id_sdt_arg_t *)arg3;

dtrace/opte-rule-match.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ rule-match {
1818
this->port = stringof(this->match->port);
1919
this->layer = stringof(this->match->layer);
2020
this->flow = this->match->flow;
21-
this->dir = stringof(this->match->dir);
21+
this->dir = DIR_STR(this->match->dir);
2222
this->af = this->flow->af;
2323
num++;
2424

@@ -44,7 +44,7 @@ rule-match /this->af == AF_INET6/ {
4444
rule-no-match {
4545
this->no_match = (rule_no_match_sdt_arg_t *)arg0;
4646
this->flow = this->no_match->flow;
47-
this->dir = stringof(this->no_match->dir);
47+
this->dir = DIR_STR(this->no_match->dir);
4848
this->layer = stringof(this->no_match->layer);
4949
this->af = this->flow->af;
5050
num++;

dtrace/opte-uft-invaildate.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ BEGIN {
1919
}
2020

2121
flow-entry-invalidated {
22-
this->dir = stringof(arg0);
22+
this->dir = DIR_STR(arg0);
2323
this->port = stringof(arg1);
2424
this->flow = (flow_id_sdt_arg_t *)arg2;
2525
this->epoch = arg3;

illumos-sys-hdrs/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,14 @@ pub union KStatNamedValue {
117117
}
118118

119119
impl core::ops::AddAssign<u64> for KStatNamedValue {
120+
#[inline]
120121
fn add_assign(&mut self, other: u64) {
121122
unsafe { self._u64 += other };
122123
}
123124
}
124125

125126
impl core::ops::SubAssign<u64> for KStatNamedValue {
127+
#[inline]
126128
fn sub_assign(&mut self, other: u64) {
127129
unsafe { self._u64 -= other };
128130
}
@@ -179,8 +181,8 @@ pub struct kmutex_t {
179181
#[derive(Debug)]
180182
pub struct dblk_t {
181183
pub db_frtnp: *const c_void, // imprecise
182-
pub db_base: *const c_uchar,
183-
pub db_lim: *const c_uchar,
184+
pub db_base: *mut c_uchar,
185+
pub db_lim: *mut c_uchar,
184186
pub db_ref: c_uchar,
185187
pub db_type: c_uchar,
186188
pub db_flags: c_uchar,
@@ -202,8 +204,8 @@ impl Default for dblk_t {
202204
fn default() -> Self {
203205
dblk_t {
204206
db_frtnp: ptr::null(),
205-
db_base: ptr::null(),
206-
db_lim: ptr::null(),
207+
db_base: ptr::null_mut(),
208+
db_lim: ptr::null_mut(),
207209
db_ref: 0,
208210
db_type: 0,
209211
db_flags: 0,

opte-api/src/encap.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ pub struct Vni {
3333
inner: [u8; 3],
3434
}
3535

36+
impl Default for Vni {
37+
fn default() -> Self {
38+
Vni::new(0u32).unwrap()
39+
}
40+
}
41+
3642
impl From<Vni> for u32 {
3743
fn from(vni: Vni) -> u32 {
3844
let bytes = vni.inner;

opte-api/src/ip.rs

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -222,74 +222,76 @@ impl SubnetRouterPair {
222222
}
223223

224224
/// An IP protocol value.
225-
///
226-
/// TODO repr(u8)?
227-
#[repr(C)]
225+
#[repr(u8)]
228226
#[derive(
229227
Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
230228
)]
231229
pub enum Protocol {
232-
ICMP = 0x1,
233-
IGMP = 0x2,
234-
TCP = 0x6,
235-
UDP = 0x11,
236-
ICMPv6 = 0x3A,
237-
Reserved = 0xFF,
230+
ICMP,
231+
IGMP,
232+
TCP,
233+
UDP,
234+
ICMPv6,
235+
Unknown(u8),
238236
}
239237

238+
pub const PROTO_ICMP: u8 = 0x1;
239+
pub const PROTO_IGMP: u8 = 0x2;
240+
pub const PROTO_TCP: u8 = 0x6;
241+
pub const PROTO_UDP: u8 = 0x11;
242+
pub const PROTO_ICMPV6: u8 = 0x3A;
243+
240244
impl Default for Protocol {
241245
fn default() -> Self {
242-
Protocol::Reserved
246+
Self::Unknown(255)
243247
}
244248
}
245249

246250
impl Display for Protocol {
247251
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248252
match self {
249-
Protocol::ICMP => write!(f, "ICMP"),
250-
Protocol::IGMP => write!(f, "IGMP"),
251-
Protocol::TCP => write!(f, "TCP"),
252-
Protocol::UDP => write!(f, "UDP"),
253-
Protocol::ICMPv6 => write!(f, "ICMPv6"),
254-
Protocol::Reserved => write!(f, "Reserved"),
253+
Self::ICMP => write!(f, "ICMP"),
254+
Self::IGMP => write!(f, "IGMP"),
255+
Self::TCP => write!(f, "TCP"),
256+
Self::UDP => write!(f, "UDP"),
257+
Self::ICMPv6 => write!(f, "ICMPv6"),
258+
Self::Unknown(_) => write!(f, "Unknown"),
255259
}
256260
}
257261
}
258262

259-
impl TryFrom<u8> for Protocol {
260-
type Error = String;
261-
262-
fn try_from(proto: u8) -> core::result::Result<Self, Self::Error> {
263+
impl From<u8> for Protocol {
264+
fn from(proto: u8) -> Self {
263265
match proto {
264-
0x1 => Ok(Protocol::ICMP),
265-
0x2 => Ok(Protocol::IGMP),
266-
0x6 => Ok(Protocol::TCP),
267-
0x11 => Ok(Protocol::UDP),
268-
0x3A => Ok(Protocol::ICMPv6),
269-
proto => Err(format!("unhandled IP protocol: 0x{:X}", proto)),
266+
PROTO_ICMP => Self::ICMP,
267+
PROTO_IGMP => Self::IGMP,
268+
PROTO_TCP => Self::TCP,
269+
PROTO_UDP => Self::UDP,
270+
PROTO_ICMPV6 => Self::ICMPv6,
271+
_ => Self::Unknown(proto),
270272
}
271273
}
272274
}
273275

274-
impl TryFrom<smoltcp::wire::IpProtocol> for Protocol {
275-
type Error = String;
276-
277-
fn try_from(
278-
proto: smoltcp::wire::IpProtocol,
279-
) -> core::result::Result<Self, Self::Error> {
280-
use smoltcp::wire::IpProtocol::*;
276+
impl From<Protocol> for u8 {
277+
fn from(proto: Protocol) -> u8 {
281278
match proto {
282-
Icmp => Ok(Protocol::ICMP),
283-
Igmp => Ok(Protocol::IGMP),
284-
Tcp => Ok(Protocol::TCP),
285-
Udp => Ok(Protocol::UDP),
286-
Icmpv6 => Ok(Protocol::ICMPv6),
287-
Unknown(x) if x == 0xFF => Ok(Protocol::Reserved),
288-
_ => Err(format!("unhandled IP protocol: 0x{:X}", u8::from(proto))),
279+
Protocol::ICMP => PROTO_ICMP,
280+
Protocol::IGMP => PROTO_IGMP,
281+
Protocol::TCP => PROTO_TCP,
282+
Protocol::UDP => PROTO_UDP,
283+
Protocol::ICMPv6 => PROTO_ICMPV6,
284+
Protocol::Unknown(v) => v,
289285
}
290286
}
291287
}
292288

289+
impl From<smoltcp::wire::IpProtocol> for Protocol {
290+
fn from(proto: smoltcp::wire::IpProtocol) -> Self {
291+
Self::from(u8::from(proto))
292+
}
293+
}
294+
293295
impl From<Protocol> for smoltcp::wire::IpProtocol {
294296
fn from(proto: Protocol) -> smoltcp::wire::IpProtocol {
295297
use smoltcp::wire::IpProtocol::*;
@@ -299,7 +301,7 @@ impl From<Protocol> for smoltcp::wire::IpProtocol {
299301
Protocol::TCP => Tcp,
300302
Protocol::UDP => Udp,
301303
Protocol::ICMPv6 => Icmpv6,
302-
Protocol::Reserved => Unknown(0xFF),
304+
Protocol::Unknown(proto) => Unknown(proto),
303305
}
304306
}
305307
}
@@ -366,10 +368,15 @@ impl Ipv4Addr {
366368
pub const LOCAL_BCAST: Self = Self { inner: [255; 4] };
367369

368370
/// Return the bytes of the address.
371+
#[inline]
369372
pub fn bytes(&self) -> [u8; 4] {
370373
self.inner
371374
}
372375

376+
pub const fn from_const(bytes: [u8; 4]) -> Self {
377+
Self { inner: bytes }
378+
}
379+
373380
/// Return the address after applying the network mask.
374381
pub fn mask(mut self, mask: u8) -> Result<Self, String> {
375382
if mask > 32 {
@@ -486,6 +493,18 @@ impl AsRef<[u8]> for Ipv4Addr {
486493
}
487494
}
488495

496+
impl AsRef<[u8; 4]> for Ipv4Addr {
497+
fn as_ref(&self) -> &[u8; 4] {
498+
&self.inner
499+
}
500+
}
501+
502+
impl From<Ipv4Addr> for [u8; 4] {
503+
fn from(ip: Ipv4Addr) -> [u8; 4] {
504+
ip.inner
505+
}
506+
}
507+
489508
impl Deref for Ipv4Addr {
490509
type Target = [u8];
491510
fn deref(&self) -> &Self::Target {
@@ -495,7 +514,16 @@ impl Deref for Ipv4Addr {
495514

496515
/// An IPv6 address.
497516
#[derive(
498-
Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize,
517+
Clone,
518+
Copy,
519+
Debug,
520+
Default,
521+
Eq,
522+
Ord,
523+
PartialEq,
524+
PartialOrd,
525+
Serialize,
526+
Deserialize,
499527
)]
500528
pub struct Ipv6Addr {
501529
inner: [u8; 16],

opte-api/src/lib.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ pub use ulp::*;
5656
///
5757
/// We rely on CI and the check-api-version.sh script to verify that
5858
/// this number is incremented anytime the oxide-api code changes.
59-
pub const API_VERSION: u64 = 18;
59+
pub const API_VERSION: u64 = 19;
6060

6161
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
6262
pub enum Direction {
63-
In,
64-
Out,
63+
In = 1,
64+
Out = 2,
6565
}
6666

6767
impl core::str::FromStr for Direction {
@@ -87,24 +87,6 @@ impl Display for Direction {
8787
}
8888
}
8989

90-
impl From<Direction> for illumos_sys_hdrs::uintptr_t {
91-
fn from(dir: Direction) -> Self {
92-
match dir {
93-
Direction::In => 0,
94-
Direction::Out => 1,
95-
}
96-
}
97-
}
98-
99-
impl Direction {
100-
pub fn cstr_raw(&self) -> *const illumos_sys_hdrs::c_char {
101-
match self {
102-
Self::In => b"in\0".as_ptr() as *const illumos_sys_hdrs::c_char,
103-
Self::Out => b"out\0".as_ptr() as *const illumos_sys_hdrs::c_char,
104-
}
105-
}
106-
}
107-
10890
/// Set the underlay devices used by the xde kernel module
10991
#[derive(Clone, Debug, Serialize, Deserialize)]
11092
pub struct SetXdeUnderlayReq {

0 commit comments

Comments
 (0)