Improvement in fabric.p4 and bng.p4
- fabric.p4 now supports double tagged hosts
- bng.p4 now only manages PPPoE termination
- bng_ingress moved at the end of the fabric pipeline
Change-Id: Iff62238fde9ec6ddf7311312a98c041e3ab3aa8d
diff --git a/pipelines/fabric/src/main/resources/include/bng.p4 b/pipelines/fabric/src/main/resources/include/bng.p4
index 11e4639..ede0001 100644
--- a/pipelines/fabric/src/main/resources/include/bng.p4
+++ b/pipelines/fabric/src/main/resources/include/bng.p4
@@ -26,10 +26,6 @@
#ifndef __BNG__
#define __BNG__
-#define BNG_MAX_SUBSC 8192
-#define BNG_MAX_NET_PER_SUBSC 4
-#define BNG_MAX_SUBSC_NET BNG_MAX_NET_PER_SUBSC * BNG_MAX_SUBSC
-
#define BNG_SUBSC_IPV6_NET_PREFIX_LEN 64
control bng_ingress_upstream(
@@ -41,38 +37,11 @@
counter(BNG_MAX_SUBSC, CounterType.packets) c_dropped;
counter(BNG_MAX_SUBSC, CounterType.packets) c_control;
- vlan_id_t s_tag = hdr.vlan_tag.vlan_id;
- vlan_id_t c_tag = hdr.inner_vlan_tag.vlan_id;
-
- _BOOL drop = _FALSE;
- // TABLE: t_line_map
- // Maps double VLAN tags to line ID. Line IDs are used to uniquelly identify
- // a subscriber.
-
- action set_line(bit<32> line_id) {
- fmeta.bng.line_id = line_id;
- }
-
- table t_line_map {
- actions = {
- @defaultonly nop;
- set_line;
- }
- key = {
- s_tag: exact @name("s_tag");
- c_tag: exact @name("c_tag");
- }
- size = BNG_MAX_SUBSC;
- const default_action = nop;
- }
-
// TABLE: t_pppoe_cp
// Punt to CPU for PPPeE control packets.
action punt_to_cpu() {
smeta.egress_spec = CPU_PORT;
- fmeta.skip_forwarding = _TRUE;
- fmeta.skip_next = _TRUE;
c_control.count(fmeta.bng.line_id);
}
@@ -95,26 +64,24 @@
@hidden
action term_enabled(bit<16> eth_type) {
- hdr.ethernet.eth_type = eth_type;
- fmeta.eth_type = eth_type;
+ hdr.inner_vlan_tag.eth_type = eth_type;
+ fmeta.last_eth_type = eth_type;
hdr.pppoe.setInvalid();
- hdr.vlan_tag.setInvalid();
- hdr.inner_vlan_tag.setInvalid();
c_terminated.count(fmeta.bng.line_id);
}
action term_disabled() {
fmeta.bng.type = BNG_TYPE_INVALID;
- fmeta.skip_forwarding = _TRUE;
- fmeta.skip_next = _TRUE;
mark_to_drop(smeta);
- drop = _TRUE;
}
action term_enabled_v4() {
term_enabled(ETHERTYPE_IPV4);
}
+ // TODO: add match on hdr.ethernet.src_addr for antispoofing
+ // Take into account that MAC src address is modified by the Next control block
+ // when doing routing functionality.
table t_pppoe_term_v4 {
key = {
fmeta.bng.line_id : exact @name("line_id");
@@ -134,6 +101,9 @@
term_enabled(ETHERTYPE_IPV6);
}
+ // TODO: add match on hdr.ethernet.src_addr for antispoofing
+ // Match on unmodified metadata field, taking into account that MAC src address
+ // is modified by the Next control block when doing routing functionality.
table t_pppoe_term_v6 {
key = {
fmeta.bng.line_id : exact @name("line_id");
@@ -150,25 +120,23 @@
#endif // WITH_IPV6
apply {
- // If table miss, line_id will be 0 (default metadata value).
- t_line_map.apply();
-
- if (t_pppoe_cp.apply().hit) {
+ if(t_pppoe_cp.apply().hit) {
return;
}
-
if (hdr.ipv4.isValid()) {
- t_pppoe_term_v4.apply();
- if (drop == _TRUE) {
- c_dropped.count(fmeta.bng.line_id);
+ switch(t_pppoe_term_v4.apply().action_run) {
+ term_disabled: {
+ c_dropped.count(fmeta.bng.line_id);
+ }
}
}
#ifdef WITH_IPV6
else if (hdr.ipv6.isValid()) {
- t_pppoe_term_v6.apply();
- if (drop == _TRUE) {
- c_dropped.count(fmeta.bng.line_id);
- }
+ switch(t_pppoe_term_v6.apply().action_run) {
+ term_disabled: {
+ c_dropped.count(fmeta.bng.line_id);
+ }
+ }
}
#endif // WITH_IPV6
}
@@ -184,65 +152,37 @@
meter(BNG_MAX_SUBSC, MeterType.bytes) m_besteff;
meter(BNG_MAX_SUBSC, MeterType.bytes) m_prio;
- // Downstream line map tables.
- // Map IP dest address to line ID and next ID. Setting a next ID here
- // allows to skip the fabric.p4 forwarding stage later.
- _BOOL prio = _FALSE;
-
- @hidden
- action set_line(bit<32> line_id) {
+ action set_session(bit<16> pppoe_session_id) {
fmeta.bng.type = BNG_TYPE_DOWNSTREAM;
- fmeta.bng.line_id = line_id;
- c_line_rx.count(line_id);
+ fmeta.bng.pppoe_session_id = pppoe_session_id;
+ c_line_rx.count(fmeta.bng.line_id);
}
- action set_line_next(bit<32> line_id, next_id_t next_id) {
- set_line(line_id);
- fmeta.next_id = next_id;
- fmeta.skip_forwarding = _TRUE;
- }
-
- action set_line_drop(bit<32> line_id) {
- set_line(line_id);
- fmeta.skip_forwarding = _TRUE;
- fmeta.skip_next = _TRUE;
+ action drop() {
+ fmeta.bng.type = BNG_TYPE_DOWNSTREAM;
+ c_line_rx.count(fmeta.bng.line_id);
mark_to_drop(smeta);
}
- table t_line_map_v4 {
+ table t_line_session_map {
key = {
- hdr.ipv4.dst_addr: exact @name("ipv4_dst");
+ fmeta.bng.line_id : exact @name("line_id");
}
actions = {
@defaultonly nop;
- set_line_next;
- set_line_drop;
+ set_session;
+ drop;
}
- size = BNG_MAX_SUBSC_NET;
+ size = BNG_MAX_SUBSC;
const default_action = nop;
}
-#ifdef WITH_IPV6
- table t_line_map_v6 {
- key = {
- hdr.ipv6.dst_addr[127:64]: exact @name("ipv6_dst_net_id");
- }
- actions = {
- @defaultonly nop;
- set_line_next;
- set_line_drop;
- }
- size = BNG_MAX_SUBSC_NET;
- const default_action = nop;
- }
-#endif // WITH_IPV6
-
// Downstream QoS tables.
// Provide coarse metering before prioritazion in the OLT. By default
// everything is tagged and metered as best-effort traffic.
action qos_prio() {
- prio = _TRUE;
+ // no-op
}
action qos_besteff() {
@@ -281,38 +221,39 @@
#endif // WITH_IPV6
apply {
+ // We are not sure the pkt is a BNG downstream one, first we need to
+ // verify the line_id matches the one of a subscriber...
+
// IPv4
- if (hdr.ipv4.isValid()) {
- if (t_line_map_v4.apply().hit) {
- // Apply QoS only to subscriber traffic. This makes sense only
- // if the downstream ports are used to receive IP traffic NOT
- // destined to subscribers, e.g. to services in the compute
- // nodes.
- t_qos_v4.apply();
- if (prio == _TRUE) {
- m_prio.execute_meter((bit<32>)fmeta.bng.line_id,
- fmeta.bng.ds_meter_result);
- } else {
- m_besteff.execute_meter((bit<32>)fmeta.bng.line_id,
- fmeta.bng.ds_meter_result);
+ if (t_line_session_map.apply().hit) {
+ // Apply QoS only to subscriber traffic. This makes sense only
+ // if the downstream ports are used to receive IP traffic NOT
+ // destined to subscribers, e.g. to services in the compute
+ // nodes.
+ if (hdr.ipv4.isValid()) {
+ switch (t_qos_v4.apply().action_run) {
+ qos_prio: {
+ m_prio.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
+ }
+ qos_besteff: {
+ m_besteff.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
+ }
}
}
- }
#ifdef WITH_IPV6
- // IPv6
- else if (hdr.ipv6.isValid()) {
- if (t_line_map_v6.apply().hit) {
- t_qos_v6.apply();
- if (prio == _TRUE) {
- m_prio.execute_meter((bit<32>)fmeta.bng.line_id,
- fmeta.bng.ds_meter_result);
- } else {
- m_besteff.execute_meter((bit<32>)fmeta.bng.line_id,
- fmeta.bng.ds_meter_result);
+ // IPv6
+ else if (hdr.ipv6.isValid()) {
+ switch (t_qos_v6.apply().action_run) {
+ qos_prio: {
+ m_prio.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
+ }
+ qos_besteff: {
+ m_besteff.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
+ }
}
}
- }
#endif // WITH_IPV6
+ }
}
}
@@ -324,52 +265,41 @@
counter(BNG_MAX_SUBSC, CounterType.packets_and_bytes) c_line_tx;
@hidden
- action encap(vlan_id_t c_tag, bit<16> pppoe_session_id) {
- // s_tag (outer VLAN) should be already set via the next_vlan table.
- // Here we add c_tag (inner VLAN) and PPPoE.
- hdr.vlan_tag.eth_type = ETHERTYPE_VLAN;
- hdr.inner_vlan_tag.setValid();
- hdr.inner_vlan_tag.vlan_id = c_tag;
+ action encap() {
+ // Here we add PPPoE and modify the inner_vlan_tag Ethernet Type.
hdr.inner_vlan_tag.eth_type = ETHERTYPE_PPPOES;
hdr.pppoe.setValid();
hdr.pppoe.version = 4w1;
hdr.pppoe.type_id = 4w1;
hdr.pppoe.code = 8w0; // 0 means session stage.
- hdr.pppoe.session_id = pppoe_session_id;
+ hdr.pppoe.session_id = fmeta.bng.pppoe_session_id;
c_line_tx.count(fmeta.bng.line_id);
}
- action encap_v4(vlan_id_t c_tag, bit<16> pppoe_session_id) {
- encap(c_tag, pppoe_session_id);
+ action encap_v4() {
+ encap();
hdr.pppoe.length = hdr.ipv4.total_len + 16w2;
hdr.pppoe.protocol = PPPOE_PROTOCOL_IP4;
}
#ifdef WITH_IPV6
- action encap_v6(vlan_id_t c_tag, bit<16> pppoe_session_id) {
- encap(c_tag, pppoe_session_id);
+ action encap_v6() {
+ encap();
hdr.pppoe.length = hdr.ipv6.payload_len + 16w42;
hdr.pppoe.protocol = PPPOE_PROTOCOL_IP6;
}
#endif // WITH_IPV6
- table t_session_encap {
- key = {
- fmeta.bng.line_id : exact @name("line_id");
- }
- actions = {
- @defaultonly nop;
- encap_v4;
-#ifdef WITH_IPV6
- encap_v6;
-#endif // WITH_IPV6
- }
- size = BNG_MAX_SUBSC;
- const default_action = nop();
- }
-
apply {
- t_session_encap.apply();
+ if (hdr.ipv4.isValid()) {
+ encap_v4();
+ }
+#ifdef WITH_IPV6
+ // IPv6
+ else if (hdr.ipv6.isValid()) {
+ encap_v6();
+ }
+#endif // WITH_IPV6
}
}
@@ -378,20 +308,54 @@
inout fabric_metadata_t fmeta,
inout standard_metadata_t smeta) {
- bng_ingress_upstream() upstream;
- bng_ingress_downstream() downstream;
+ bng_ingress_upstream() upstream;
+ bng_ingress_downstream() downstream;
- apply {
- if (hdr.pppoe.isValid()) {
- fmeta.bng.type = BNG_TYPE_UPSTREAM;
- upstream.apply(hdr, fmeta, smeta);
+ vlan_id_t s_tag = 0;
+ vlan_id_t c_tag = 0;
+
+ // TABLE: t_line_map
+ // Map s_tag and c_tag to a line ID to uniquely identify a subscriber
+
+ action set_line(bit<32> line_id) {
+ fmeta.bng.line_id = line_id;
}
- else {
- // We are not sure the pkt is a BNG downstream one, first we need to
- // verify the IP dst matches the IP addr of a subscriber...
- downstream.apply(hdr, fmeta, smeta);
+
+ table t_line_map {
+ key = {
+ s_tag : exact @name("s_tag");
+ c_tag : exact @name("c_tag");
+ }
+ actions = {
+ @defaultonly nop;
+ set_line;
+ }
+ size = BNG_MAX_SUBSC;
+ const default_action = nop;
}
- }
+
+ apply {
+ if(hdr.pppoe.isValid()) {
+ s_tag = hdr.vlan_tag.vlan_id;
+ c_tag = hdr.inner_vlan_tag.vlan_id;
+ } else {
+ // We expect the packet to be downstream,
+ // the tags are set by the next stage in the metadata.
+ s_tag = fmeta.vlan_id;
+ c_tag = fmeta.inner_vlan_id;
+ }
+
+ // First map the double VLAN tags to a line ID
+ // If table miss line ID will be 0.
+ t_line_map.apply();
+
+ if (hdr.pppoe.isValid()) {
+ fmeta.bng.type = BNG_TYPE_UPSTREAM;
+ upstream.apply(hdr, fmeta, smeta);
+ } else {
+ downstream.apply(hdr, fmeta, smeta);
+ }
+ }
}
control bng_egress(
diff --git a/pipelines/fabric/src/main/resources/include/control/acl.p4 b/pipelines/fabric/src/main/resources/include/control/acl.p4
index bf70f15..4c2df67 100644
--- a/pipelines/fabric/src/main/resources/include/control/acl.p4
+++ b/pipelines/fabric/src/main/resources/include/control/acl.p4
@@ -66,7 +66,7 @@
hdr.ethernet.dst_addr: ternary @name("eth_src"); // 48
hdr.ethernet.src_addr: ternary @name("eth_dst"); // 48
hdr.vlan_tag.vlan_id: ternary @name("vlan_id"); // 12
- fabric_metadata.eth_type: ternary @name("eth_type"); //16
+ fabric_metadata.last_eth_type: ternary @name("eth_type"); //16
hdr.ipv4.src_addr: ternary @name("ipv4_src"); // 32
hdr.ipv4.dst_addr: ternary @name("ipv4_dst"); // 32
hdr.icmp.icmp_type: ternary @name("icmp_type"); // 8
diff --git a/pipelines/fabric/src/main/resources/include/control/filtering.p4 b/pipelines/fabric/src/main/resources/include/control/filtering.p4
index cc8e313..a3213e9 100644
--- a/pipelines/fabric/src/main/resources/include/control/filtering.p4
+++ b/pipelines/fabric/src/main/resources/include/control/filtering.p4
@@ -45,14 +45,17 @@
action permit_with_internal_vlan(vlan_id_t vlan_id) {
fabric_metadata.vlan_id = vlan_id;
- ingress_port_vlan_counter.count();
+ permit();
}
+ // FIXME: remove the use of ternary match on valid inner VLAN.
+ // Use multi-table approach to remove ternary matching
table ingress_port_vlan {
key = {
- standard_metadata.ingress_port: exact @name("ig_port");
- hdr.vlan_tag.isValid(): exact @name("vlan_is_valid");
- hdr.vlan_tag.vlan_id: ternary @name("vlan_id");
+ standard_metadata.ingress_port : exact @name("ig_port");
+ hdr.vlan_tag.isValid() : exact @name("vlan_is_valid");
+ hdr.vlan_tag.vlan_id : ternary @name("vlan_id");
+ hdr.inner_vlan_tag.vlan_id : ternary @name("inner_vlan_id");
}
actions = {
deny();
@@ -86,9 +89,11 @@
table fwd_classifier {
key = {
- standard_metadata.ingress_port: exact @name("ig_port");
- hdr.ethernet.dst_addr: ternary @name("eth_dst");
- fabric_metadata.eth_type: exact @name("eth_type");
+ standard_metadata.ingress_port : exact @name("ig_port");
+ hdr.ethernet.dst_addr : ternary @name("eth_dst");
+ fabric_metadata.is_ipv4 : exact @name("is_ipv4");
+ fabric_metadata.is_ipv6 : exact @name("is_ipv6");
+ fabric_metadata.is_mpls : exact @name("is_mpls");
}
actions = {
set_forwarding_type;
@@ -102,11 +107,17 @@
// Initialize lookup metadata. Packets without a VLAN header will be
// treated as belonging to a default VLAN ID (see parser).
if (hdr.vlan_tag.isValid()) {
- fabric_metadata.eth_type = hdr.vlan_tag.eth_type;
fabric_metadata.vlan_id = hdr.vlan_tag.vlan_id;
fabric_metadata.vlan_pri = hdr.vlan_tag.pri;
fabric_metadata.vlan_cfi = hdr.vlan_tag.cfi;
}
+ #ifdef WITH_DOUBLE_VLAN_TERMINATION
+ if (hdr.inner_vlan_tag.isValid()) {
+ fabric_metadata.inner_vlan_id = hdr.inner_vlan_tag.vlan_id;
+ fabric_metadata.inner_vlan_pri = hdr.inner_vlan_tag.pri;
+ fabric_metadata.inner_vlan_cfi = hdr.inner_vlan_tag.cfi;
+ }
+ #endif // WITH_DOUBLE_VLAN_TERMINATION
if (!hdr.mpls.isValid()) {
// Packets with a valid MPLS header will have
// fabric_metadata.mpls_ttl set to the packet's MPLS ttl value (see
@@ -115,6 +126,22 @@
fabric_metadata.mpls_ttl = DEFAULT_MPLS_TTL + 1;
}
+ // Set last_eth_type checking the validity of the L2.5 headers
+ if (hdr.mpls.isValid()) {
+ fabric_metadata.last_eth_type = ETHERTYPE_MPLS;
+ } else {
+ if (hdr.vlan_tag.isValid()) {
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
+ if(hdr.inner_vlan_tag.isValid()) {
+ fabric_metadata.last_eth_type = hdr.inner_vlan_tag.eth_type;
+ } else
+#endif // WITH_XCONNECT || WITH_BNG || WITH_DOUBLE_VLAN_TERMINATION
+ fabric_metadata.last_eth_type = hdr.vlan_tag.eth_type;
+ } else {
+ fabric_metadata.last_eth_type = hdr.ethernet.eth_type;
+ }
+ }
+
ingress_port_vlan.apply();
fwd_classifier.apply();
}
diff --git a/pipelines/fabric/src/main/resources/include/control/next.p4 b/pipelines/fabric/src/main/resources/include/control/next.p4
index 82b61eb..9868339 100644
--- a/pipelines/fabric/src/main/resources/include/control/next.p4
+++ b/pipelines/fabric/src/main/resources/include/control/next.p4
@@ -71,12 +71,23 @@
next_vlan_counter.count();
}
+#ifdef WITH_DOUBLE_VLAN_TERMINATION
+ action set_double_vlan(vlan_id_t outer_vlan_id, vlan_id_t inner_vlan_id) {
+ set_vlan(outer_vlan_id);
+ fabric_metadata.push_double_vlan = _TRUE;
+ fabric_metadata.inner_vlan_id = inner_vlan_id;
+ }
+#endif // WITH_DOUBLE_VLAN_TERMINATION
+
table next_vlan {
key = {
fabric_metadata.next_id: exact @name("next_id");
}
actions = {
set_vlan;
+#ifdef WITH_DOUBLE_VLAN_TERMINATION
+ set_double_vlan;
+#endif // WITH_DOUBLE_VLAN_TERMINATION
@defaultonly nop;
}
const default_action = nop();
@@ -93,6 +104,7 @@
action output_xconnect(port_num_t port_num) {
output(port_num);
+ fabric_metadata.last_eth_type = ETHERTYPE_VLAN;
xconnect_counter.count();
}
@@ -251,7 +263,7 @@
action pop_mpls_if_present() {
hdr.mpls.setInvalid();
// Assuming there's an IP header after the MPLS one.
- fabric_metadata.eth_type = fabric_metadata.ip_eth_type;
+ fabric_metadata.last_eth_type = fabric_metadata.ip_eth_type;
}
@hidden
@@ -261,7 +273,7 @@
hdr.mpls.tc = 3w0;
hdr.mpls.bos = 1w1; // BOS = TRUE
hdr.mpls.ttl = fabric_metadata.mpls_ttl; // Decrement after push.
- fabric_metadata.eth_type = ETHERTYPE_MPLS;
+ fabric_metadata.last_eth_type = ETHERTYPE_MPLS;
}
@hidden
@@ -271,11 +283,25 @@
hdr.vlan_tag.setValid();
hdr.vlan_tag.cfi = fabric_metadata.vlan_cfi;
hdr.vlan_tag.pri = fabric_metadata.vlan_pri;
- hdr.vlan_tag.eth_type = fabric_metadata.eth_type;
+ hdr.vlan_tag.eth_type = fabric_metadata.last_eth_type;
hdr.vlan_tag.vlan_id = fabric_metadata.vlan_id;
hdr.ethernet.eth_type = ETHERTYPE_VLAN;
}
+#ifdef WITH_DOUBLE_VLAN_TERMINATION
+ @hidden
+ action push_inner_vlan() {
+ // Then push inner VLAN TAG, rewriting correclty the outer vlan eth_type
+ // and the ethernet eth_type
+ hdr.inner_vlan_tag.setValid();
+ hdr.inner_vlan_tag.cfi = fabric_metadata.inner_vlan_cfi;
+ hdr.inner_vlan_tag.pri = fabric_metadata.inner_vlan_pri;
+ hdr.inner_vlan_tag.vlan_id = fabric_metadata.inner_vlan_id;
+ hdr.inner_vlan_tag.eth_type = fabric_metadata.last_eth_type;
+ hdr.vlan_tag.eth_type = ETHERTYPE_VLAN;
+ }
+#endif // WITH_DOUBLE_VLAN_TERMINATION
+
/*
* Egress VLAN Table.
* Pops the VLAN tag if the pair egress port and VLAN ID is matched.
@@ -283,7 +309,7 @@
direct_counter(CounterType.packets_and_bytes) egress_vlan_counter;
action pop_vlan() {
- hdr.ethernet.eth_type = fabric_metadata.eth_type;
+ hdr.ethernet.eth_type = fabric_metadata.last_eth_type;
hdr.vlan_tag.setInvalid();
egress_vlan_counter.count();
}
@@ -314,12 +340,26 @@
set_mpls();
}
- if (!egress_vlan.apply().hit) {
- // Push VLAN tag if not the default one.
- if (fabric_metadata.vlan_id != DEFAULT_VLAN_ID) {
- push_vlan();
+#ifdef WITH_DOUBLE_VLAN_TERMINATION
+ if (fabric_metadata.push_double_vlan == _TRUE) {
+ // Double VLAN termination.
+ push_vlan();
+ push_inner_vlan();
+ } else {
+ // If no push double vlan, inner_vlan_tag must be popped
+ hdr.inner_vlan_tag.setInvalid();
+#endif // WITH_DOUBLE_VLAN_TERMINATION
+ // Port-based VLAN tagging (by default all
+ // ports are assumed tagged)
+ if (!egress_vlan.apply().hit) {
+ // Push VLAN tag if not the default one.
+ if (fabric_metadata.vlan_id != DEFAULT_VLAN_ID) {
+ push_vlan();
+ }
}
+#ifdef WITH_DOUBLE_VLAN_TERMINATION
}
+#endif // WITH_DOUBLE_VLAN_TERMINATION
// TTL decrement and check.
if (hdr.mpls.isValid()) {
diff --git a/pipelines/fabric/src/main/resources/include/header.p4 b/pipelines/fabric/src/main/resources/include/header.p4
index 11204e8..09df685 100644
--- a/pipelines/fabric/src/main/resources/include/header.p4
+++ b/pipelines/fabric/src/main/resources/include/header.p4
@@ -159,17 +159,27 @@
struct bng_meta_t {
bit<2> type; // upstream or downstream
bit<32> line_id; // subscriber line
+ bit<16> pppoe_session_id;
bit<32> ds_meter_result; // for downstream metering
}
#endif // WITH_BNG
//Custom metadata definition
struct fabric_metadata_t {
- bit<16> eth_type;
+ bit<16> last_eth_type;
+ _BOOL is_ipv4;
+ _BOOL is_ipv6;
+ _BOOL is_mpls;
bit<16> ip_eth_type;
vlan_id_t vlan_id;
bit<3> vlan_pri;
bit<1> vlan_cfi;
+#ifdef WITH_DOUBLE_VLAN_TERMINATION
+ _BOOL push_double_vlan;
+ vlan_id_t inner_vlan_id;
+ bit<3> inner_vlan_pri;
+ bit<1> inner_vlan_cfi;
+#endif // WITH_DOUBLE_VLAN_TERMINATION
mpls_label_t mpls_label;
bit<8> mpls_ttl;
_BOOL skip_forwarding;
@@ -195,9 +205,9 @@
struct parsed_headers_t {
ethernet_t ethernet;
vlan_tag_t vlan_tag;
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
vlan_tag_t inner_vlan_tag;
-#endif // WITH_XCONNECT || WITH_BNG
+#endif // WITH_XCONNECT || WITH_BNG || WITH_DOUBLE_VLAN_TERMINATION
#ifdef WITH_BNG
pppoe_t pppoe;
#endif // WITH_BNG
diff --git a/pipelines/fabric/src/main/resources/include/parser.p4 b/pipelines/fabric/src/main/resources/include/parser.p4
index e234676..2d6a1d4 100644
--- a/pipelines/fabric/src/main/resources/include/parser.p4
+++ b/pipelines/fabric/src/main/resources/include/parser.p4
@@ -40,14 +40,14 @@
state parse_ethernet {
packet.extract(hdr.ethernet);
- fabric_metadata.eth_type = hdr.ethernet.eth_type;
+ fabric_metadata.last_eth_type = hdr.ethernet.eth_type;
fabric_metadata.vlan_id = DEFAULT_VLAN_ID;
transition select(hdr.ethernet.eth_type){
ETHERTYPE_VLAN: parse_vlan_tag;
ETHERTYPE_MPLS: parse_mpls;
- ETHERTYPE_IPV4: parse_ipv4;
+ ETHERTYPE_IPV4: pre_parse_ipv4;
#ifdef WITH_IPV6
- ETHERTYPE_IPV6: parse_ipv6;
+ ETHERTYPE_IPV6: pre_parse_ipv6;
#endif // WITH_IPV6
default: accept;
}
@@ -56,25 +56,27 @@
state parse_vlan_tag {
packet.extract(hdr.vlan_tag);
transition select(hdr.vlan_tag.eth_type){
- ETHERTYPE_IPV4: parse_ipv4;
+ ETHERTYPE_IPV4: pre_parse_ipv4;
#ifdef WITH_IPV6
- ETHERTYPE_IPV6: parse_ipv6;
+ ETHERTYPE_IPV6: pre_parse_ipv6;
#endif // WITH_IPV6
ETHERTYPE_MPLS: parse_mpls;
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
ETHERTYPE_VLAN: parse_inner_vlan_tag;
+ ETHERTYPE_QINQ: parse_inner_vlan_tag;
+ ETHERTYPE_QINQ_NON_STD: parse_inner_vlan_tag;
#endif // WITH_XCONNECT
default: accept;
}
}
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
state parse_inner_vlan_tag {
packet.extract(hdr.inner_vlan_tag);
transition select(hdr.inner_vlan_tag.eth_type){
- ETHERTYPE_IPV4: parse_ipv4;
+ ETHERTYPE_IPV4: pre_parse_ipv4;
#ifdef WITH_IPV6
- ETHERTYPE_IPV6: parse_ipv6;
+ ETHERTYPE_IPV6: pre_parse_ipv6;
#endif // WITH_IPV6
ETHERTYPE_MPLS: parse_mpls;
#ifdef WITH_BNG
@@ -84,16 +86,16 @@
default: accept;
}
}
-#endif // WITH_XCONNECT
+#endif // WITH_XCONNECT || WITH_BNG || WITH_DOUBLE_VLAN_TERMINATION
#ifdef WITH_BNG
state parse_pppoe {
packet.extract(hdr.pppoe);
transition select(hdr.pppoe.protocol) {
PPPOE_PROTOCOL_MPLS: parse_mpls;
- PPPOE_PROTOCOL_IP4: parse_ipv4;
+ PPPOE_PROTOCOL_IP4: pre_parse_ipv4;
#ifdef WITH_IPV6
- PPPOE_PROTOCOL_IP6: parse_ipv6;
+ PPPOE_PROTOCOL_IP6: pre_parse_ipv6;
#endif // WITH_IPV6
default: accept;
}
@@ -102,13 +104,16 @@
state parse_mpls {
packet.extract(hdr.mpls);
+ fabric_metadata.is_mpls = _TRUE;
fabric_metadata.mpls_label = hdr.mpls.label;
fabric_metadata.mpls_ttl = hdr.mpls.ttl;
// There is only one MPLS label for this fabric.
// Assume header after MPLS header is IPv4/IPv6
// Lookup first 4 bits for version
transition select(packet.lookahead<bit<IP_VER_LENGTH>>()) {
- //The packet should be either IPv4 or IPv6.
+ // The packet should be either IPv4 or IPv6.
+ // If we have MPLS, go directly to parsing state without
+ // moving to pre_ states, the packet is considered MPLS
IP_VERSION_4: parse_ipv4;
#ifdef WITH_IPV6
IP_VERSION_6: parse_ipv6;
@@ -117,6 +122,11 @@
}
}
+ // Intermediate state to set is_ipv4
+ state pre_parse_ipv4 {
+ fabric_metadata.is_ipv4 = _TRUE;
+ transition parse_ipv4;
+ }
state parse_ipv4 {
packet.extract(hdr.ipv4);
fabric_metadata.ip_proto = hdr.ipv4.protocol;
@@ -132,6 +142,11 @@
}
#ifdef WITH_IPV6
+ // Intermediate state to set is_ipv6
+ state pre_parse_ipv6 {
+ fabric_metadata.is_ipv6 = _TRUE;
+ transition parse_ipv6;
+ }
state parse_ipv6 {
packet.extract(hdr.ipv6);
fabric_metadata.ip_proto = hdr.ipv6.next_hdr;
@@ -270,9 +285,9 @@
#endif // WITH_INT_SINK
packet.emit(hdr.ethernet);
packet.emit(hdr.vlan_tag);
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
packet.emit(hdr.inner_vlan_tag);
-#endif // WITH_XCONNECT
+#endif // WITH_XCONNECT || WITH_BNG || WITH_DOUBLE_VLAN_TERMINATION
#ifdef WITH_BNG
packet.emit(hdr.pppoe);
#endif // WITH_BNG
diff --git a/pipelines/fabric/src/main/resources/include/size.p4 b/pipelines/fabric/src/main/resources/include/size.p4
index 8cd2fcc..2883094 100644
--- a/pipelines/fabric/src/main/resources/include/size.p4
+++ b/pipelines/fabric/src/main/resources/include/size.p4
@@ -2,8 +2,14 @@
#define __TABLE_SIZE__
// Default sizes when building for BMv2.
-
-#define PORT_VLAN_TABLE_SIZE 1024
+#define BNG_MAX_SUBSC 8192
+#define BNG_MAX_NET_PER_SUBSC 4
+#define BNG_MAX_SUBSC_NET BNG_MAX_NET_PER_SUBSC * BNG_MAX_SUBSC
+#ifdef WITH_BNG
+ #define PORT_VLAN_TABLE_SIZE BNG_MAX_SUBSC
+#else
+ #define PORT_VLAN_TABLE_SIZE 1024
+#endif // WITH_BNG
#define FWD_CLASSIFIER_TABLE_SIZE 1024
#define BRIDGING_TABLE_SIZE 1024
#define MPLS_TABLE_SIZE 1024