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(