diff --git a/include/aca_security_group.h b/include/aca_security_group.h new file mode 100644 index 00000000..3e549f03 --- /dev/null +++ b/include/aca_security_group.h @@ -0,0 +1,188 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ALCOR_CONTROL_AGENT_SECURITY_GROUP_H +#define ALCOR_CONTROL_AGENT_SECURITY_GROUP_H +#include +#include +#include +#include +#include + +using namespace std; + +namespace aca_security_group +{ + +enum OperationType { + CREATE=1, + UPDATE, + DELETE, + UNKNOWN_OPERATION, +}; + +enum Direction { + INGRESS=1, + EGRESS, + UNKNOWN_DIRECTION, +}; + +enum Ethertype { + IPV4=0x0800, + ARP=0x0806, + IPV6=0x86dd, + UNKNOWN_ETHERTYPE, +}; + +enum Protocol { + TCP=6, + UDP=17, + ICMP=1, + UNKNOWN_PROTO +}; + +class Aca_Security_Group; + +class Aca_Security_Group_Rule { +public: + static Aca_Security_Group_Rule &get_instance(); + void set_id(string id); + string get_id(void); + void set_name(string name); + string get_name(void); + void set_cookie(uint64_t cookie); + uint64_t get_cookie(void); + void set_direction(Direction direction); + Direction get_direction(void); + void set_ethertype(Ethertype ethertype); + Ethertype get_ethertype(void); + void set_protocol(Protocol protocol); + Protocol get_protocol(void); + uint32_t get_port_range_min(void); + void set_port_range_min(uint32_t port_range_min); + uint32_t get_port_range_max(void); + void set_port_range_max(uint32_t port_range_max); + string get_remote_ip_prefix(void); + void set_remote_ip_prefix(string remote_ip_prefix); + void set_remote_group_id(string remote_group_id); + string get_remote_group_id(void); + void set_operation_type(OperationType operation_type); + OperationType get_operation_type(void); + void set_remote_group(Aca_Security_Group * remote_group); + Aca_Security_Group * get_remote_group(void); + +private: + string id; + string name; + uint64_t cookie; + Direction direction; + Ethertype ethertype; + Protocol protocol; + uint32_t port_range_min; + uint32_t port_range_max; + string remote_ip_prefix; + string remote_group_id; + OperationType operation_type; + Aca_Security_Group *remote_group; +}; + +class Aca_Security_Group { +public: + Aca_Security_Group(); + Aca_Security_Group(Aca_Security_Group &sg); + void set_id(string id); + string get_id(void); + void set_name(string name); + string get_name(void); + void set_format_version(uint32_t format_version); + uint32_t get_format_version(void); + void set_revision_number(uint32_t revision_number); + uint32_t get_revision_number(void); + void set_vpc_id(string vpc_id); + string get_vpc_id(void); + void set_operation_type(OperationType operation_type); + OperationType get_operation_type(void); + void add_port_id(string port_id); + void delete_port_id(string port_id); + int get_port_num(void); + set &get_port_ids(void); + void add_security_group_rule(Aca_Security_Group_Rule *sg_rule); + void update_security_group_rule(Aca_Security_Group_Rule *sg_rule); + void delete_security_group_rule(string sg_rule_id); + Aca_Security_Group_Rule* get_security_group_rule(string sg_rule_id); + map get_security_group_rules(); + +private: + string id; + string name; + uint32_t format_version; + uint32_t revision_number; + string vpc_id; + OperationType operation_type; + set port_ids; + map rules; +}; + +class Aca_Port { +public: + Aca_Port(); + Aca_Port(Aca_Port &port); + void set_id(string id); + string get_id(void); + void set_name(string name); + string get_name(void); + void set_ofport(uint32_t ofport); + uint32_t get_ofport(void); + void set_vni(uint32_t vni); + uint32_t get_vni(void); + void set_format_version(uint32_t format_version); + uint32_t get_format_version(void); + void set_revision_number(uint32_t revision_number); + uint32_t get_revision_number(void); + void set_vpc_id(string vpc_id); + string get_vpc_id(void); + void set_mac_address(string mac_address); + string get_mac_address(void); + void add_fixed_ip(string fixed_ip); + vector &get_fixed_ip(void); + void add_security_group_id(string security_group_id); + void delete_security_group_id(string security_group_id); + int get_security_group_num(void); + void add_allow_address_pair(string ip_address, string mac_address); + int allow_address_pairs_size(void); + vector> get_allow_address_pairs(void); + void add_security_group(Aca_Security_Group *security_group); + Aca_Security_Group *get_security_group(string sg_id); + +private: + string id; + string name; + uint32_t ofport; + uint32_t vni; + uint32_t format_version; + uint32_t revision_number; + string vpc_id; + string mac_address; + vector fixed_ips; + set security_group_ids; + vector> allow_address_pairs; + map security_groups; +}; + +} + +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_H diff --git a/include/aca_security_group_manager.h b/include/aca_security_group_manager.h new file mode 100644 index 00000000..74848c87 --- /dev/null +++ b/include/aca_security_group_manager.h @@ -0,0 +1,46 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H +#define ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H +#include "aca_security_group.h" + + +namespace aca_security_group { + +class Aca_Security_Group_Manager { +public: + static Aca_Security_Group_Manager &get_instance(); + int create_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int update_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int delete_security_group_rule(Aca_Port &port, Aca_Security_Group &sg, Aca_Security_Group_Rule &sg_rule); + int create_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg); + int update_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg); + int delete_security_group(Aca_Port &input_port, Aca_Security_Group &input_sg); + + map &get_ports(void); + map &get_security_groups(void); + +private: + int set_remote_group(Aca_Security_Group_Rule &sg_rule); + + map ports; + map security_groups; +}; + +} +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_MANAGER_H diff --git a/include/aca_security_group_ovs.h b/include/aca_security_group_ovs.h new file mode 100644 index 00000000..213d17c5 --- /dev/null +++ b/include/aca_security_group_ovs.h @@ -0,0 +1,83 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H +#define ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H + +#include "aca_security_group.h" + + +namespace aca_security_group { + +#define TRANSIENT_TABLE 60 +#define BASE_EGRESS_TABLE 71 +#define RULES_EGRESS_TABLE 72 +#define ACCEPT_OR_INGRESS_TABLE 73 +#define BASE_INGRESS_TABLE 81 +#define RULES_INGRESS_TABLE 82 +#define ACCEPTED_EGRESS_TRAFFIC_TABLE 91 +#define ACCEPTED_INGRESS_TRAFFIC_TABLE 92 +#define DROPPED_TRAFFIC_TABLE 93 +#define ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE 94 + +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_IPV6 0x86dd + +#define PROTO_NUM_ICMP 1 +#define PROTO_NUM_TCP 6 +#define PROTO_NUM_UDP 17 + +#define REG_PORT 5 +#define REG_NET 6 + +#define BR_INT "br-int" +#define BR_TUN "br-tun" + +#define FLOW_PRIORITY_BASE 70 + +class Aca_Security_Group_Ovs { +public: + static Aca_Security_Group_Ovs &get_instance(); + void init_port_flows(Aca_Port &port); + void clear_port_flows(Aca_Port &port); + int create_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule); + int update_port_security_group_rule(Aca_Port &port, Aca_Security_Group_Rule &new_sg_rule, Aca_Security_Group_Rule &old_sg_rule); + int delete_port_security_group_rule(Aca_Port &port, Aca_Security_Group_Rule &sg_rule); +private: + int get_vlan_by_segment_id(const int segment_id); + void init_port_egress_flows(Aca_Port &port); + void init_port_ingress_flows(const Aca_Port &port); + int flow_priority_offset(Aca_Security_Group_Rule &sg_rule, bool conjunction); + int get_dl_type_by_ether_type(uint32_t ether_type); + string get_nw_proto_by_protocol(uint32_t protocol); + int get_remote_group_conj_id(Aca_Security_Group_Rule &sg_rule); + int build_flows_by_sg_rule(Aca_Port &port,Aca_Security_Group_Rule &sg_rule, bool del_flow, vector &flows); + int build_conjunction_flows(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, vector &flows); + int get_remote_group_ips(Aca_Security_Group *remote_group, vector &remote_ips); + int build_flows_by_remote_ip(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, string remote_ip, int conj_id, vector &flows); + int build_flow_match_fileds(Aca_Port &port, Aca_Security_Group_Rule &sg_rule, bool del_flow, vector &flows); + int add_conjunction_actions(string _flow, int conj_id, int dimension, vector &flows); + int build_accept_flows(Aca_Port &port,Aca_Security_Group_Rule &sg_rule, int conj_id, vector &flows); + + uint64_t conj_id_base; + map conj_ids; +}; + +} +#endif //ALCOR_CONTROL_AGENT_SECURITY_GROUP_OVS_H diff --git a/include/aca_sg_state_handler.h b/include/aca_sg_state_handler.h new file mode 100644 index 00000000..8d73fdaf --- /dev/null +++ b/include/aca_sg_state_handler.h @@ -0,0 +1,45 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ALCOR_CONTROL_AGENT_ACA_SG_STATE_HANDLER_H +#define ALCOR_CONTROL_AGENT_ACA_SG_STATE_HANDLER_H +#include "aca_security_group.h" +#include "goalstateprovisioner.grpc.pb.h" + +namespace aca_security_group +{ +class Aca_Sg_State_Handler { +public: + static Aca_Sg_State_Handler &get_instance(); + int update_security_group_states(const alcor::schema::GoalState &goal_state, + alcor::schema::GoalStateOperationReply &reply); + +private: + // constructor and destructor marked as private so that noone can call it + // for the singleton implementation + Aca_Sg_State_Handler(); + ~Aca_Sg_State_Handler(); + Aca_Port * parse_port_state(const alcor::schema::PortState &port_state); + void parse_security_group_states(const alcor::schema::GoalState &goal_state, std::map &sg_state_map); + OperationType get_operation_type(alcor::schema::OperationType operation_type); + Direction get_direction(alcor::schema::SecurityGroupConfiguration::Direction direction); + Ethertype get_ethertype(alcor::schema::EtherType ethertype); + Protocol get_protocol(alcor::schema::Protocol protocol); + int handle_port_security_group(Aca_Port &aca_port, Aca_Security_Group &aca_sg); +}; +} +#endif //ALCOR_CONTROL_AGENT_ACA_SG_STATE_HANDLER_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 643df590..a7b9a3e4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,7 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../build/bin) +add_definitions("-O0 -g") + set(SOURCES ./comm/aca_message_producer.cpp ./comm/aca_message_consumer.cpp @@ -15,8 +17,12 @@ set(SOURCES ./ovs/aca_ovs_control.cpp ./dhcp/aca_dhcp_state_handler.cpp ./dhcp/aca_dhcp_server.cpp + ./sg/aca_sg_state_handler.cpp + ./sg/aca_security_group.cpp + ./sg/aca_security_group_manager.cpp + ./sg/aca_security_group_ovs.cpp ) -FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu NO_DEFAULT_PATH) +FIND_LIBRARY(RDKAFKA rdkafka /usr/lib/x86_64-linux-gnu /usr/local/lib NO_DEFAULT_PATH) #for centos FIND_LIBRARY(CPPKAFKA cppkafka /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(OPENVSWITCH openvswitch /usr/local/lib NO_DEFAULT_PATH) FIND_LIBRARY(MESSAGEMANAGER messagemanager ${CMAKE_CURRENT_SOURCE_DIR}/../include NO_DEFAULT_PATH) diff --git a/src/comm/aca_comm_mgr.cpp b/src/comm/aca_comm_mgr.cpp index 573cf336..785dab54 100644 --- a/src/comm/aca_comm_mgr.cpp +++ b/src/comm/aca_comm_mgr.cpp @@ -17,12 +17,14 @@ #include "aca_comm_mgr.h" #include "aca_goal_state_handler.h" #include "aca_dhcp_state_handler.h" +#include "aca_sg_state_handler.h" #include "goalstateprovisioner.grpc.pb.h" using namespace std; using namespace alcor::schema; using namespace aca_goal_state_handler; using namespace aca_dhcp_state_handler; +using namespace aca_security_group; extern string g_rpc_server; extern string g_rpc_protocol; @@ -126,6 +128,17 @@ int Aca_Comm_Manager::update_goal_state(GoalState &goal_state_message, rc = exec_command_rc; } + if (goal_state_message.security_group_states_size() > 0) { + exec_command_rc = Aca_Sg_State_Handler::get_instance().update_security_group_states( + goal_state_message, gsOperationReply); + if (exec_command_rc == EXIT_SUCCESS) { + ACA_LOG_INFO("Successfully security group states, rc: %d\n", exec_command_rc); + } else { + ACA_LOG_ERROR("Failed to security group states. rc: %d\n", exec_command_rc); + rc = exec_command_rc; + } + } + auto end = chrono::steady_clock::now(); auto message_total_operation_time = cast_to_nanoseconds(end - start).count(); diff --git a/src/ovs/aca_ovs_l2_programmer.cpp b/src/ovs/aca_ovs_l2_programmer.cpp index ab099296..2709b39f 100644 --- a/src/ovs/aca_ovs_l2_programmer.cpp +++ b/src/ovs/aca_ovs_l2_programmer.cpp @@ -322,7 +322,7 @@ void ACA_OVS_L2_Programmer::execute_ovsdb_command(const std::string cmd_string, auto ovsdb_client_start = chrono::steady_clock::now(); - string ovsdb_cmd_string = "/usr/bin/ovs-vsctl " + cmd_string; + string ovsdb_cmd_string = "ovs-vsctl " + cmd_string; int rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(ovsdb_cmd_string); if (rc != EXIT_SUCCESS) { @@ -349,7 +349,7 @@ void ACA_OVS_L2_Programmer::execute_openflow_command(const std::string cmd_strin auto openflow_client_start = chrono::steady_clock::now(); - string openflow_cmd_string = "/usr/bin/ovs-ofctl " + cmd_string; + string openflow_cmd_string = "ovs-ofctl " + cmd_string; int rc = aca_net_config::Aca_Net_Config::get_instance().execute_system_command(openflow_cmd_string); if (rc != EXIT_SUCCESS) { diff --git a/src/sg/aca_security_group.cpp b/src/sg/aca_security_group.cpp new file mode 100644 index 00000000..dd92d510 --- /dev/null +++ b/src/sg/aca_security_group.cpp @@ -0,0 +1,353 @@ +// +// Created by Administrator on 2020/10/12. +// +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "aca_security_group.h" + +using namespace std; + + +namespace aca_security_group { + +void Aca_Security_Group_Rule::set_id(string id) { + this->id = id; +} + +string Aca_Security_Group_Rule::get_id(void) { + return this->id; +} + +void Aca_Security_Group_Rule::set_name(string name) { + this->name = name; +} + + +string Aca_Security_Group_Rule::get_name(void) { + return this->name; +} + +void Aca_Security_Group_Rule::set_cookie(uint64_t cookie) { + this->cookie = cookie; +} + +uint64_t Aca_Security_Group_Rule::get_cookie(void) { + return this->cookie; +} + +void Aca_Security_Group_Rule::set_direction(Direction direction) { + this->direction = direction; +} + +Direction Aca_Security_Group_Rule::get_direction(void) { + return this->direction; +} + +void Aca_Security_Group_Rule::set_ethertype(Ethertype ethertype) { + this->ethertype = ethertype; + +} + +Ethertype Aca_Security_Group_Rule::get_ethertype(void) { + return this->ethertype; +} + +void Aca_Security_Group_Rule::set_protocol(Protocol protocol) { + this->protocol = protocol; + +} +Protocol Aca_Security_Group_Rule::get_protocol(void) { + return this->protocol; +} + +void Aca_Security_Group_Rule::set_port_range_min(uint32_t port_range_min) { + this->port_range_min = port_range_min; +} + +uint32_t Aca_Security_Group_Rule::get_port_range_min(void) { + return this->port_range_min; +} + +void Aca_Security_Group_Rule::set_port_range_max(uint32_t port_range_max) { + this->port_range_max = port_range_max; +} + +uint32_t Aca_Security_Group_Rule::get_port_range_max(void) { + return this->port_range_max; +} + +void Aca_Security_Group_Rule::set_remote_ip_prefix(string remote_ip_prefix) { + this->remote_ip_prefix = remote_ip_prefix; +} + +string Aca_Security_Group_Rule::get_remote_ip_prefix(void) { + return this->remote_ip_prefix; +} + +void Aca_Security_Group_Rule::set_remote_group_id(string remote_group_id) { + this->remote_group_id = remote_group_id; +} + +string Aca_Security_Group_Rule::get_remote_group_id(void) { + return this->remote_group_id; +} + +void Aca_Security_Group_Rule::set_operation_type(OperationType operation_type) { + this->operation_type = operation_type; +} + +OperationType Aca_Security_Group_Rule::get_operation_type(void) { + return this->operation_type; +} + +void Aca_Security_Group_Rule::set_remote_group(Aca_Security_Group * remote_group) { + this->remote_group = remote_group; +} + +Aca_Security_Group * Aca_Security_Group_Rule::get_remote_group(void) { + return this->remote_group; +} + +Aca_Security_Group::Aca_Security_Group() { +} + +Aca_Security_Group::Aca_Security_Group(Aca_Security_Group &sg) { + this->id = sg.get_id(); + this->name = sg.get_name(); + this->format_version = sg.get_format_version(); + this->revision_number = sg.get_revision_number(); + this->vpc_id = sg.get_vpc_id(); + this->operation_type = sg.get_operation_type(); +} + +void Aca_Security_Group::set_id(string id) { + this->id = id; +} + +string Aca_Security_Group::get_id(void) { + return this->id; +} + +void Aca_Security_Group::set_name(string name) { + this->name = name; +} + +string Aca_Security_Group::get_name(void) { + return this->name; +} +void Aca_Security_Group::set_format_version(uint32_t format_version) { + this->format_version = format_version; +} +uint32_t Aca_Security_Group::get_format_version(void) { + return this->format_version; +} +void Aca_Security_Group::set_revision_number(uint32_t revision_number) { + this->revision_number = revision_number; +} +uint32_t Aca_Security_Group::get_revision_number(void) { + return this->revision_number; +} + +void Aca_Security_Group::set_vpc_id(string vpc_id) { + this->vpc_id = vpc_id; +} +string Aca_Security_Group::get_vpc_id(void) { + return this->vpc_id; +} + +void Aca_Security_Group::set_operation_type(OperationType operation_type) { + this->operation_type = operation_type; +} + +OperationType Aca_Security_Group::get_operation_type(void) { + return this->operation_type; +} + +void Aca_Security_Group::add_port_id(string port_id) { + this->port_ids.insert(port_id); +} + +void Aca_Security_Group::delete_port_id(string port_id) { + this->port_ids.erase(port_id); +} + +int Aca_Security_Group::get_port_num(void) { + return this->port_ids.size(); +} + +set &Aca_Security_Group::get_port_ids(void) { + return this->port_ids; +} + +void Aca_Security_Group::add_security_group_rule(Aca_Security_Group_Rule *sg_rule) { + Aca_Security_Group_Rule *new_sg_rule = new Aca_Security_Group_Rule(*sg_rule); + this->rules[new_sg_rule->get_id()] = new_sg_rule; +} + +void Aca_Security_Group::update_security_group_rule(Aca_Security_Group_Rule *sg_rule) { + Aca_Security_Group_Rule *old_sg_rule = get_security_group_rule(sg_rule->get_id()); + if (old_sg_rule != NULL) { + delete old_sg_rule; + } + + add_security_group_rule(sg_rule); +} + +void Aca_Security_Group::delete_security_group_rule(string sg_rule_id) { + Aca_Security_Group_Rule *old_sg_rule = get_security_group_rule(sg_rule_id); + if (old_sg_rule != NULL) { + this->rules.erase(sg_rule_id); + delete old_sg_rule; + } +} + + +Aca_Security_Group_Rule* Aca_Security_Group::get_security_group_rule(string sg_rule_id) { + map::iterator iterator = this->rules.find(sg_rule_id); + if (iterator != this->rules.end()) { + return iterator->second; + } + + return NULL; +} +map Aca_Security_Group::get_security_group_rules(void) { + return this->rules; +} + +Aca_Port::Aca_Port() { +} + +Aca_Port::Aca_Port(Aca_Port &port) { + this->id = port.get_id(); + this->name = port.get_name(); + this->ofport = port.get_ofport(); + this->vni = port.get_vni(); + this->format_version = port.get_format_version(); + this->revision_number = port.get_revision_number(); + this->vpc_id = port.get_vpc_id(); + this->mac_address = port.get_mac_address(); + this->fixed_ips = port.get_fixed_ip(); +} + +void Aca_Port::set_id(string id) { + this->id = id; +} + +string Aca_Port::get_id(void) { + return this->id; +} + +void Aca_Port::set_name(string name) { + this->name = name; +} + +string Aca_Port::get_name(void) { + return this->name; +} + +void Aca_Port::set_ofport(uint32_t ofport) { + this->ofport = ofport; +} + +uint32_t Aca_Port::get_ofport(void) { + return this->ofport; +} + +void Aca_Port::set_vni(uint32_t vni) { + this->vni = vni; +} + +uint32_t Aca_Port::get_vni(void) { + return this->vni; +} + +void Aca_Port::set_format_version(uint32_t format_version) { + this->format_version = format_version; +} +uint32_t Aca_Port::get_format_version(void) { + return this->format_version; +} +void Aca_Port::set_revision_number(uint32_t revision_number) { + this->revision_number = revision_number; +} +uint32_t Aca_Port::get_revision_number(void) { + return this->revision_number; +} + +void Aca_Port::set_vpc_id(string vpc_id) { + this->vpc_id = vpc_id; +} + +string Aca_Port::get_vpc_id(void) { + return this->vpc_id; +} + +void Aca_Port::set_mac_address(string mac_address) { + this->mac_address = mac_address; +} + +string Aca_Port::get_mac_address(void) { + return this->mac_address; +} + +void Aca_Port::add_fixed_ip(string fixed_ip) { + this->fixed_ips.push_back(fixed_ip); +} + +vector &Aca_Port::get_fixed_ip(void) { + return this->fixed_ips; +} + +void Aca_Port::add_security_group_id(string security_group_id) { + this->security_group_ids.insert(security_group_id); +} + +void Aca_Port::delete_security_group_id(string security_group_id) { + this->security_group_ids.erase(security_group_id); +} + +int Aca_Port::get_security_group_num(void) { + return this->security_group_ids.size(); +} + +void Aca_Port::add_allow_address_pair(string ip_address, string mac_address) { + pair allow_address_pair(ip_address, mac_address); + this->allow_address_pairs.push_back(allow_address_pair); +} + +int Aca_Port::allow_address_pairs_size(void) +{ + return this->allow_address_pairs.size(); +} + +vector> Aca_Port::get_allow_address_pairs() +{ + return this->allow_address_pairs; +} + +void Aca_Port::add_security_group(Aca_Security_Group *security_group) { + this->security_groups.insert(pair(security_group->get_id(), security_group)); +} + +Aca_Security_Group *Aca_Port::get_security_group(string sg_id) { + map::iterator iterator = this->security_groups.find(sg_id); + if (iterator != this->security_groups.end()) { + return iterator->second; + } + + return NULL; +} + + +} diff --git a/src/sg/aca_security_group_manager.cpp b/src/sg/aca_security_group_manager.cpp new file mode 100644 index 00000000..38b29981 --- /dev/null +++ b/src/sg/aca_security_group_manager.cpp @@ -0,0 +1,273 @@ +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "aca_log.h" +#include "aca_security_group.h" +#include "aca_security_group_manager.h" +#include "aca_security_group_ovs.h" + +using namespace std; + +namespace aca_security_group { + +Aca_Security_Group_Manager &Aca_Security_Group_Manager::get_instance() +{ + // It is instantiated on first use. + // allocated instance is destroyed when program exits. + static Aca_Security_Group_Manager instance; + return instance; +} + +map &Aca_Security_Group_Manager::get_ports(void) +{ + return this->ports; +} + +map &Aca_Security_Group_Manager::get_security_groups(void) +{ + return this->security_groups; +} + +int Aca_Security_Group_Manager::set_remote_group(Aca_Security_Group_Rule &sg_rule) +{ + map::iterator iter; + string remote_grou_id = sg_rule.get_remote_group_id(); + + if (remote_grou_id != "") { + iter = this->security_groups.find(remote_grou_id); + if (iter == this->security_groups.end()) { + return EXIT_FAILURE; + } + + sg_rule.set_remote_group(iter->second); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::create_security_group_rule(Aca_Port &port, + Aca_Security_Group &sg, + Aca_Security_Group_Rule &sg_rule) +{ + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + string rule_id; + Aca_Security_Group_Rule *aca_sg_rule; + rule_id = sg_rule.get_id(); + + aca_sg_rule = sg.get_security_group_rule(rule_id); + if (aca_sg_rule != NULL) { + TRN_LOG_WARN("Security group rule(id:%s) already exist", rule_id.data()); + return update_security_group_rule(port, sg, sg_rule); + } + + if (set_remote_group(sg_rule) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + sg_rule.set_cookie(0); + sg_ovs.create_port_security_group_rule(port, sg_rule); + sg.add_security_group_rule(&sg_rule); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::update_security_group_rule(Aca_Port &port, + Aca_Security_Group &sg, + Aca_Security_Group_Rule &sg_rule) +{ + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + string rule_id; + Aca_Security_Group_Rule *aca_sg_rule; + rule_id = sg_rule.get_id(); + + aca_sg_rule = sg.get_security_group_rule(rule_id); + if (aca_sg_rule == NULL) { + ACA_LOG_ERROR("Can not find security group rule by id:%s", rule_id.data()); + return EXIT_FAILURE; + } + + if (set_remote_group(sg_rule) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + sg_rule.set_cookie(aca_sg_rule->get_cookie() + 1); + sg_ovs.update_port_security_group_rule(port, sg_rule, *aca_sg_rule); + sg.update_security_group_rule(&sg_rule); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::delete_security_group_rule(Aca_Port &port, + Aca_Security_Group &sg, + Aca_Security_Group_Rule &sg_rule) +{ + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + string rule_id; + Aca_Security_Group_Rule *aca_sg_rule; + rule_id = sg_rule.get_id(); + + aca_sg_rule = sg.get_security_group_rule(rule_id); + if (aca_sg_rule == NULL) { + ACA_LOG_ERROR("Can not find security group rule by id:%s", rule_id.data()); + return EXIT_FAILURE; + } + + if (set_remote_group(sg_rule) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + sg_ovs.delete_port_security_group_rule(port, *aca_sg_rule); + sg.delete_security_group_rule(sg_rule.get_id()); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::create_security_group(Aca_Port &input_port, + Aca_Security_Group &input_sg) + { + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + map::iterator piter; + map::iterator siter; + Aca_Security_Group *aca_sg; + Aca_Port * aca_port; + string port_id = input_port.get_id(); + string sg_id = input_sg.get_id(); + + //TODO: maybe multi threads access this map + piter = this->ports.find(port_id); + if (piter == this->ports.end()) { + aca_port = new Aca_Port(input_port); + this->ports[port_id] = aca_port; + sg_ovs.init_port_flows(*aca_port); + } else { + aca_port = piter->second; + } + + siter = this->security_groups.find(sg_id); + if (siter == this->security_groups.end()) { + aca_sg = new Aca_Security_Group(input_sg); + this->security_groups[sg_id] = aca_sg; + } else { + aca_sg = siter->second; + } + + aca_sg->add_port_id(port_id); + aca_port->add_security_group_id(sg_id); + + for (auto &it : input_sg.get_security_group_rules()) { + create_security_group_rule(*aca_port, *aca_sg, *(it.second)); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::update_security_group(Aca_Port &input_port, + Aca_Security_Group &input_sg) +{ + map::iterator piter; + map::iterator siter; + Aca_Security_Group *aca_sg; + Aca_Port * aca_port; + + string port_id = input_port.get_id(); + string sg_id = input_sg.get_id(); + + //TODO: do we need to update the port ? + piter = this->ports.find(port_id); + if (piter == this->ports.end()) { + ACA_LOG_ERROR("Can not find port by id:%s", port_id.data()); + return EXIT_FAILURE; + } + + aca_port = piter->second; + + siter = this->security_groups.find(sg_id); + if (siter == this->security_groups.end()) { + ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); + return EXIT_FAILURE; + } + + aca_sg = siter->second; + + for (auto &it : input_sg.get_security_group_rules()) { + Aca_Security_Group_Rule *sg_rule = it.second; + switch (sg_rule->get_operation_type()) { + case CREATE: + create_security_group_rule(*aca_port, *aca_sg, *sg_rule); + break; + case UPDATE: + update_security_group_rule(*aca_port, *aca_sg, *sg_rule); + break; + case DELETE: + delete_security_group_rule(*aca_port, *aca_sg, *sg_rule); + break; + default: + ACA_LOG_ERROR("Invalid security group rule operation type"); + } + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Manager::delete_security_group(Aca_Port &input_port, + Aca_Security_Group &input_sg) +{ + Aca_Security_Group_Ovs &sg_ovs = Aca_Security_Group_Ovs::get_instance(); + map::iterator piter; + map::iterator siter; + Aca_Security_Group *aca_sg; + Aca_Port *aca_port; + + string port_id = input_port.get_id(); + string sg_id = input_sg.get_id(); + + piter = this->ports.find(port_id); + if (piter == this->ports.end()) { + ACA_LOG_ERROR("Can not find port by id:%s", port_id.data()); + return EXIT_FAILURE; + } + + aca_port = piter->second; + + siter = this->security_groups.find(sg_id); + if (siter == this->security_groups.end()) { + ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); + return EXIT_FAILURE; + } + + aca_sg = siter->second; + + //TODO: Special processing needs when overlapping security group rules are deleted + for (auto &it : input_sg.get_security_group_rules()) { + Aca_Security_Group_Rule *sg_rule = it.second; + delete_security_group_rule(*aca_port, *aca_sg, *sg_rule); + } + + aca_port->delete_security_group_id(sg_id); + if (aca_port->get_security_group_num() == 0) { + this->ports.erase(port_id); + sg_ovs.clear_port_flows(*aca_port); + delete aca_port; + } + + aca_sg->delete_port_id(port_id); + if (aca_sg->get_port_num() == 0) { + this->security_groups.erase(sg_id); + delete aca_sg; + } + + return EXIT_SUCCESS; +} + +} diff --git a/src/sg/aca_security_group_mizar.cpp b/src/sg/aca_security_group_mizar.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/sg/aca_security_group_ovs.cpp b/src/sg/aca_security_group_ovs.cpp new file mode 100644 index 00000000..c0ba327c --- /dev/null +++ b/src/sg/aca_security_group_ovs.cpp @@ -0,0 +1,610 @@ +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "aca_log.h" +#include "aca_security_group_ovs.h" +#include "aca_security_group_manager.h" +#include "aca_ovs_control.h" + +using namespace aca_ovs_control; + +namespace aca_security_group { + +static const char *ct_state[] = { + "+est-rel-rpl", + "+new-est" +}; + +Aca_Security_Group_Ovs &Aca_Security_Group_Ovs::get_instance() +{ + // It is instantiated on first use. + // allocated instance is destroyed when program exits. + static Aca_Security_Group_Ovs instance; + return instance; +} + +int Aca_Security_Group_Ovs::get_vlan_by_segment_id(const int segment_id) +{ + return segment_id; +} + +void Aca_Security_Group_Ovs::init_port_egress_flows(Aca_Port &port) +{ + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + char flow[128] = {0}; + + string port_id = port.get_id(); + string vpc_id = port.get_vpc_id(); + const char *mac_address = port.get_mac_address().data(); + int ofport = 12; + int patch_ofport = 13; + + int vni = 10; + int local_vlan = get_vlan_by_segment_id(vni); + + + // DHCP discovery + sprintf(flow, "table=%d,priority=80,in_port=%d,reg%d=%d,dl_type=0x%04x,nw_proto=%d," + "tp_src=68,tp_dst=67,actions=resubmit(,%d)", BASE_EGRESS_TABLE, ofport, REG_PORT, + ofport, ETHERTYPE_IP, PROTO_NUM_UDP, ACCEPT_OR_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); + + // Drop DHCP response from vm + sprintf(flow, "table=%d,priority=70,in_port=%d,reg%d=%d,dl_type=0x%04x,nw_proto=%d," + "tp_src=67,tp_dst=68,actions=resubmit(,%d)", BASE_EGRESS_TABLE, ofport, REG_PORT, + ofport, ETHERTYPE_IP, PROTO_NUM_UDP, DROPPED_TRAFFIC_TABLE); + controller.add_flow(BR_INT, flow); + + // Drop all remaining egress connections + sprintf(flow, "table=%d,priority=10,in_port=%d,reg%d=%d,actions=ct_clear,resubmit(,%d)", + BASE_EGRESS_TABLE, ofport, REG_PORT, ofport, DROPPED_TRAFFIC_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=90,dl_type=0x%04x,reg%d=%d,ct_state=+new-est," + "actions=ct(commit,zone=NXM_NX_REG%d[0..15]),resubmit(,%d)", + ACCEPT_OR_INGRESS_TABLE, ETHERTYPE_IP, REG_PORT, ofport, REG_NET, ACCEPTED_EGRESS_TRAFFIC_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=80,reg%d=%d,actions=resubmit(,%d)", + ACCEPT_OR_INGRESS_TABLE, REG_PORT, ofport, ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=12,dl_dst=%s,reg%d=%d,actions=output:%d", + ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, mac_address, REG_NET, local_vlan, ofport); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=10,dl_src=%s,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00," + "reg%d=%d,actions=output:%d", + ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE, mac_address, REG_NET, local_vlan, patch_ofport); + controller.add_flow(BR_INT, flow); +} + +void Aca_Security_Group_Ovs::init_port_ingress_flows(const Aca_Port &port) +{ + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + char flow[128] = {0}; + + int ofport = 12; + + sprintf(flow, "table=%d,priority=100,dl_type=0x%04x,reg%d=%d,actions=output:%d", + BASE_INGRESS_TABLE, ETHERTYPE_ARP, REG_PORT, ofport, ofport); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=95,reg%d=%d,dl_type=0x%04x,nw_proto=%d," + "tp_src=67,tp_dst=68,actions=output:%d", + BASE_INGRESS_TABLE, REG_PORT, ofport, ETHERTYPE_IP, PROTO_NUM_UDP, ofport); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=90,reg%d=%d,dl_type=0x%04x,ct_state=-trk," + "actions=ct(table=%d,zone=NXM_NX_REG%d[0..15])", + BASE_INGRESS_TABLE, REG_PORT, ofport, ETHERTYPE_IP, RULES_INGRESS_TABLE, REG_NET); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,ct_state=+trk,priority=80,reg%d=%d,actions=resubmit(,%d)", + BASE_INGRESS_TABLE, REG_PORT, ofport, RULES_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); +} + +void Aca_Security_Group_Ovs::init_port_flows(Aca_Port &port) +{ + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + char flow[128] = {0}; + + string port_id = port.get_id(); + string vpc_id = port.get_vpc_id(); + int ofport = 12; + int vni = 10; + int local_vlan = get_vlan_by_segment_id(vni); + + sprintf(flow, "table=%d,priority=100,in_port=%d,actions=set_field:%d->reg%d," + "set_field:%d->reg%d,resubmit(,%d)", TRANSIENT_TABLE, ofport, ofport, + REG_PORT, local_vlan, REG_NET, BASE_EGRESS_TABLE); + controller.add_flow(BR_INT, flow); + + // Allow address pairs + vector> address_pairs = port.get_allow_address_pairs(); + for (auto iter = address_pairs.cbegin(); iter != address_pairs.cend(); iter++) { + //pair address_pair = aca_port.allow_address_pairs(i); + const char * ip_address = iter->first.data(); + const char *mac_address = iter->second.data(); + + sprintf(flow, "table=%d,priority=90,dl_dst=%s,dl_vlan=%d,actions=set_field:%d->reg%d," + "set_field:%d->reg%d,strip_vlan,resubmit(,%d)", TRANSIENT_TABLE, mac_address, + local_vlan, ofport, REG_PORT, local_vlan, REG_NET, BASE_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=95,in_port=%d,reg%d=%d,dl_src=%s,dl_type=0x%04x," + "arp_spa=%s,actions=resubmit(,%d)", BASE_EGRESS_TABLE, ofport, REG_PORT, ofport, + mac_address, ETHERTYPE_ARP, ip_address, ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=65,in_port=%d,reg%d=%d,dl_src=%s,dl_type=0x%04x," + "nw_src=%s,actions=ct(table=%d,zone=NXM_NX_REG%d[0..15])", BASE_EGRESS_TABLE, ofport, + REG_PORT, ofport, mac_address, ETHERTYPE_IP, ip_address, RULES_EGRESS_TABLE, REG_NET); + controller.add_flow(BR_INT, flow); + + sprintf(flow, "table=%d,priority=100,dl_dst=%s,reg_net=%d," + "actions=set_field:%d->reg%d,resubmit(,%d)", + ACCEPT_OR_INGRESS_TABLE, mac_address, local_vlan, ofport, REG_PORT, BASE_INGRESS_TABLE); + controller.add_flow(BR_INT, flow); + } + + init_port_egress_flows(port); + + init_port_ingress_flows(port); +} + +void Aca_Security_Group_Ovs::clear_port_flows(Aca_Port &port) +{ + //TODO: delete all flows of this port +} +int Aca_Security_Group_Ovs::flow_priority_offset(Aca_Security_Group_Rule &sg_rule, + bool conjunction) +{ + + int conj_offset = 4; + Aca_Security_Group * remote_group = sg_rule.get_remote_group(); + Protocol protocol = sg_rule.get_protocol(); + + if (remote_group == NULL || conjunction) { + conj_offset = 0; + } + + if (protocol == UNKNOWN_PROTO) { + return conj_offset; + } + + uint32_t port_range_min = sg_rule.get_port_range_min(); + uint32_t port_range_max = sg_rule.get_port_range_max(); + + if (protocol == PROTO_NUM_ICMP) { + if (port_range_min == 0) { + return conj_offset + 1; + } else if (port_range_max == 0) { + return conj_offset + 2; + } + } + + return conj_offset + 3; +} + +int Aca_Security_Group_Ovs::get_dl_type_by_ether_type(uint32_t ethertype) +{ + return ethertype; +} + +string Aca_Security_Group_Ovs::get_nw_proto_by_protocol(uint32_t protocol) +{ + switch (protocol) { + case PROTO_NUM_TCP: + return "tcp"; + case PROTO_NUM_UDP: + return "udp"; + case PROTO_NUM_ICMP: + return "icmp"; + default: + ACA_LOG_ERROR("=====>wrong ether type\n"); + } + + return ""; +} + +int Aca_Security_Group_Ovs::build_flow_match_fileds(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + bool del_flow, + vector &flows) +{ + stringstream match_fileds; + int priority; + string nw_src_dst; + string tcp_udp_dst; + + uint64_t cookie = sg_rule.get_cookie(); + uint32_t dl_type = sg_rule.get_ethertype(); + uint32_t nw_proto = sg_rule.get_protocol(); + Direction direction = sg_rule.get_direction(); + uint32_t port_range_min = sg_rule.get_port_range_min(); + uint32_t port_range_max = sg_rule.get_port_range_max(); + string remote_ip_prefix = sg_rule.get_remote_ip_prefix(); + Aca_Security_Group * remote_group = sg_rule.get_remote_group(); + uint32_t ofport = port.get_ofport(); + + priority = flow_priority_offset(sg_rule, remote_group != NULL) + FLOW_PRIORITY_BASE; + //dl_type = get_dl_type_by_ether_type(ethertype); + tcp_udp_dst = get_nw_proto_by_protocol(nw_proto); + + if (direction == INGRESS) { + match_fileds << "table=" << RULES_INGRESS_TABLE << ","; + } else { + match_fileds << "table=" << RULES_EGRESS_TABLE << ","; + } + + if (del_flow) { + match_fileds << "cookie=" << cookie << "/-1,"; + } else { + match_fileds << "cookie=" << cookie << ","; + } + + match_fileds << "priority=" << priority << ","; + match_fileds << "reg" << REG_PORT << "=" << ofport << ","; + + if (dl_type > 0) { + match_fileds << "dl_type=" << dl_type << ","; + } + + if (remote_ip_prefix != "") { + if (direction == INGRESS) { + nw_src_dst = "nw_src=" + remote_ip_prefix ; + match_fileds << "nw_src=" << remote_ip_prefix << ","; + } else { + nw_src_dst = "nw_dst=" + remote_ip_prefix; + match_fileds << "nw_dst=" << remote_ip_prefix << ","; + } + } + + if (nw_proto > 0) { + match_fileds << "nw_proto=" << nw_proto << ","; + } + + if (nw_proto == ICMP) { + stringstream ss; + string flow; + + if (port_range_min > 0) { + ss << "icmp_type=" << port_range_min; + } + + if (port_range_max > 0) { + ss << "icmp_code=" << port_range_max; + } + + flow = match_fileds.str() + ss.str(); + + flows.push_back(flow); + } else { + for (uint32_t i = port_range_min; i <= port_range_max; i++) { + stringstream ss; + string flow; + + ss << tcp_udp_dst << "_dst=" << i; + flow = match_fileds.str() + ss.str(); + + flows.push_back(flow); + } + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::get_remote_group_ips(Aca_Security_Group *remote_group, + vector &remote_ips) +{ + Aca_Security_Group_Manager manager = Aca_Security_Group_Manager::get_instance(); + set &port_ids = remote_group->get_port_ids(); + + for(set::iterator it = port_ids.begin(); it != port_ids.end(); it++) { + string port_id = *it; + map &ports = manager.get_ports(); + map::iterator iter; + Aca_Port *port; + + iter = ports.find(port_id); + if (iter == ports.end()) { + return EXIT_FAILURE; + } + + port = iter->second; + vector &fixed_ips = port->get_fixed_ip(); + + for (uint32_t j = 0; j < fixed_ips.size(); j++) { + remote_ips.push_back(fixed_ips[j]); + } + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::get_remote_group_conj_id(Aca_Security_Group_Rule &sg_rule) +{ + int offset; + int conj_id; + string key; + map::iterator iter; + + offset = flow_priority_offset(sg_rule, true); + + //TODU: use (sg_id, remote_sg_id, direction, ethertype) as key + key = sg_rule.get_remote_group_id(); + + iter = this->conj_ids.find(key); + if (iter == this->conj_ids.end()) { + this->conj_id_base += 8; + conj_id = this->conj_id_base + offset * 2; + this->conj_ids[key] = conj_id; + } else { + conj_id = iter->second; + } + + return conj_id; +} + +int Aca_Security_Group_Ovs::build_flows_by_remote_ip(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + string remote_ip, + int conj_id, + vector &flows) +{ + stringstream match_fileds; + string actions; + int priority; + int vni = 10; + + uint64_t cookie = sg_rule.get_cookie(); + uint32_t dl_type = sg_rule.get_ethertype(); + Direction direction = sg_rule.get_direction(); + int local_vlan = get_vlan_by_segment_id(vni); + + if (direction == INGRESS) { + match_fileds << "table=" << RULES_INGRESS_TABLE << ","; + } else { + match_fileds << "table=" << RULES_EGRESS_TABLE << ","; + } + + priority = 70 + (conj_id % 8) / 2; + + match_fileds << "cookie=" << cookie << ","; + match_fileds << "priority=" << priority << ","; + match_fileds << "dl_type=" << dl_type << ","; + match_fileds << "reg" << REG_NET << "=" << local_vlan << ","; + + if (direction == INGRESS) { + match_fileds << "nw_src=" << remote_ip; + } else { + match_fileds << "nw_dst=" << remote_ip; + } + + return add_conjunction_actions(match_fileds.str(), conj_id, 1, flows); +} + +int Aca_Security_Group_Ovs::add_conjunction_actions(string flow, + int conj_id, + int dimension, + vector &flows) +{ + for (int i = 0; i < 2; i++) { + stringstream s_flow; + + s_flow << ",ct_state=" << ct_state[i] << ",actions=conjunction(" \ + << conj_id + i << "," << dimension << "/2)"; + + flows.push_back(flow + s_flow.str()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::build_accept_flows(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + int conj_id, + vector &flows) +{ + stringstream match_fileds; + int priority; + string actions; + string flow; + int vni = 10; + + uint64_t cookie = sg_rule.get_cookie(); + uint32_t dl_type = sg_rule.get_ethertype(); + Direction direction = sg_rule.get_direction(); + uint32_t ofport = port.get_ofport(); + int local_vlan = get_vlan_by_segment_id(vni); + + if (direction == INGRESS) { + match_fileds << "table=" << RULES_INGRESS_TABLE << ","; + actions = "output:" + to_string(ofport); + } else { + match_fileds << "table=" << RULES_EGRESS_TABLE << ","; + actions = "resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; + } + + priority = (conj_id % 8) / 2; + + match_fileds << "cookie=" << cookie << ","; + match_fileds << "priority=" << priority << ","; + match_fileds << "dl_type=" << dl_type << ","; + match_fileds << "reg" << REG_NET << "=" << local_vlan << ","; + + for (int i = 0; i < 2; i++) { + stringstream s_flow; + + match_fileds << "ct_state=" << ct_state[i] << ","; + if (i == 1 && direction == INGRESS) { + s_flow << match_fileds.str() << "conj_id=" << conj_id + 1 << ","; + s_flow << "actions=ct(commit,zone=NXM_NX_REG" << REG_NET << "[0..15])," << actions \ + << ",resubmit(," << ACCEPTED_INGRESS_TRAFFIC_TABLE << ")"; + } else { + s_flow << match_fileds.str() << "conj_id=" << conj_id << ",actions=" << actions; + } + + flows.push_back(s_flow.str()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::build_conjunction_flows(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + vector &flows) +{ + int conj_id; + vector remote_ips; + vector match_fileds; + Aca_Security_Group *remote_group; + + remote_group = sg_rule.get_remote_group(); + if (remote_group == NULL) { + return EXIT_FAILURE; + } + + if (get_remote_group_ips(remote_group, remote_ips) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Get ips of remote group failed\n"); + return EXIT_FAILURE; + } + + conj_id = get_remote_group_conj_id(sg_rule); + + for (uint32_t i = 0; i < remote_ips.size(); i++) { + build_flows_by_remote_ip(port, sg_rule, remote_ips[i], conj_id, flows); + } + + build_flow_match_fileds(port, sg_rule, false, match_fileds); + + for (uint32_t i = 0; i < match_fileds.size(); i++) { + add_conjunction_actions(match_fileds[i], conj_id, 2, flows); + } + + return build_accept_flows(port, sg_rule, conj_id, flows); +} + + +int Aca_Security_Group_Ovs::build_flows_by_sg_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule, + bool del_flow, + vector &flows) +{ + Direction direction; + uint32_t ofport; + string actions; + vector tmp_flows; + + if (sg_rule.get_remote_group() != NULL) { + return build_conjunction_flows(port, sg_rule, flows); + } + + build_flow_match_fileds(port, sg_rule, del_flow, tmp_flows); + + direction = sg_rule.get_direction(); + ofport = port.get_ofport(); + + if (direction == INGRESS) { + actions = "actions=output:" + ofport; + } else { + actions = "actions=resubmit(," + to_string(ACCEPT_OR_INGRESS_TABLE) + ")"; + } + + for (uint32_t i = 0; i < tmp_flows.size(); i++) { + string flow = tmp_flows[i]; + + for (int j = 0; j < 2; j++) { + stringstream s_flow; + + s_flow << flow << ",ct_state=" << ct_state[j]; + + if (!del_flow) { + if (j == 1 && direction == INGRESS) { + s_flow << "ct(comit,zone=NXM_NX_REG" << REG_NET << "[0..15])," << actions \ + << ",resubmit(," << ACCEPTED_INGRESS_TRAFFIC_TABLE << ")"; + } else { + s_flow << "," << actions; + } + } + + flows.push_back(s_flow.str()); + } + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::create_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule) +{ + vector flows; + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + + if (build_flows_by_sg_rule(port, sg_rule, false, flows) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Build flows by sg rule failed\n"); + return EXIT_FAILURE; + } + + for (uint32_t i = 0; i < flows.size(); i++) { + controller.add_flow(BR_INT, flows[i].data()); + } + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::update_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &new_sg_rule, + Aca_Security_Group_Rule &old_sg_rule) +{ + vector flows; + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + + if (build_flows_by_sg_rule(port, new_sg_rule, false, flows) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Build flows by sg rule failed\n"); + return EXIT_FAILURE; + } + + for (uint32_t i = 0; i < flows.size(); i++) { + controller.add_flow(BR_INT, flows[i].data()); + } + + //TODO: Consider port update + delete_port_security_group_rule(port, old_sg_rule); + + return EXIT_SUCCESS; +} + +int Aca_Security_Group_Ovs::delete_port_security_group_rule(Aca_Port &port, + Aca_Security_Group_Rule &sg_rule) +{ + vector flows; + ACA_OVS_Control &controller = ACA_OVS_Control::get_instance(); + + if (build_flows_by_sg_rule(port, sg_rule, true, flows) != EXIT_SUCCESS) { + ACA_LOG_ERROR("Build flows by sg rule failed\n"); + return EXIT_FAILURE; + } + + for (uint32_t i = 0; i < flows.size(); i++) { + controller.del_flows(BR_INT, flows[i].data()); + } + + return EXIT_SUCCESS; +} + +} diff --git a/src/sg/aca_sg_state_handler.cpp b/src/sg/aca_sg_state_handler.cpp new file mode 100644 index 00000000..e0217f7e --- /dev/null +++ b/src/sg/aca_sg_state_handler.cpp @@ -0,0 +1,274 @@ +// Copyright 2019 The Alcor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "aca_log.h" +#include "aca_util.h" +#include "aca_sg_state_handler.h" +#include "aca_goal_state_handler.h" +#include "goalstateprovisioner.grpc.pb.h" +#include "aca_security_group_manager.h" + +using namespace std; +using namespace alcor::schema; + +namespace aca_security_group +{ +Aca_Sg_State_Handler::Aca_Sg_State_Handler() +{ + ACA_LOG_INFO("Sg State Handler: using sg server\n"); +} + +Aca_Sg_State_Handler::~Aca_Sg_State_Handler() +{ + // allocated sg_programming_if is destroyed when program exits. +} + +Aca_Sg_State_Handler &Aca_Sg_State_Handler::get_instance() +{ + // It is instantiated on first use. + // allocated instance is destroyed when program exits. + static Aca_Sg_State_Handler instance; + return instance; +} + +int Aca_Sg_State_Handler::handle_port_security_group(Aca_Port &aca_port, + Aca_Security_Group &aca_sg) +{ + Aca_Security_Group_Manager &sg_manager = Aca_Security_Group_Manager::get_instance(); + OperationType operation_type = aca_sg.get_operation_type(); + + switch (operation_type) { + case CREATE: + return sg_manager.create_security_group(aca_port, aca_sg); + case UPDATE: + return sg_manager.update_security_group(aca_port, aca_sg); + case DELETE: + return sg_manager.delete_security_group(aca_port, aca_sg); + default: + ACA_LOG_ERROR("=====>wrong security group operation\n"); + } + + return EXIT_FAILURE; +} + +Aca_Port * Aca_Sg_State_Handler::parse_port_state(const PortState &port_state) +{ + PortConfiguration port_config = port_state.configuration(); + + //TODO: verify fields of port_state + Aca_Port *aca_port = new Aca_Port(); + aca_port->set_id(port_config.id()); + aca_port->set_mac_address(port_config.mac_address()); + + for (int i = 0; i < port_config.fixed_ips_size(); i++) { + aca_port->add_fixed_ip(port_config.fixed_ips(i).ip_address()); + } + + for (int i = 0; i < port_config.allow_address_pairs_size(); i++) { + PortConfiguration::AllowAddressPair pair = port_config.allow_address_pairs(i); + aca_port->add_allow_address_pair(pair.ip_address(), pair.mac_address()); + } + + for (int i = 0; i < port_config.security_group_ids_size(); i++) { + aca_port->add_security_group_id(port_config.security_group_ids(i).id()); + } + + return aca_port; +} + +OperationType Aca_Sg_State_Handler::get_operation_type(alcor::schema::OperationType operation_type) +{ + switch(operation_type) { + case alcor::schema::OperationType::CREATE: + return CREATE; + case alcor::schema::OperationType::UPDATE: + return UPDATE; + case alcor::schema::OperationType::DELETE: + return DELETE; + default: + ACA_LOG_ERROR("Invalid operation type"); + } + + return UNKNOWN_OPERATION; +} + +Direction Aca_Sg_State_Handler::get_direction(SecurityGroupConfiguration::Direction direction) +{ + switch(direction) { + case SecurityGroupConfiguration::EGRESS: + return EGRESS; + case SecurityGroupConfiguration::INGRESS: + return INGRESS; + default: + ACA_LOG_ERROR("Invalid direction"); + } + + return UNKNOWN_DIRECTION; +} + +Ethertype Aca_Sg_State_Handler::get_ethertype(alcor::schema::EtherType ethertype) +{ + switch(ethertype) { + case alcor::schema::EtherType::IPV4: + return IPV4; + case alcor::schema::EtherType::IPV6: + return IPV6; + default: + ACA_LOG_ERROR("Invalid ethertype"); + } + + return UNKNOWN_ETHERTYPE; +} + +Protocol Aca_Sg_State_Handler::get_protocol(alcor::schema::Protocol protocol) +{ + switch(protocol) { + case alcor::schema::Protocol::TCP: + return TCP; + case alcor::schema::Protocol::UDP: + return UDP; + case alcor::schema::Protocol::ICMP: + return ICMP; + default: + ACA_LOG_ERROR("Invalid protocol"); + } + + return UNKNOWN_PROTO; +} + + +void Aca_Sg_State_Handler::parse_security_group_states(const GoalState &goal_state, + map &aca_sgs) +{ + //TODO: verify fields of port_state + for (int i = 0; i < goal_state.security_group_states_size(); i++) { + ACA_LOG_DEBUG("=====>parsing security group states #%d\n", i); + + Aca_Security_Group *aca_sg; + SecurityGroupState sg_state = goal_state.security_group_states(i); + SecurityGroupConfiguration sg_config = sg_state.configuration(); + + if (sg_config.id() == "") { + ACA_LOG_ERROR("Security group id is empty"); + continue; + } + + aca_sg = new Aca_Security_Group(); + + aca_sg->set_id(sg_config.id()); + aca_sg->set_name(sg_config.name()); + aca_sg->set_vpc_id(sg_config.vpc_id()); + aca_sg->set_format_version(sg_config.format_version()); + aca_sg->set_revision_number(sg_config.revision_number()); + aca_sg->set_operation_type(get_operation_type(sg_state.operation_type())); + + for (int j = 0; j < sg_config.security_group_rules_size(); j++) { + SecurityGroupConfiguration::SecurityGroupRule sg_rule = sg_config.security_group_rules(i); + Aca_Security_Group_Rule *aca_sg_rule = new Aca_Security_Group_Rule(); + + if (sg_config.id() == "") { + ACA_LOG_ERROR("Security group rule id is empty"); + continue; + } + + aca_sg_rule->set_id(sg_rule.id()); + aca_sg_rule->set_direction(get_direction(sg_rule.direction())); + aca_sg_rule->set_ethertype(get_ethertype(sg_rule.ethertype())); + aca_sg_rule->set_protocol(get_protocol(sg_rule.protocol())); + aca_sg_rule->set_port_range_min(sg_rule.port_range_min()); + aca_sg_rule->set_port_range_max(sg_rule.port_range_max()); + aca_sg_rule->set_remote_ip_prefix(sg_rule.remote_ip_prefix()); + aca_sg_rule->set_remote_group_id(sg_rule.remote_group_id()); + aca_sg_rule->set_operation_type(get_operation_type(sg_rule.operation_type())); + + aca_sg->add_security_group_rule(aca_sg_rule); + } + + aca_sgs[sg_config.id()] = aca_sg; + } +} + +int Aca_Sg_State_Handler::update_security_group_states(const GoalState &goal_state, + GoalStateOperationReply &reply) +{ + std::vector> futures; + int rc; + int overall_rc = EXIT_SUCCESS; + map aca_sgs; + map::iterator siter; + vector aca_ports; + + parse_security_group_states(goal_state, aca_sgs); + + for (int i = 0; i < goal_state.port_states_size(); i++) { + PortState port_state = goal_state.port_states(i); + PortConfiguration port_config = port_state.configuration(); + + Aca_Port *aca_port = parse_port_state(port_state); + aca_ports.push_back(aca_port); + + for (int j = 0; j < port_config.security_group_ids_size(); j++) { + PortConfiguration::SecurityGroupId security_group_id = port_config.security_group_ids(j); + string sg_id = security_group_id.id(); + + map::iterator iterator = aca_sgs.find(sg_id); + if (iterator == aca_sgs.end()) { + ACA_LOG_ERROR("Can not find security group by id:%s", sg_id.data()); + continue; + } + + futures.push_back(std::async( + std::launch::async, &Aca_Sg_State_Handler::handle_port_security_group, + this, std::ref(*aca_port), std::ref(*(iterator->second)))); + } + } + + for (uint32_t i = 0; i < futures.size(); i++) { + rc = futures[i].get(); + if (rc != EXIT_SUCCESS) { + overall_rc = rc; + } + } + + siter = aca_sgs.begin(); + while(siter != aca_sgs.end()) { + Aca_Security_Group *aca_sg = siter->second; + map::iterator riter; + map sg_rules = aca_sg->get_security_group_rules(); + + riter = sg_rules.begin(); + while(riter != sg_rules.end()) { + Aca_Security_Group_Rule * sg_rule = riter->second; + delete sg_rule; + riter++; + } + + delete aca_sg; + siter++; + } + + aca_sgs.clear(); + + for (size_t i = 0; i < aca_ports.size(); i++) { + Aca_Port *aca_port = aca_ports[i]; + delete aca_port; + } + + aca_ports.clear(); + + return overall_rc; +} + +} diff --git a/test/aca-sg-test/.idea/.gitignore b/test/aca-sg-test/.idea/.gitignore new file mode 100644 index 00000000..5c98b428 --- /dev/null +++ b/test/aca-sg-test/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml b/test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/test/aca-sg-test/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/compiler.xml b/test/aca-sg-test/.idea/compiler.xml new file mode 100644 index 00000000..45f38519 --- /dev/null +++ b/test/aca-sg-test/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/encodings.xml b/test/aca-sg-test/.idea/encodings.xml new file mode 100644 index 00000000..b26911bd --- /dev/null +++ b/test/aca-sg-test/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/misc.xml b/test/aca-sg-test/.idea/misc.xml new file mode 100644 index 00000000..e6a9feae --- /dev/null +++ b/test/aca-sg-test/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/.idea/vcs.xml b/test/aca-sg-test/.idea/vcs.xml new file mode 100644 index 00000000..b2bdec2d --- /dev/null +++ b/test/aca-sg-test/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/aca-sg-test/aca-sg-test.iml b/test/aca-sg-test/aca-sg-test.iml new file mode 100644 index 00000000..78b2cc53 --- /dev/null +++ b/test/aca-sg-test/aca-sg-test.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/aca-sg-test/pom.xml b/test/aca-sg-test/pom.xml new file mode 100644 index 00000000..da63f813 --- /dev/null +++ b/test/aca-sg-test/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + com.futurewei + aca-sg-test + 1.0-SNAPSHOT + + + UTF-8 + 11 + 11 + + + + + com.futurewei.alcor + schema + 0.1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java b/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java new file mode 100644 index 00000000..52724386 --- /dev/null +++ b/test/aca-sg-test/src/main/java/com/futurewei/aca/securitygroup/SecurityGroupTest.java @@ -0,0 +1,219 @@ +/* +Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.aca.securitygroup; + +import com.futurewei.alcor.schema.Common; +import com.futurewei.alcor.schema.Common.EtherType; +import com.futurewei.alcor.schema.Common.Protocol; +import com.futurewei.alcor.schema.Common.OperationType; +import com.futurewei.alcor.schema.Vpc.VpcState; +import com.futurewei.alcor.schema.Vpc.VpcConfiguration; +import com.futurewei.alcor.schema.Subnet.SubnetState; +import com.futurewei.alcor.schema.Subnet.SubnetConfiguration; +import com.futurewei.alcor.schema.Port.PortState; +import com.futurewei.alcor.schema.Port.PortConfiguration; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupState; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupConfiguration; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupConfiguration.SecurityGroupRule; +import com.futurewei.alcor.schema.SecurityGroup.SecurityGroupConfiguration.Direction; +import com.futurewei.alcor.schema.GoalStateProvisionerGrpc.GoalStateProvisionerBlockingStub; +import com.futurewei.alcor.schema.GoalStateProvisionerGrpc; +import com.futurewei.alcor.schema.Goalstate.GoalState; +import com.futurewei.alcor.schema.Goalstateprovisioner.GoalStateOperationReply; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; + +public class SecurityGroupTest { + private ManagedChannel managedChannel; + + public SecurityGroupTest() { + this.managedChannel = ManagedChannelBuilder.forAddress("192.168.131.131",50001) + .usePlaintext().build(); + } + + @Override + protected void finalize() { + managedChannel.shutdown(); + } + + private VpcState buildVpcState() { + VpcConfiguration.Builder vpcConfigBuilder = VpcConfiguration.newBuilder(); + vpcConfigBuilder.setName("vpc1"); + vpcConfigBuilder.setCidr("10.10.10.0/24"); + vpcConfigBuilder.setId("vpc_id1"); + + VpcState.Builder vpcStateBuilder = VpcState.newBuilder(); + vpcStateBuilder.setOperationType(OperationType.CREATE); + vpcStateBuilder.setConfiguration(vpcConfigBuilder.build()); + + return vpcStateBuilder.build(); + } + + private SubnetState buildSubnetState() { + SubnetConfiguration.Builder subnetConfigBuilder = SubnetConfiguration.newBuilder(); + subnetConfigBuilder.setName("subnet1"); + subnetConfigBuilder.setCidr("10.10.10.0/24"); + subnetConfigBuilder.setId("subnet_id1"); + + SubnetState.Builder subnetStateBuilder = SubnetState.newBuilder(); + subnetStateBuilder.setOperationType(OperationType.CREATE); + subnetStateBuilder.setConfiguration(subnetConfigBuilder.build()); + + return subnetStateBuilder.build(); + } + + private PortState buildPortState() { + PortConfiguration.Builder portConfigBuilder = PortConfiguration.newBuilder(); + portConfigBuilder.setName("port1"); + portConfigBuilder.setVpcId("vpc_id1"); + portConfigBuilder.setId("port_id1"); + portConfigBuilder.setFormatVersion(1); + portConfigBuilder.setRevisionNumber(1); + portConfigBuilder.setAdminStateUp(true); + portConfigBuilder.setMessageType(Common.MessageType.FULL); + portConfigBuilder.setMacAddress("7E:04:D0:C9:12:6C"); + portConfigBuilder.addFixedIps(PortConfiguration.FixedIp.newBuilder() + .setIpAddress("10.10.10.2").setSubnetId("subnet_id1").build()); + PortConfiguration.SecurityGroupId.Builder securityGroupIdBuilder = PortConfiguration.SecurityGroupId.newBuilder(); + securityGroupIdBuilder.setId("security_group_id1"); + portConfigBuilder.addSecurityGroupIds(securityGroupIdBuilder.build()); + + PortState.Builder portStateBuilder = PortState.newBuilder(); + portStateBuilder.setOperationType(OperationType.CREATE); + portStateBuilder.setConfiguration(portConfigBuilder.build()); + + return portStateBuilder.build(); + } + + private PortState buildPortState2() { + PortConfiguration.Builder portConfigBuilder = PortConfiguration.newBuilder(); + portConfigBuilder.setName("port2"); + portConfigBuilder.setVpcId("vpc_id1"); + portConfigBuilder.setId("port_id2"); + portConfigBuilder.setFormatVersion(2); + portConfigBuilder.setRevisionNumber(2); + portConfigBuilder.setAdminStateUp(true); + portConfigBuilder.setMessageType(Common.MessageType.FULL); + portConfigBuilder.setMacAddress("7E:04:D0:A9:42:53"); + portConfigBuilder.addFixedIps(PortConfiguration.FixedIp.newBuilder() + .setIpAddress("10.10.10.3").setSubnetId("subnet_id1").build()); + PortConfiguration.SecurityGroupId.Builder securityGroupIdBuilder = PortConfiguration.SecurityGroupId.newBuilder(); + securityGroupIdBuilder.setId("security_group_id2"); + portConfigBuilder.addSecurityGroupIds(securityGroupIdBuilder.build()); + + PortState.Builder portStateBuilder = PortState.newBuilder(); + portStateBuilder.setOperationType(OperationType.CREATE); + portStateBuilder.setConfiguration(portConfigBuilder.build()); + + return portStateBuilder.build(); + } + + private SecurityGroupState buildSecurityGroupState() { + SecurityGroupConfiguration.Builder securityGroupConfigBuilder = SecurityGroupConfiguration.newBuilder(); + securityGroupConfigBuilder.setName("security_group1"); + securityGroupConfigBuilder.setVpcId("vpc_id1"); + securityGroupConfigBuilder.setId("security_group_id1"); + securityGroupConfigBuilder.setFormatVersion(1); + securityGroupConfigBuilder.setRevisionNumber(1); + SecurityGroupRule.Builder securityGroupRuleBuilder = SecurityGroupRule.newBuilder(); + securityGroupRuleBuilder.setOperationType(OperationType.CREATE); + securityGroupRuleBuilder.setId("security_group_rule_id1"); + securityGroupRuleBuilder.setSecurityGroupId("security_group_id1"); + securityGroupRuleBuilder.setDirection(Direction.EGRESS); + securityGroupRuleBuilder.setEthertype(EtherType.IPV4); + securityGroupRuleBuilder.setProtocol(Protocol.TCP); + securityGroupRuleBuilder.setPortRangeMin(100); + securityGroupRuleBuilder.setPortRangeMax(101); + securityGroupRuleBuilder.setRemoteIpPrefix("11.11.11.0/24"); + securityGroupConfigBuilder.addSecurityGroupRules(securityGroupRuleBuilder.build()); + + SecurityGroupState.Builder securityGroupStateBuilder = SecurityGroupState.newBuilder(); + securityGroupStateBuilder.setOperationType(OperationType.CREATE); + securityGroupStateBuilder.setConfiguration(securityGroupConfigBuilder.build()); + + return securityGroupStateBuilder.build(); + } + + private SecurityGroupState buildSecurityGroupState2() { + SecurityGroupConfiguration.Builder securityGroupConfigBuilder = SecurityGroupConfiguration.newBuilder(); + securityGroupConfigBuilder.setName("security_group2"); + securityGroupConfigBuilder.setVpcId("vpc_id1"); + securityGroupConfigBuilder.setId("security_group_id2"); + securityGroupConfigBuilder.setFormatVersion(2); + securityGroupConfigBuilder.setRevisionNumber(2); + SecurityGroupRule.Builder securityGroupRuleBuilder = SecurityGroupRule.newBuilder(); + securityGroupRuleBuilder.setOperationType(OperationType.CREATE); + securityGroupRuleBuilder.setId("security_group_rule_id2"); + securityGroupRuleBuilder.setSecurityGroupId("security_group_id2"); + securityGroupRuleBuilder.setDirection(Direction.INGRESS); + securityGroupRuleBuilder.setEthertype(EtherType.IPV4); + securityGroupRuleBuilder.setProtocol(Protocol.UDP); + securityGroupRuleBuilder.setPortRangeMin(200); + securityGroupRuleBuilder.setPortRangeMax(201); + securityGroupRuleBuilder.setRemoteGroupId("security_group_id1"); + securityGroupConfigBuilder.addSecurityGroupRules(securityGroupRuleBuilder.build()); + + SecurityGroupState.Builder securityGroupStateBuilder = SecurityGroupState.newBuilder(); + securityGroupStateBuilder.setOperationType(OperationType.CREATE); + securityGroupStateBuilder.setConfiguration(securityGroupConfigBuilder.build()); + + return securityGroupStateBuilder.build(); + } + + private GoalState buildGoalState(PortState portState, SecurityGroupState securityGroupState) { + GoalState.Builder builder = GoalState.newBuilder(); + builder.setFormatVersion(1); + builder.addVpcStates(buildVpcState()); + builder.addSubnetStates(buildSubnetState()); + builder.addPortStates(portState); + builder.addSecurityGroupStates(securityGroupState); + + return builder.build(); + } + + private void pushNetworkResourceStates(GoalState goalState) { + GoalStateProvisionerBlockingStub blockingStub = + GoalStateProvisionerGrpc.newBlockingStub(managedChannel); + + GoalStateOperationReply goalStateOperationReply + = blockingStub.pushNetworkResourceStates(goalState); + + System.out.println(goalStateOperationReply.toString()); + } + + private void createGeneralSecurityGroupTest() { + PortState portState = buildPortState(); + SecurityGroupState securityGroupState = buildSecurityGroupState(); + GoalState goalState = buildGoalState(portState, securityGroupState); + pushNetworkResourceStates(goalState); + } + + private void createRemoteGroupSecurityGroupTest() { + createGeneralSecurityGroupTest(); + + PortState portState = buildPortState2(); + SecurityGroupState securityGroupState = buildSecurityGroupState2(); + GoalState goalState = buildGoalState(portState, securityGroupState); + pushNetworkResourceStates(goalState); + } + + public static void main(String[] args) { + SecurityGroupTest securityGroupTest = new SecurityGroupTest(); + //securityGroupTest.createGeneralSecurityGroupTest(); + + securityGroupTest.createRemoteGroupSecurityGroupTest(); + } +} diff --git a/test/aca-sg-test/target/aca-sg-test-1.0-SNAPSHOT.jar b/test/aca-sg-test/target/aca-sg-test-1.0-SNAPSHOT.jar new file mode 100644 index 00000000..3c254344 Binary files /dev/null and b/test/aca-sg-test/target/aca-sg-test-1.0-SNAPSHOT.jar differ diff --git a/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class b/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class new file mode 100644 index 00000000..36ee8232 Binary files /dev/null and b/test/aca-sg-test/target/classes/com/futurewei/aca/securitygroup/SecurityGroupTest.class differ diff --git a/test/aca-sg-test/target/maven-archiver/pom.properties b/test/aca-sg-test/target/maven-archiver/pom.properties new file mode 100644 index 00000000..c13c9b5e --- /dev/null +++ b/test/aca-sg-test/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Wed Oct 14 15:03:52 CST 2020 +groupId=com.futurewei +artifactId=aca-sg-test +version=1.0-SNAPSHOT diff --git a/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 00000000..fafceb50 --- /dev/null +++ b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +com\futurewei\aca\securitygroup\SecurityGroupTest.class diff --git a/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 00000000..0ab59aa8 --- /dev/null +++ b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1 @@ +F:\work\alcor\git\chenpp\alcor-control-agent\test\aca-sg-test\src\main\java\com\futurewei\aca\securitygroup\SecurityGroupTest.java diff --git a/test/aca-sg-test/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/test/aca-sg-test/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 00000000..e69de29b