[VOL-3396] Encryption of the GPON GEMs
- Enables downstream encryption on both GPON and XGSPON unicast GEM PortIDs through FlowAdd operation
Change-Id: I4171194db050b96a0940842afc10e8c8c9e285d1
diff --git a/agent/Makefile.in b/agent/Makefile.in
index 9a99b6b..5ccea59 100644
--- a/agent/Makefile.in
+++ b/agent/Makefile.in
@@ -42,7 +42,7 @@
# This specifies the GIT tag in https://github.com/opencord/voltha-protos
# repo that we need to refer to, to pick the right version of
# openolt.proto and tech_profile.proto
-OPENOLT_PROTO_VER ?= v4.0.11
+OPENOLT_PROTO_VER ?= v4.0.14
# Variables used for Inband build
INBAND = "n"
diff --git a/agent/common/core.h b/agent/common/core.h
index ab4c788..b3a5408 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -225,7 +225,7 @@
int32_t alloc_id, int32_t network_intf_id,
int32_t gemport_id, const ::openolt::Classifier& classifier,
const ::openolt::Action& action, int32_t priority_value,
- uint64_t cookie, int32_t group_id, uint32_t tech_profile_id);
+ uint64_t cookie, int32_t group_id, uint32_t tech_profile_id, bool enable_encryption = false);
Status FlowRemoveWrapper_(const openolt::Flow* request);
Status FlowRemove_(uint32_t flow_id, const std::string flow_type);
Status Disable_();
diff --git a/agent/src/core_api_handler.cc b/agent/src/core_api_handler.cc
index 2c5ff83..3d8bd93 100644
--- a/agent/src/core_api_handler.cc
+++ b/agent/src/core_api_handler.cc
@@ -1149,6 +1149,7 @@
}
}
+// TODO: MOVE THIS TO A NEW METHOD
if (omcc_encryption_mode == true) {
// set the encryption mode for omci port id
bcmolt_itupon_gem_cfg gem_cfg;
@@ -1162,7 +1163,7 @@
BCMOLT_FIELD_SET(&gem_cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
err = bcmolt_cfg_set(dev_id, &gem_cfg.hdr);
if(err != BCM_ERR_OK) {
- OPENOLT_LOG(ERROR, openolt_log_id, "failed to confiure omci gem_port encryption mode = %d\n", onu_id);
+ OPENOLT_LOG(ERROR, openolt_log_id, "failed to configure omci gem_port encryption mode = %d\n", onu_id);
return bcm_to_grpc_err(err, "Access_Control set ITU PON OMCI Gem port failed");
}
}
@@ -1459,6 +1460,17 @@
return Status::OK;
}
+bool get_aes_flag_for_gem_port(const google::protobuf::Map<unsigned int, bool> &gemport_to_aes, uint32_t gemport_id) {
+ bool aes_flag = false;
+ for (google::protobuf::Map<unsigned int, bool>::const_iterator it=gemport_to_aes.begin(); it!=gemport_to_aes.end(); it++) {
+ if (it->first == gemport_id) {
+ aes_flag = it->second;
+ break;
+ }
+ }
+ return aes_flag;
+}
+
Status FlowAddWrapper_(const ::openolt::Flow* request) {
int32_t access_intf_id = request->access_intf_id();
@@ -1479,7 +1491,9 @@
uint32_t tech_profile_id = request->tech_profile_id();
bool replicate_flow = request->replicate_flow();
const google::protobuf::Map<unsigned int, unsigned int> &pbit_to_gemport = request->pbit_to_gemport();
+ const google::protobuf::Map<unsigned int, bool> &gemport_to_aes = request->gemport_to_aes();
uint16_t flow_id;
+ bool enable_encryption;
// The intf_id variable defaults to access(PON) interface ID.
// For trap-from-nni flow where access interface ID is not valid , change it to NNI interface ID
@@ -1515,11 +1529,12 @@
flow_id = dev_fl_symm_params[0].flow_id;
gemport_id = dev_fl_symm_params[0].gemport_id; // overwrite the gemport with symmetric flow gemport
// Should be same as what is coming in this request.
+ enable_encryption = get_aes_flag_for_gem_port(gemport_to_aes, gemport_id);
::openolt::Classifier cl = ::openolt::Classifier(classifier);
cl.set_o_pbits(dev_fl_symm_params[0].pbit);
Status st = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id,
flow_type, alloc_id, network_intf_id, gemport_id, cl,
- action, priority, cookie, group_id, tech_profile_id);
+ action, priority, cookie, group_id, tech_profile_id, enable_encryption);
if (st.error_code() == grpc::StatusCode::OK) {
device_flow dev_fl;
dev_fl.is_flow_replicated = false;
@@ -1536,10 +1551,11 @@
::openolt::Classifier cl = ::openolt::Classifier(classifier);
flow_id = dev_fl_symm_params[i].flow_id;
gemport_id = dev_fl_symm_params[i].gemport_id;
+ enable_encryption = get_aes_flag_for_gem_port(gemport_to_aes, gemport_id);
cl.set_o_pbits(dev_fl_symm_params[i].pbit);
Status st = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id,
flow_type, alloc_id, network_intf_id, gemport_id, cl,
- action, priority, cookie, group_id, tech_profile_id);
+ action, priority, cookie, group_id, tech_profile_id, enable_encryption);
if (st.error_code() != grpc::StatusCode::OK && st.error_code() != grpc::StatusCode::ALREADY_EXISTS) {
OPENOLT_LOG(ERROR, openolt_log_id, "failed to install device flow=%u for voltha flow=%lu. Undoing any device flows installed.", flow_id, voltha_flow_id);
// On failure remove any successfully replicated flows installed so far for the voltha_flow_id
@@ -1568,9 +1584,10 @@
OPENOLT_LOG(ERROR, openolt_log_id, "could not allocated flow id for voltha-flow-id=%lu\n", voltha_flow_id);
return ::Status(grpc::StatusCode::RESOURCE_EXHAUSTED, "flow-ids-exhausted");
}
+ enable_encryption = get_aes_flag_for_gem_port(gemport_to_aes, gemport_id);
Status st = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id,
flow_type, alloc_id, network_intf_id, gemport_id, classifier,
- action, priority, cookie, group_id, tech_profile_id);
+ action, priority, cookie, group_id, tech_profile_id, enable_encryption);
if (st.error_code() == grpc::StatusCode::OK) {
device_flow dev_fl;
dev_fl.is_flow_replicated = false;
@@ -1607,10 +1624,11 @@
::openolt::Classifier cl = ::openolt::Classifier(classifier);
flow_id = dev_fl.params[cnt].flow_id;
gemport_id = dev_fl.params[cnt].gemport_id;
+ enable_encryption = get_aes_flag_for_gem_port(gemport_to_aes, gemport_id);
cl.set_o_pbits(dev_fl.params[cnt].pbit);
Status st = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id,
flow_type, alloc_id, network_intf_id, gemport_id, cl,
- action, priority, cookie, group_id, tech_profile_id);
+ action, priority, cookie, group_id, tech_profile_id, enable_encryption);
if (st.error_code() != grpc::StatusCode::OK) {
OPENOLT_LOG(ERROR, openolt_log_id, "failed to install device flow=%u for voltha flow=%lu. Undoing any device flows installed.", flow_id, voltha_flow_id);
// Remove any successfully replicated flows installed so far for the voltha_flow_id
@@ -1644,7 +1662,7 @@
int32_t alloc_id, int32_t network_intf_id,
int32_t gemport_id, const ::openolt::Classifier& classifier,
const ::openolt::Action& action, int32_t priority_value, uint64_t cookie,
- int32_t group_id, uint32_t tech_profile_id) {
+ int32_t group_id, uint32_t tech_profile_id, bool aes_enabled) {
bcmolt_flow_cfg cfg;
bcmolt_flow_key key = { }; /**< Object key. */
int32_t o_vid = -1;
@@ -1698,13 +1716,13 @@
return bcm_to_grpc_err(BCM_ERR_PARM, "flow network setting invalid");
}
- if (onu_id >= 0) {
+ if (onu_id >= ONU_ID_START) {
BCMOLT_MSG_FIELD_SET(&cfg, onu_id, onu_id);
}
- if (gemport_id >= 0) {
+ if (gemport_id >= GEM_PORT_ID_START) {
BCMOLT_MSG_FIELD_SET(&cfg, svc_port_id, gemport_id);
}
- if (gemport_id >= 0 && port_no != 0) {
+ if (gemport_id >= GEM_PORT_ID_START && port_no != 0) {
bcmos_fastlock_lock(&data_lock);
if (key.flow_type == BCMOLT_FLOW_TYPE_DOWNSTREAM) {
port_to_flows[port_no].insert(key.flow_id);
@@ -1856,7 +1874,7 @@
BCMOLT_MSG_FIELD_SET(&cfg, action, a_val);
- if ((access_intf_id >= 0) && (onu_id >= 0)) {
+ if ((access_intf_id >= 0) && (onu_id >= ONU_ID_START)) {
qos_type = get_qos_type(access_intf_id, onu_id, uni_id);
if (key.flow_type == BCMOLT_FLOW_TYPE_DOWNSTREAM) {
tm_val.sched_id = get_tm_sched_id(access_intf_id, onu_id, uni_id, downstream, tech_profile_id);
@@ -1996,6 +2014,22 @@
bcmos_fastlock_unlock(&data_lock, 0);
}
+
+ /*
+ Enable AES encryption on GEM ports if they are used in downstream unicast flows.
+ Rationale: We can't do upstream encryption in GPON. This change addresses the common denominator (and also minimum viable)
+ use case for both technologies which is downstream unicast GEM port encryption. Since the downstream traffic is inherently
+ broadcast to all the ONUs behind a PON port, encrypting the individual subscriber traffic in this direction is important
+ and considered good enough in terms of security (See Section 12.1 of G.984.3). For upstream unicast and downstream multicast
+ GEM encryption, we need to make additional changes specific to XGSPON. This will be done as a future work.
+ */
+ if (aes_enabled && (access_intf_id >= 0) && (gemport_id >= GEM_PORT_ID_START) && (key.flow_type == BCMOLT_FLOW_TYPE_DOWNSTREAM)) {
+ OPENOLT_LOG(INFO, openolt_log_id, "Setting encryption on pon = %d gem_port = %d through flow_id = %d\n", access_intf_id, gemport_id, flow_id);
+ enable_encryption_for_gem_port(access_intf_id, gemport_id);
+ } else {
+ OPENOLT_LOG(WARNING, openolt_log_id, "Flow config for flow_id = %d is not suitable for setting downstream encryption on pon = %d gem_port = %d. No action taken.\n", flow_id, access_intf_id, gemport_id);
+ }
+
return Status::OK;
}
diff --git a/agent/src/core_utils.cc b/agent/src/core_utils.cc
index 968975e..59c7cdc 100644
--- a/agent/src/core_utils.cc
+++ b/agent/src/core_utils.cc
@@ -918,7 +918,7 @@
err = bcmolt_cfg_set(dev_id, &cfg.hdr);
if(err != BCM_ERR_OK) {
- OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d err_text=%s\n", gemport_id, cfg.hdr.hdr.err_text);
+ OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d err = %s (%d)\n", gemport_id, cfg.hdr.hdr.err_text, err);
return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
}
@@ -939,7 +939,7 @@
err = bcmolt_cfg_clear(dev_id, &gem_cfg.hdr);
if (err != BCM_ERR_OK)
{
- OPENOLT_LOG(ERROR, openolt_log_id, "failed to remove gem_port = %d err=%s\n", gemport_id, gem_cfg.hdr.hdr.err_text);
+ OPENOLT_LOG(ERROR, openolt_log_id, "failed to remove gem_port = %d err = %s (%d)\n", gemport_id, gem_cfg.hdr.hdr.err_text, err);
return bcm_to_grpc_err(err, "Access_Control clear ITU PON Gem port failed");
}
@@ -948,6 +948,32 @@
return Status::OK;
}
+Status enable_encryption_for_gem_port(int32_t intf_id, int32_t gemport_id) {
+ bcmos_errno err;
+ bcmolt_itupon_gem_cfg cfg;
+ bcmolt_itupon_gem_key key = {
+ .pon_ni = (bcmolt_interface)intf_id,
+ .gem_port_id = (bcmolt_gem_port_id)gemport_id
+ };
+
+ BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
+
+ bcmolt_control_state encryption_mode;
+ encryption_mode = BCMOLT_CONTROL_STATE_ENABLE;
+ BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
+
+ err = bcmolt_cfg_set(dev_id, &cfg.hdr);
+ if(err != BCM_ERR_OK) {
+ OPENOLT_LOG(ERROR, openolt_log_id, "failed to set encryption on pon = %d gem_port = %d, err = %s (%d)\n",
+ intf_id, gemport_id, cfg.hdr.hdr.err_text, err);
+ return bcm_to_grpc_err(err, "Failed to set encryption on GEM port");;
+ }
+
+ OPENOLT_LOG(INFO, openolt_log_id, "encryption set successfully on pon = %d gem_port = %d\n", intf_id, gemport_id);
+
+ return Status::OK;
+}
+
Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
bcmolt_members_update_command acl_cmd) {
bcmos_errno err;
diff --git a/agent/src/core_utils.h b/agent/src/core_utils.h
index 8404912..0f7cfe7 100644
--- a/agent/src/core_utils.h
+++ b/agent/src/core_utils.h
@@ -93,6 +93,7 @@
bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state);
Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t gemport_id);
Status remove_gem_port(int32_t intf_id, int32_t gemport_id);
+Status enable_encryption_for_gem_port(int32_t intf_id, int32_t gemport_id);
Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
bcmolt_members_update_command acl_cmd);
Status install_acl(const acl_classifier_key acl_key);
diff --git a/agent/test/Makefile b/agent/test/Makefile
index 66986e3..df93b7c 100644
--- a/agent/test/Makefile
+++ b/agent/test/Makefile
@@ -21,7 +21,7 @@
TOP_DIR=`pwd`
OPENOLTDEVICE ?= asfvolt16
-OPENOLT_PROTO_VER ?= v4.0.11
+OPENOLT_PROTO_VER ?= v4.0.14
########################################################################
##
diff --git a/agent/test/src/test_core.cc b/agent/test/src/test_core.cc
index 7efb8c9..2d2bede 100644
--- a/agent/test/src/test_core.cc
+++ b/agent/test/src/test_core.cc
@@ -1237,6 +1237,7 @@
uint64_t cookie = 0;
int32_t group_id = -1;
uint32_t tech_profile_id = 64;
+ bool enable_encryption = true;
NiceMock<BalMocker> balMock;
openolt::Flow* flow;
@@ -1536,7 +1537,81 @@
ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
}
+// Test 11 - FlowAdd - success case (Downstream-Encrypted GEM)
+TEST_F(TestFlowAdd, FlowAddDownstreamEncryptedGemSuccess) {
+ onu_id = 2;
+ flow_id = 7;
+ flow_type = "downstream";
+ alloc_id = 1025;
+ enable_encryption = true;
+ bcmos_errno flow_cfg_get_stub_res = BCM_ERR_OK;
+ bcmos_errno olt_cfg_set_res = BCM_ERR_OK;
+ EXPECT_GLOBAL_CALL(bcmolt_cfg_get__flow_stub, bcmolt_cfg_get__flow_stub(_, _))
+ .WillRepeatedly(DoAll(SetArg1ToBcmOltFlowCfg(flow_cfg), Return(flow_cfg_get_stub_res)));
+ ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
+
+ Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
+ gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id, enable_encryption);
+ ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
+}
+
+// Test 12 - FlowAdd - success case (Downstream-Unencrypted GEM - prints warning that encryption will not applied)
+TEST_F(TestFlowAdd, FlowAddDownstreamUnencryptedGemWarning) {
+ onu_id = 2;
+ flow_id = 8;
+ flow_type = "downstream";
+ alloc_id = 1025;
+ enable_encryption = false;
+
+ bcmos_errno flow_cfg_get_stub_res = BCM_ERR_OK;
+ bcmos_errno olt_cfg_set_res = BCM_ERR_OK;
+ EXPECT_GLOBAL_CALL(bcmolt_cfg_get__flow_stub, bcmolt_cfg_get__flow_stub(_, _))
+ .WillRepeatedly(DoAll(SetArg1ToBcmOltFlowCfg(flow_cfg), Return(flow_cfg_get_stub_res)));
+ ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
+
+ Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
+ gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id, enable_encryption);
+ ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
+}
+
+// Test 13 - FlowAdd - success case (Upstream-Encrypted GEM - prints warning that encryption will not applied)
+TEST_F(TestFlowAdd, FlowAddUpstreamEncryptedGemWarning) {
+ onu_id = 2;
+ flow_id = 9;
+ flow_type = "upstream";
+ alloc_id = 1025;
+ enable_encryption = true;
+
+ bcmos_errno flow_cfg_get_stub_res = BCM_ERR_OK;
+ bcmos_errno olt_cfg_set_res = BCM_ERR_OK;
+ EXPECT_GLOBAL_CALL(bcmolt_cfg_get__flow_stub, bcmolt_cfg_get__flow_stub(_, _))
+ .WillRepeatedly(DoAll(SetArg1ToBcmOltFlowCfg(flow_cfg), Return(flow_cfg_get_stub_res)));
+ ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
+
+ Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
+ gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id, enable_encryption);
+ ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
+}
+
+// Test 14 - FlowAdd - success case (Multicast-Encrypted GEM - prints warning that encryption will not applied)
+TEST_F(TestFlowAdd, FlowAddMulticastEncryptedGemWarning) {
+ onu_id = 2;
+ flow_id = 10;
+ flow_type = "multicast";
+ alloc_id = 1025;
+ enable_encryption = true;
+
+ bcmos_errno flow_cfg_get_stub_res = BCM_ERR_OK;
+ bcmos_errno olt_cfg_set_res = BCM_ERR_OK;
+ EXPECT_GLOBAL_CALL(bcmolt_cfg_get__flow_stub, bcmolt_cfg_get__flow_stub(_, _))
+ .WillRepeatedly(DoAll(SetArg1ToBcmOltFlowCfg(flow_cfg), Return(flow_cfg_get_stub_res)));
+ ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
+
+ Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
+ gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id, enable_encryption);
+ ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
+}
////////////////////////////////////////////////////////////////////////////
// For testing OnuPacketOut functionality
////////////////////////////////////////////////////////////////////////////
@@ -1716,6 +1791,10 @@
FlowRemove_(4, "downstream");
FlowRemove_(5, "upstream");
FlowRemove_(6, "downstream");
+ FlowRemove_(7, "downstream");
+ FlowRemove_(8, "downstream");
+ FlowRemove_(9, "upstream");
+ FlowRemove_(10, "multicast");
bcmos_errno flow_cfg_get_stub_res = BCM_ERR_OK;
EXPECT_GLOBAL_CALL(bcmolt_cfg_get__flow_stub, bcmolt_cfg_get__flow_stub(_, _))