-
Notifications
You must be signed in to change notification settings - Fork 10
Open
Labels
multicastMulticast-related feature/implMulticast-related feature/impl
Description
With the additional Geneve option added as part of Multicast replication in oxidecomputer/dendrite#14, we need to update the Geneve engine in OPTE to parse and set this option.
Here's the P4 code showing the additions:
const bit<7> GENEVE_OPT_OXIDE_MCAST = 0x01;/* Geneve option for an `mcast_tag`.
* This is a 2-bit field that indicates the type of
* multicast traffic:
* 0 - Replicate packets to ports set for external multicast traffic
* 1 - Replicate packets to ports set for underlay multicast traffic
* 2 - Replicate packets to ports set for underlay and external multicast
traffic (bifurcated)
*
* The rest of the option is reserved.
*/
header geneve_opt_mcast_h {
bit<2> mcast_tag;
bit<30> reserved;
}struct geneve_opt_headers_t {
geneve_opt_h ox_external_tag;
geneve_opt_h ox_external_tag;
// Multicast-specific options
geneve_opt_mcast_h ox_mcast_tag;
}Here's a test helper used in packet testing to generate the option as part of a Geneve (encapsulated) packet:
/// Build a Geneve packet with a possible multicast tag.
pub fn gen_geneve_packet_with_mcast_tag(
src: Endpoint,
dst: Endpoint,
inner_type: u16,
vni: u32,
tag_ingress: bool,
mcast_tag: Option<u8>, // New parameter for multicast tag
payload: &[u8],
) -> Packet {
let udp_stack = match src.get_ip("src").unwrap() {
IpAddr::V4(_) => {
vec![inner_type, ipv4::IPPROTO_UDP.into(), eth::ETHER_IPV4]
}
IpAddr::V6(_) => {
vec![inner_type, ipv6::IPPROTO_UDP.into(), eth::ETHER_IPV6]
}
};
let mut pkt = Packet::gen(src, dst, udp_stack, Some(payload)).unwrap();
let geneve = pkt.hdrs.geneve_hdr.as_mut().unwrap();
geneve.vni = vni;
match (tag_ingress, mcast_tag) {
(true, Some(tag)) if tag < 3 => {
geneve.opt_len = 2;
// Multicast tag option
#[rustfmt::skip]
geneve.options.extend_from_slice(&[
// First 2 bytes: Geneve option class (0x0129)
// The OXIDE vendor-specific class identifier
0x01, 0x29,
// Third byte: Critical bit (0) + Option type (1)
// Type 1 represents multicast tagged packets
0x01,
// Fourth byte: Option(s) length
0x01,
// Fifth byte: Tag value (encoded in the data)
(tag & 0x03) << 6,
// Sixth byte: reserved
0x00,
// Seventh byte
0x00,
// Eighth byte
0x00,
]);
let extra_bytes = geneve.options.len() as u16;
match src.get_ip("src").unwrap() {
IpAddr::V4(_) => {
pkt.hdrs.ipv4_hdr.as_mut().unwrap().ipv4_total_len +=
extra_bytes
}
IpAddr::V6(_) => {
pkt.hdrs.ipv6_hdr.as_mut().unwrap().ipv6_payload_len +=
extra_bytes
}
}
pkt.hdrs.udp_hdr.as_mut().unwrap().udp_len += extra_bytes;
}
(true, Some(_)) => {
// Multicast tag is not valid
panic!("Multicast tag must be less than 3");
}
(true, None) => {
// External packet option
geneve.opt_len = 1;
#[rustfmt::skip]
geneve.options.extend_from_slice(&[
// First 2 bytes: Geneve option class (0x0129)
// The OXIDE vendor-specific class identifier
0x01, 0x29,
// Third byte: Critical bit (0) + Option type (1)
0x00,
// reserved + body len
0x00,
]);
let extra_bytes = geneve.options.len() as u16;
match src.get_ip("src").unwrap() {
IpAddr::V4(_) => {
pkt.hdrs.ipv4_hdr.as_mut().unwrap().ipv4_total_len +=
extra_bytes
}
IpAddr::V6(_) => {
pkt.hdrs.ipv6_hdr.as_mut().unwrap().ipv6_payload_len +=
extra_bytes
}
}
pkt.hdrs.udp_hdr.as_mut().unwrap().udp_len += extra_bytes;
}
_ => {}
}
pkt
}Metadata
Metadata
Assignees
Labels
multicastMulticast-related feature/implMulticast-related feature/impl