I am working on a program that uses the project p4-srv6 (GitHub - netgroup/p4-srv6) as a basis for multihoming. Still, there is a problem, this project uses an older version of P4c before the function clone3() was deprecated, being that function was only used once in the whole project.
So I have been trying to adapt it so that instead of using clone3() it uses “clone_preserving_field_list()” as it is advised. This is the OG code on the main.p4 file:
action clone_to_cpu() {
clone3(CloneType.I2E, CPU_CLONE_SESSION_ID, standard_metadata);
}
The EgressPipeline:
control EgressPipeImpl (inout parsed_headers_t hdr,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
apply {
if (standard_metadata.egress_port == CPU_PORT) { //packets for the controller
hdr.packet_in.setValid();
hdr.packet_in.ingress_port = standard_metadata.ingress_port;
}
if (local_metadata.is_multicast == true
&& standard_metadata.ingress_port == standard_metadata.egress_port) {
mark_to_drop(standard_metadata);
}
}
}
As this is a project that is not mine I tried to change as little as possible, so my idea was to use the struct local_metadata_t (from another project that I am also using), to store all the metadata used by the v1model.p4 so the cloned packet keeps the access to it.
const bit<8> CLONE_FL_1 = 1; //used by INT
const bit<8> CLONE_FL_clone3 = 2;
struct preserving_metadata_t {
@field_list(CLONE_FL_1)
@field_list(CLONE_FL_clone3)
bit<9> ingress_port;
@field_list(CLONE_FL_clone3)
bit<9> egress_spec;
@field_list(CLONE_FL_1)
@field_list(CLONE_FL_clone3)
bit<9> egress_port;
@field_list(CLONE_FL_clone3)
bit<32> clone_spec;
@field_list(CLONE_FL_clone3)
bit<32> instance_type;
@field_list(CLONE_FL_clone3)
bit<1> drop;
@field_list(CLONE_FL_clone3)
bit<16> recirculate_port;
@field_list(CLONE_FL_clone3)
bit<32> packet_length;
@field_list(CLONE_FL_clone3)
bit<32> enq_timestamp;
@field_list(CLONE_FL_clone3)
bit<19> enq_qdepth;
@field_list(CLONE_FL_clone3)
bit<32> deq_timedelta;
@field_list(CLONE_FL_1)
@field_list(CLONE_FL_clone3)
bit<19> deq_qdepth;
@field_list(CLONE_FL_1)
@field_list(CLONE_FL_clone3)
bit<48> ingress_global_timestamp;
@field_list(CLONE_FL_clone3)
bit<48> egress_global_timestamp;
@field_list(CLONE_FL_clone3)
bit<32> lf_field_list;
@field_list(CLONE_FL_clone3)
bit<16> mcast_grp;
@field_list(CLONE_FL_clone3)
bit<32> resubmit_flag;
@field_list(CLONE_FL_clone3)
bit<16> egress_rid;
@field_list(CLONE_FL_clone3)
bit<1> checksum_error;
@field_list(CLONE_FL_clone3)
bit<32> recirculate_flag;
}
typedef bit<32> switch_id_t;
struct int_metadata_t { //used by INT
switch_id_t switch_id;
bit<16> new_bytes;
bit<8> new_words;
bool source;
bool sink;
bool transit;
bit<8> intl4_shim_len;
bit<16> int_shim_len;
}
//Custom metadata definition
struct local_metadata_t { //used by INT
bool is_multicast;
bool skip_l2;
bool xconnect;
ipv6_addr_t next_srv6_sid;
ipv6_addr_t ua_next_hop;
bit<8> ip_proto;
bit<8> icmp_type;
l4_port_t l4_src_port;
l4_port_t l4_dst_port;
bool ipv4_update;
int_metadata_t int_meta;
preserving_metadata_t perserv_meta;
}
right before the cloning is done, I copy all the information into the struct.
action clone_to_cpu() {
local_metadata.perserv_meta.ingress_port = standard_metadata.ingress_port;
local_metadata.perserv_meta.egress_spec = standard_metadata.egress_spec;
local_metadata.perserv_meta.ingress_port = standard_metadata.ingress_port;
local_metadata.perserv_meta.egress_spec = standard_metadata.egress_spec;
local_metadata.perserv_meta.egress_port = standard_metadata.egress_port;
local_metadata.perserv_meta.instance_type = standard_metadata.instance_type;
local_metadata.perserv_meta.packet_length = standard_metadata.packet_length;
local_metadata.perserv_meta.enq_timestamp = standard_metadata.enq_timestamp;
local_metadata.perserv_meta.deq_timedelta = standard_metadata.deq_timedelta;
local_metadata.perserv_meta.deq_qdepth = standard_metadata.deq_qdepth;
local_metadata.perserv_meta.ingress_global_timestamp = standard_metadata.ingress_global_timestamp;
local_metadata.perserv_meta.egress_global_timestamp = standard_metadata.egress_global_timestamp;
local_metadata.perserv_meta.mcast_grp = standard_metadata.mcast_grp;
local_metadata.perserv_meta.egress_rid = standard_metadata.egress_rid;
local_metadata.perserv_meta.checksum_error = standard_metadata.checksum_error;
clone_preserving_field_list(CloneType.I2E, CPU_CLONE_SESSION_ID, CLONE_FL_clone3);
}
I am testing using mininet, and when I compile and run the original project and try to ping between the hosts, those are detected by the topology and the pings work.
On my version, the hosts are not detected and the pings fail, when it comes to the logs from the ONOS controller, there is no difference between the warning logs of the 2 versions.
Some of the warnings are:
1. onos | 17:06:30.114 WARN [ModelCache] DeviceID device:r13 not found as a UiDevice
2. onos | 17:06:48.365 WARN [LinkDiscovery] LLDP Packet failed to validate!
So, does someone know how the conversion from clone3() to clone_preserving_field_list() should be done and why this one is failing?