From 2d59c4b3d563ca272562836503f08a5ecadd8f8c Mon Sep 17 00:00:00 2001 From: Marian Pritsak Date: Sat, 2 Oct 2021 03:46:59 +0300 Subject: [PATCH] Add pipeline definition Signed-off-by: Marian Pritsak --- sirius-pipeline/.gitignore | 1 + sirius-pipeline/sirius_acl.p4 | 67 ++++++++++ sirius-pipeline/sirius_conntrack.p4 | 81 ++++++++++++ sirius-pipeline/sirius_headers.p4 | 94 ++++++++++++++ sirius-pipeline/sirius_inbound.p4 | 91 +++++++++++++ sirius-pipeline/sirius_metadata.p4 | 37 ++++++ sirius-pipeline/sirius_outbound.p4 | 122 +++++++++++++++++ sirius-pipeline/sirius_parser.p4 | 107 +++++++++++++++ sirius-pipeline/sirius_pipeline.p4 | 159 +++++++++++++++++++++++ sirius-pipeline/sirius_service_tunnel.p4 | 42 ++++++ sirius-pipeline/sirius_vxlan.p4 | 87 +++++++++++++ 11 files changed, 888 insertions(+) create mode 100644 sirius-pipeline/.gitignore create mode 100644 sirius-pipeline/sirius_acl.p4 create mode 100644 sirius-pipeline/sirius_conntrack.p4 create mode 100644 sirius-pipeline/sirius_headers.p4 create mode 100644 sirius-pipeline/sirius_inbound.p4 create mode 100644 sirius-pipeline/sirius_metadata.p4 create mode 100644 sirius-pipeline/sirius_outbound.p4 create mode 100644 sirius-pipeline/sirius_parser.p4 create mode 100644 sirius-pipeline/sirius_pipeline.p4 create mode 100644 sirius-pipeline/sirius_service_tunnel.p4 create mode 100644 sirius-pipeline/sirius_vxlan.p4 diff --git a/sirius-pipeline/.gitignore b/sirius-pipeline/.gitignore new file mode 100644 index 000000000..bf4246a12 --- /dev/null +++ b/sirius-pipeline/.gitignore @@ -0,0 +1 @@ +sirius_pipeline.bmv2/ diff --git a/sirius-pipeline/sirius_acl.p4 b/sirius-pipeline/sirius_acl.p4 new file mode 100644 index 000000000..67c5210e8 --- /dev/null +++ b/sirius-pipeline/sirius_acl.p4 @@ -0,0 +1,67 @@ +#ifndef _SIRIUS_ACL_P4_ +#define _SIRIUS_ACL_P4_ + +#include "sirius_headers.p4" + +match_kind { + /* list of ternary values + A/A_len,B/_B-len,... + if empty, then don't care + */ + list, + /* Also possibly range_list - a-b,c-d,... */ + range_list +} + +#define ACL_STAGE(table_name) \ + direct_counter(CounterType.packets_and_bytes) ## table_name ##_counter; \ + table table_name { \ + key = { \ + meta.eni : exact @name("meta.eni:eni"); \ + hdr.ipv4.dst_addr : list @name("hdr.ipv4.dst_addr:dip"); \ + hdr.ipv4.src_addr : list @name("hdr.ipv4.src_addr:sip"); \ + hdr.ipv4.protocol : list @name("hdr.ipv4.src_addr:protocol"); \ + hdr.tcp.src_port : range_list @name("hdr.tcp.src_port:sport"); \ + hdr.tcp.dst_port : range_list @name("hdr.tcp.dst_port:dport"); \ + } \ + actions = { \ + permit; \ + permit_and_continue; \ + deny; \ + deny_and_continue; \ + } \ + default_action = deny; \ + counters = ## table_name ##_counter; \ + } + +#define ACL_STAGE_APPLY(table_name) \ + switch (table_name.apply().action_run) { \ + permit: {return;} \ + deny: {return;} \ + } + +/* + * This control results in a new set of tables every time + * it is applied, i. e. inbound ACL tables are different + * from outbound, and API will be generated for each of them + */ +control acl(inout headers_t hdr, + inout metadata_t meta, + inout standard_metadata_t standard_metadata) +{ + action permit() {} + action permit_and_continue() {} + action deny() {meta.dropped = true;} + action deny_and_continue() {meta.dropped = true;} + +ACL_STAGE(stage1) +ACL_STAGE(stage2) +ACL_STAGE(stage3) + + apply { +ACL_STAGE_APPLY(stage1) +ACL_STAGE_APPLY(stage2) +ACL_STAGE_APPLY(stage3) + } +} +#endif /* _SIRIUS_ACL_P4_ */ diff --git a/sirius-pipeline/sirius_conntrack.p4 b/sirius-pipeline/sirius_conntrack.p4 new file mode 100644 index 000000000..8502032f0 --- /dev/null +++ b/sirius-pipeline/sirius_conntrack.p4 @@ -0,0 +1,81 @@ +#ifndef _SIRIUS_CONNTRACK_P4_ +#define _SIRIUS_CONNTRACK_P4_ + +#include "sirius_headers.p4" + +#ifdef STATEFUL_P4 + +state_context ConntrackCtx { +} + +state_graph ConnGraphOut(inout state_context flow_ctx, + in headers_t headers, + in standard_metadata_t standard_metadata) +{ + state START { + /* Only for new connections */ + if (!headers.tcp.isValid() || headers.tcp.flags != 0x2 /* SYN */) { + return; + } + + if (meta.direction == INBOUND) { + transition ALLOW; + } + } + + state ALLOW { + meta.conntrack_data.allow_out = true; + + /* Remove connection based on TCP flags */ + if (headers.tcp.flags & 0x101 /* FIN/RST */) { + transition START; + } + } +} + +state_graph ConnGraphIn(inout state_context flow_ctx, + in headers_t headers, + in standard_metadata_t standard_metadata) +{ + state START { + /* Only for new connections */ + if (!headers.tcp.isValid() || headers.tcp.flags != 0x2 /* SYN */) { + return; + } + + if (meta.direction == OUTBOUND) { + transition ALLOW; + } + } + + state ALLOW { + meta.conntrack_data.allow_in = true; + + /* Remove connection based on TCP flags */ + if (headers.tcp.flags & 0x101 /* FIN/RST */) { + transition START; + } + } +} + +state_table ConntrackOut +{ + flow_key[0] = {hdr.ipv4.src, hdr.ipv4.dst , hdr.ipv4.proto, hdr.l4.src_port, hdr.l4.dst_port, meta.eni}; + flow_key[1] = {hdr.ipv4.dst, hdr.ipv4.src , hdr.ipv4.proto, hdr.l4.dst_port, hdr.l4.src_port, meta.eni}; + eviction_policy = LRU; + context = ConntrackCtx; + graph = ConnGraphOut(ConntrackCtx, hdr, standard_metadata); +} + +state_table ConntrackIn +{ + flow_key[0] = {hdr.ipv4.src, hdr.ipv4.dst , hdr.ipv4.proto, hdr.l4.src_port, hdr.l4.dst_port, meta.eni}; + flow_key[1] = {hdr.ipv4.dst, hdr.ipv4.src , hdr.ipv4.proto, hdr.l4.dst_port, hdr.l4.src_port, meta.eni}; + eviction_policy = LRU; + context = ConntrackCtx; + graph = ConnGraphIn(ConntrackCtx, hdr, standard_metadata); +} + +#endif /* STATEFUL_P4 */ + +#endif /* _SIRIUS_CONNTRACK_P4_ */ diff --git a/sirius-pipeline/sirius_headers.p4 b/sirius-pipeline/sirius_headers.p4 new file mode 100644 index 000000000..dfadb5317 --- /dev/null +++ b/sirius-pipeline/sirius_headers.p4 @@ -0,0 +1,94 @@ +#ifndef _SIRIUS_HEADERS_P4_ +#define _SIRIUS_HEADERS_P4_ + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; +typedef bit<128> IPv6Address; + +header ethernet_t { + EthernetAddress dst_addr; + EthernetAddress src_addr; + bit<16> ether_type; +} + +const bit<16> ETHER_HDR_SIZE=112/8; + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> total_len; + bit<16> identification; + bit<3> flags; + bit<13> frag_offset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdr_checksum; + IPv4Address src_addr; + IPv4Address dst_addr; +} + +const bit<16> IPV4_HDR_SIZE=160/8; + +header udp_t { + bit<16> src_port; + bit<16> dst_port; + bit<16> length; + bit<16> checksum; +} + +const bit<16> UDP_HDR_SIZE=64/8; + +header vxlan_t { + bit<8> flags; + bit<24> reserved; + bit<24> vni; + bit<8> reserved_2; +} + +const bit<16> VXLAN_HDR_SIZE=64/8; + +header tcp_t { + bit<16> src_port; + bit<16> dst_port; + bit<32> seq_no; + bit<32> ack_no; + bit<4> data_offset; + bit<3> res; + bit<3> ecn; + bit<6> flags; + bit<16> window; + bit<16> checksum; + bit<16> urgent_ptr; +} + +const bit<16> TCP_HDR_SIZE=160/8; + +header ipv6_t { + bit<4> version; + bit<8> traffic_class; + bit<20> flow_label; + bit<16> payload_length; + bit<8> next_header; + bit<8> hop_limit; + IPv6Address src_addr; + IPv6Address dst_addr; +} + +const bit<16> IPV6_HDR_SIZE=320/8; + +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; + ipv6_t ipv6; + udp_t udp; + tcp_t tcp; + vxlan_t vxlan; + ethernet_t inner_ethernet; + ipv4_t inner_ipv4; + ipv6_t inner_ipv6; + udp_t inner_udp; + tcp_t inner_tcp; +} + +#endif /* _SIRIUS_HEADERS_P4_ */ diff --git a/sirius-pipeline/sirius_inbound.p4 b/sirius-pipeline/sirius_inbound.p4 new file mode 100644 index 000000000..aec7ab904 --- /dev/null +++ b/sirius-pipeline/sirius_inbound.p4 @@ -0,0 +1,91 @@ +#ifndef _SIRIUS_INBOUND_P4_ +#define _SIRIUS_INBOUND_P4_ + +#include "sirius_headers.p4" +#include "sirius_service_tunnel.p4" +#include "sirius_vxlan.p4" +#include "sirius_acl.p4" + +control inbound(inout headers_t hdr, + inout metadata_t meta, + inout standard_metadata_t standard_metadata) +{ + action set_eni(bit<16> eni) { + meta.eni = eni; + } + + table eni_lookup_to_vm { + key = { + hdr.ethernet.dst_addr : exact @name("hdr.ethernet.dst_addr:dmac"); + } + + actions = { + set_eni; + } + } + + action set_vm_attributes(EthernetAddress underlay_dmac, + IPv4Address underlay_dip, + bit<24> vni) { + meta.encap_data.underlay_dmac = underlay_dmac; + meta.encap_data.underlay_dip = underlay_dip; + meta.encap_data.vni = vni; + } + + action set_vm_id(bit<16> vm_id) { + meta.vm_id = vm_id; + } + + table eni_to_vm { + key = { + meta.eni: exact @name("meta.eni:eni"); + } + + actions = { + set_vm_id; + } + } + + table vm { + key = { + meta.vm_id: exact @name("meta.vm_id:vm_id"); + } + + actions = { + set_vm_attributes; + } + } + + apply { + eni_lookup_to_vm.apply(); + + eni_to_vm.apply(); + + vm.apply(); + + /* Check if PA is valid */ + +#ifdef STATEFUL_P4 + ConntrackIn.apply(0); +#endif /* STATEFUL_P4 */ + + /* ACL */ + if (meta.conntrack_data.allow_in) { + acl.apply(hdr, meta, standard_metadata); + } + +#ifdef STATEFUL_P4 + ConntrackOut.apply(1); +#endif /* STATEFUL_P4 */ + + vxlan_encap(hdr, + meta.encap_data.underlay_dmac, + meta.encap_data.underlay_smac, + meta.encap_data.underlay_dip, + meta.encap_data.underlay_sip, + hdr.ethernet.dst_addr, + meta.encap_data.vni); + } +} + +#endif /* _SIRIUS_INBOUND_P4_ */ diff --git a/sirius-pipeline/sirius_metadata.p4 b/sirius-pipeline/sirius_metadata.p4 new file mode 100644 index 000000000..3f42050e7 --- /dev/null +++ b/sirius-pipeline/sirius_metadata.p4 @@ -0,0 +1,37 @@ +#ifndef _SIRIUS_METADATA_P4_ +#define _SIRIUS_METADATA_P4_ + +#include "sirius_headers.p4" + +struct encap_data_t { + bit<24> vni; + bit<24> dest_vnet_vni; + IPv4Address underlay_sip; + IPv4Address underlay_dip; + EthernetAddress underlay_smac; + EthernetAddress underlay_dmac; + EthernetAddress overlay_dmac; +} + +enum direction_t { + INVALID, + OUTBOUND, + INBOUND +} + +struct conntrack_data_t { + bool allow_in; + bool allow_out; +} + +struct metadata_t { + bool dropped; + direction_t direction; + encap_data_t encap_data; + bit<16> eni; + bit<16> vm_id; + bit<8> appliance_id; + conntrack_data_t conntrack_data; +} + +#endif /* _SIRIUS_METADATA_P4_ */ diff --git a/sirius-pipeline/sirius_outbound.p4 b/sirius-pipeline/sirius_outbound.p4 new file mode 100644 index 000000000..c7b2e2b54 --- /dev/null +++ b/sirius-pipeline/sirius_outbound.p4 @@ -0,0 +1,122 @@ +#ifndef _SIRIUS_OUTBOUND_P4_ +#define _SIRIUS_OUTBOUND_P4_ + +#include "sirius_headers.p4" +#include "sirius_acl.p4" + +control outbound(inout headers_t hdr, + inout metadata_t meta, + inout standard_metadata_t standard_metadata) +{ + action set_eni(bit<16> eni) { + meta.eni = eni; + } + + table eni_lookup_from_vm { + key = { + hdr.ethernet.src_addr : exact @name("hdr.ethernet.src_addr:smac"); + } + + actions = { + set_eni; + } + } + + action set_vni(bit<24> vni) { + meta.encap_data.vni = vni; + } + + table eni_to_vni { + key = { + meta.eni : exact @name("meta.eni:eni"); + } + + actions = { + set_vni; + } + } + + action route_vnet(bit<24> dest_vnet_vni) { + meta.encap_data.dest_vnet_vni = dest_vnet_vni; + } + + direct_counter(CounterType.packets_and_bytes) routing_counter; + + table routing { + key = { + meta.eni : exact @name("meta.eni:eni"); + hdr.ipv4.dst_addr : lpm @name("hdr.ipv4.dst_addr:destination"); + } + + actions = { + route_vnet; /* for expressroute - ecmp of overlay */ + } + + counters = routing_counter; + } + + action set_tunnel_mapping(IPv4Address underlay_dip, + EthernetAddress overlay_dmac, + bit<1> use_dst_vni) { + /* + if (use_dst_vni) + vni = meta.encap_data.vni; + else + vni = meta.encap_data.dest_vnet_vni; + */ + meta.encap_data.vni = meta.encap_data.vni * (bit<24>)(~use_dst_vni) + meta.encap_data.dest_vnet_vni * (bit<24>)use_dst_vni; + meta.encap_data.overlay_dmac = overlay_dmac; + meta.encap_data.underlay_dip = underlay_dip; + } + + direct_counter(CounterType.packets_and_bytes) ca_to_pa_counter; + + table ca_to_pa { + key = { + /* Flow for express route */ + meta.encap_data.dest_vnet_vni : exact @name("meta.encap_data.dest_vnet_vni:dest_vni"); + hdr.ipv4.dst_addr : exact @name("hdr.ipv4.dst_addr:dip"); + } + + actions = { + set_tunnel_mapping; + } + + counters = ca_to_pa_counter; + } + + apply { + eni_lookup_from_vm.apply(); + + eni_to_vni.apply(); + +#ifdef STATEFUL_P4 + ConntrackOut.apply(0); +#endif /* STATEFUL_P4 */ + + /* ACL */ + if (meta.conntrack_data.allow_out) { + acl.apply(hdr, meta, standard_metadata); + } + +#ifdef STATEFUL_P4 + ConntrackIn.apply(1); +#endif /* STATEFUL_P4 */ + + switch (routing.apply().action_run) { + route_vnet: { + ca_to_pa.apply(); + + vxlan_encap(hdr, + meta.encap_data.underlay_dmac, + meta.encap_data.underlay_smac, + meta.encap_data.underlay_dip, + meta.encap_data.underlay_sip, + meta.encap_data.overlay_dmac, + meta.encap_data.vni); + } + } + } +} + +#endif /* _SIRIUS_OUTBOUND_P4_ */ diff --git a/sirius-pipeline/sirius_parser.p4 b/sirius-pipeline/sirius_parser.p4 new file mode 100644 index 000000000..85884d10d --- /dev/null +++ b/sirius-pipeline/sirius_parser.p4 @@ -0,0 +1,107 @@ +#ifndef _SIRIUS_PARSER_P4_ +#define _SIRIUS_PARSER_P4_ + +#include "sirius_headers.p4" + +error { + IPv4IncorrectVersion, + IPv4OptionsNotSupported +} + +#define UDP_PORT_VXLAN 4789 +#define UDP_PROTO 17 +#define TCP_PROTO 6 +#define IPV4_ETHTYPE 0x800 +#define IPV6_ETHTYPE 0x86dd + +parser sirius_parser(packet_in packet, + out headers_t hd, + inout metadata_t meta, + inout standard_metadata_t standard_meta) +{ + state start { + packet.extract(hd.ethernet); + transition select(hd.ethernet.ether_type) { + 0x0800: parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(hd.ipv4); + verify(hd.ipv4.version == 4w4, error.IPv4IncorrectVersion); + verify(hd.ipv4.ihl == 4w5, error.IPv4OptionsNotSupported); + transition select(hd.ipv4.protocol) { + UDP_PROTO: parse_udp; + TCP_PROTO: parse_tcp; + default: accept; + } + } + + state parse_udp { + packet.extract(hd.udp); + transition select(hd.udp.dst_port) { + UDP_PORT_VXLAN: parse_vxlan; + default: accept; + } + } + + state parse_tcp { + packet.extract(hd.tcp); + transition accept; + } + + state parse_vxlan { + packet.extract(hd.vxlan); + transition parse_inner_ethernet; + } + + state parse_inner_ethernet { + packet.extract(hd.inner_ethernet); + transition select(hd.ethernet.ether_type) { + IPV4_ETHTYPE: parse_inner_ipv4; + default: accept; + } + } + + state parse_inner_ipv4 { + packet.extract(hd.inner_ipv4); + verify(hd.inner_ipv4.version == 4w4, error.IPv4IncorrectVersion); + verify(hd.inner_ipv4.ihl == 4w5, error.IPv4OptionsNotSupported); + transition select(hd.inner_ipv4.protocol) { + UDP_PROTO: parse_inner_udp; + TCP_PROTO: parse_inner_tcp; + default: accept; + } + } + + state parse_inner_tcp { + packet.extract(hd.inner_tcp); + transition accept; + } + + state parse_inner_udp { + packet.extract(hd.inner_udp); + transition accept; + } +} + +control sirius_deparser(packet_out packet, + in headers_t hdr) +{ + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.ipv4); + packet.emit(hdr.ipv6); + packet.emit(hdr.udp); + packet.emit(hdr.tcp); + packet.emit(hdr.vxlan); + packet.emit(hdr.inner_ethernet); + packet.emit(hdr.inner_ipv4); + packet.emit(hdr.inner_ipv6); + packet.emit(hdr.inner_tcp); + packet.emit(hdr.inner_udp); + } +} + +#endif /* _SIRIUS_PARSER_P4_ */ diff --git a/sirius-pipeline/sirius_pipeline.p4 b/sirius-pipeline/sirius_pipeline.p4 new file mode 100644 index 000000000..3306d3d01 --- /dev/null +++ b/sirius-pipeline/sirius_pipeline.p4 @@ -0,0 +1,159 @@ +#include +#include +#include "sirius_headers.p4" +#include "sirius_metadata.p4" +#include "sirius_parser.p4" +#include "sirius_vxlan.p4" +#include "sirius_outbound.p4" +#include "sirius_inbound.p4" +#include "sirius_conntrack.p4" + +control sirius_verify_checksum(inout headers_t hdr, + inout metadata_t meta) +{ + apply { } +} + +control sirius_compute_checksum(inout headers_t hdr, + inout metadata_t meta) +{ + apply { } +} + +control sirius_ingress(inout headers_t hdr, + inout metadata_t meta, + inout standard_metadata_t standard_metadata) +{ + action drop_action() { + mark_to_drop(standard_metadata); + } + + action set_direction(direction_t direction) { + meta.direction = direction; + } + + table direction_lookup { + key = { + hdr.vxlan.vni : exact @name("hdr.vxlan.vni:vni"); + } + + actions = { + set_direction; + } + } + + action set_appliance(EthernetAddress neighbor_mac, + EthernetAddress mac, + IPv4Address ip) { + meta.encap_data.underlay_dmac = neighbor_mac; + meta.encap_data.underlay_smac = mac; + meta.encap_data.underlay_sip = ip; + } + + table appliance { + key = { + meta.appliance_id : ternary @name("meta.appliance_id:appliance_id"); + } + + actions = { + set_appliance; + } + } + + direct_counter(CounterType.packets_and_bytes) eni_counter; + + table eni_meter { + key = { + meta.eni : exact @name("meta.eni:eni"); + meta.direction : exact @name("meta.direction:direction"); + meta.dropped : exact @name("meta.dropped:dropped"); + } + + actions = { NoAction; } + + counters = eni_counter; + } + + action permit() { + meta.dropped = false; + } + + action deny() { + meta.dropped = true; + } + + table pa_validation { + key = { + hdr.ipv4.src_addr : exact @name("hdr.ipv4.src_addr:sip"); + hdr.vxlan.vni : exact @name("hdr.vxlan.vni:vni"); + } + + actions = { + permit; + @defaultonly deny; + } + + const default_action = deny; + } + + table inbound_routing { + key = { + hdr.vxlan.vni : exact @name("hdr.vxlan.vni:vni"); + } + actions = { + vxlan_decap; + vxlan_decap_pa_validate; + @defaultonly deny; + } + + const default_action = deny; + } + + apply { + direction_lookup.apply(); + + appliance.apply(); + + /* Outer header processing */ + + if (meta.direction == direction_t.OUTBOUND) { + vxlan_decap(hdr); + } else if (meta.direction == direction_t.INBOUND) { + slb_decap.apply(); /* TODO: define this encapsulation */ + + switch (inbound_routing.apply().action_run) { + vxlan_decap_pa_validate: { + pa_validation.apply(); + vxlan_decap(); + } + } + } + + /* At this point the processing is done on customer headers */ + + if (meta.direction == direction_t.OUTBOUND) { + outbound.apply(hdr, meta, standard_metadata); + } else if (meta.direction == direction_t.INBOUND) { + inbound.apply(hdr, meta, standard_metadata); + } + + eni_meter.apply(); + + /* Send packet to port 1 by default if we reached the end of pipeline */ + standard_metadata.egress_spec = 1; + } +} + +control sirius_egress(inout headers_t hdr, + inout metadata_t meta, + inout standard_metadata_t standard_metadata) +{ + apply { } +} + +V1Switch(sirius_parser(), + sirius_verify_checksum(), + sirius_ingress(), + sirius_egress(), + sirius_compute_checksum(), + sirius_deparser()) main; diff --git a/sirius-pipeline/sirius_service_tunnel.p4 b/sirius-pipeline/sirius_service_tunnel.p4 new file mode 100644 index 000000000..e4dd898ed --- /dev/null +++ b/sirius-pipeline/sirius_service_tunnel.p4 @@ -0,0 +1,42 @@ +#ifndef _SIRIUS_SERVICE_TUNNEL_P4_ +#define _SIRIUS_SERVICE_TUNNEL_P4_ + +#include "sirius_headers.p4" + +/* Encodes V4 in V6 */ +action service_tunnel_encode(inout headers_t hdr, + in IPv6Address st_dst_prefix, + in IPv6Address st_src_prefix) { + hdr.ipv6.setValid(); + hdr.ipv6.version = 6; + hdr.ipv6.traffic_class = 0; + hdr.ipv6.flow_label = 0; + hdr.ipv6.payload_length = hdr.ipv4.total_len - IPV4_HDR_SIZE; + hdr.ipv6.next_header = hdr.ipv4.protocol; + hdr.ipv6.hop_limit = hdr.ipv4.ttl; + hdr.ipv6.dst_addr = (IPv6Address)hdr.ipv4.dst_addr + st_dst_prefix; + hdr.ipv6.src_addr = (IPv6Address)hdr.ipv4.src_addr + st_src_prefix; + + hdr.ipv4.setInvalid(); + hdr.ethernet.ether_type = IPV6_ETHTYPE; +} + +/* Decodes V4 from V6 */ +action service_tunnel_decode(inout headers_t hdr) { + hdr.ipv4.setValid(); + hdr.ipv4.version = 4; + hdr.ipv4.ihl = 5; + hdr.ipv4.diffserv = 0; + hdr.ipv4.total_len = hdr.ipv6.payload_length + IPV4_HDR_SIZE; + hdr.ipv4.identification = 1; + hdr.ipv4.flags = 0; + hdr.ipv4.frag_offset = 0; + hdr.ipv4.protocol = hdr.ipv6.next_header; + hdr.ipv4.ttl = hdr.ipv6.hop_limit; + hdr.ipv4.hdr_checksum = 0; + + hdr.ipv6.setInvalid(); + hdr.ethernet.ether_type = IPV4_ETHTYPE; +} + +#endif /* _SIRIUS_SERVICE_TUNNEL_P4_ */ diff --git a/sirius-pipeline/sirius_vxlan.p4 b/sirius-pipeline/sirius_vxlan.p4 new file mode 100644 index 000000000..6c2f44512 --- /dev/null +++ b/sirius-pipeline/sirius_vxlan.p4 @@ -0,0 +1,87 @@ +#ifndef _SIRIUS_VXLAN_P4_ +#define _SIRIUS_VXLAN_P4_ + +#include "sirius_headers.p4" + +action vxlan_encap(inout headers_t hdr, + in EthernetAddress underlay_dmac, + in EthernetAddress underlay_smac, + in IPv4Address underlay_dip, + in IPv4Address underlay_sip, + in EthernetAddress overlay_dmac, + in bit<24> vni) { + hdr.inner_ethernet = hdr.ethernet; + hdr.inner_ethernet.dst_addr = overlay_dmac; + hdr.ethernet.setInvalid(); + + hdr.inner_ipv4 = hdr.ipv4; + hdr.ipv4.setInvalid(); + hdr.inner_ipv6 = hdr.ipv6; + hdr.ipv6.setInvalid(); + hdr.inner_tcp = hdr.tcp; + hdr.tcp.setInvalid(); + hdr.inner_udp = hdr.udp; + hdr.udp.setInvalid(); + + hdr.ethernet.setValid(); + hdr.ethernet.dst_addr = underlay_dmac; + hdr.ethernet.src_addr = underlay_smac; + hdr.ethernet.ether_type = IPV4_ETHTYPE; + + hdr.ipv4.setValid(); + hdr.ipv4.version = 4; + hdr.ipv4.ihl = 5; + hdr.ipv4.diffserv = 0; + hdr.ipv4.total_len = hdr.inner_ipv4.total_len*(bit<16>)(bit<1>)hdr.inner_ipv4.isValid() + \ + hdr.inner_ipv6.payload_length*(bit<16>)(bit<1>)hdr.inner_ipv6.isValid() + \ + IPV6_HDR_SIZE*(bit<16>)(bit<1>)hdr.inner_ipv6.isValid() + \ + ETHER_HDR_SIZE + \ + IPV4_HDR_SIZE + \ + UDP_HDR_SIZE + \ + VXLAN_HDR_SIZE; + hdr.ipv4.identification = 1; + hdr.ipv4.flags = 0; + hdr.ipv4.frag_offset = 0; + hdr.ipv4.ttl = 64; + hdr.ipv4.protocol = UDP_PROTO; + hdr.ipv4.dst_addr = underlay_dip; + hdr.ipv4.src_addr = underlay_sip; + hdr.ipv4.hdr_checksum = 0; + + hdr.udp.setValid(); + hdr.udp.src_port = 0; + hdr.udp.dst_port = UDP_PORT_VXLAN; + hdr.udp.length = hdr.inner_ipv4.total_len*(bit<16>)(bit<1>)hdr.inner_ipv4.isValid() + \ + hdr.inner_ipv6.payload_length*(bit<16>)(bit<1>)hdr.inner_ipv6.isValid() + \ + IPV6_HDR_SIZE*(bit<16>)(bit<1>)hdr.inner_ipv6.isValid() + \ + UDP_HDR_SIZE + \ + VXLAN_HDR_SIZE + \ + ETHER_HDR_SIZE; + hdr.udp.checksum = 0; + + hdr.vxlan.setValid(); + hdr.vxlan.reserved = 0; + hdr.vxlan.reserved_2 = 0; + hdr.vxlan.flags = 0; + hdr.vxlan.vni = vni; + +} + +action vxlan_decap(inout headers_t hdr) { + hdr.ethernet = hdr.inner_ethernet; + hdr.inner_ethernet.setInvalid(); + + hdr.ipv4 = hdr.inner_ipv4; + hdr.inner_ipv4.setInvalid(); + + hdr.vxlan.setInvalid(); + hdr.udp.setInvalid(); + + hdr.tcp = hdr.inner_tcp; + hdr.inner_tcp.setInvalid(); + + hdr.udp = hdr.inner_udp; + hdr.inner_udp.setInvalid(); +} + +#endif /* _SIRIUS_VXLAN_P4_ */