diff --git a/meson.build b/meson.build index a52320124..5f4f2484c 100644 --- a/meson.build +++ b/meson.build @@ -41,6 +41,8 @@ sources = files(''' src/netlink/tap_manager.hpp src/of-dpa/controller.cpp src/of-dpa/controller.hpp + src/of-dpa/ofdpa_client.cpp + src/of-dpa/ofdpa_client.hpp src/of-dpa/ofdpa_datatypes.h src/sai.hpp src/utils/rofl-utils.hpp @@ -128,12 +130,16 @@ grpc_gen = generator(protoc, '@INPUT@']) # generate sources and files -src_pb = protoc_gen.process('src/grpc/proto/common/empty.proto', +src_pb = protoc_gen.process( + 'src/grpc/proto/api/ofdpa.proto', + 'src/grpc/proto/common/empty.proto', 'src/grpc/proto/common/openconfig-interfaces.proto', 'src/grpc/proto/statistics/statistics-service.proto', preserve_path_from : meson.current_source_dir()+'/src/grpc/proto') -src_grpc = grpc_gen.process('src/grpc/proto/statistics/statistics-service.proto', +src_grpc = grpc_gen.process( + 'src/grpc/proto/api/ofdpa.proto', + 'src/grpc/proto/statistics/statistics-service.proto', preserve_path_from : meson.current_source_dir()+'/src/grpc/proto') version_h = vcs_tag(input: 'src/version.h.in', diff --git a/pkg/systemd/sysconfig.template b/pkg/systemd/sysconfig.template index f6e447c32..9669a7fa8 100644 --- a/pkg/systemd/sysconfig.template +++ b/pkg/systemd/sysconfig.template @@ -2,6 +2,9 @@ # # Listening port: # FLAGS_port=6653 +# +# gRPC listening port: +# FLAGS_ofdpa_grpc_port=50051 ### glog # diff --git a/src/baseboxd.cpp b/src/baseboxd.cpp index e3c4351cc..b0b4f4863 100644 --- a/src/baseboxd.cpp +++ b/src/baseboxd.cpp @@ -14,6 +14,7 @@ DECLARE_string(tryfromenv); // from gflags DEFINE_int32(port, 6653, "Listening port"); +DEFINE_int32(ofdpa_grpc_port, 50051, "Listening port of ofdpa gRPC server"); static bool validate_port(const char *flagname, gflags::int32 value) { VLOG(3) << __FUNCTION__ << ": flagname=" << flagname << ", value=" << value; @@ -33,8 +34,13 @@ int main(int argc, char **argv) { exit(1); } + if (!gflags::RegisterFlagValidator(&FLAGS_ofdpa_grpc_port, &validate_port)) { + std::cerr << "Failed to register port validator 2" << std::endl; + exit(1); + } + // all variables can be set from env - FLAGS_tryfromenv = std::string("port"); + FLAGS_tryfromenv = std::string("port,ofdpa_grpc_port"); gflags::SetUsageMessage(""); gflags::SetVersionString(PROJECT_VERSION); @@ -51,7 +57,7 @@ int main(int argc, char **argv) { std::shared_ptr tap_man(new tap_manager(nl)); std::unique_ptr nbi(new nbi_impl(nl, tap_man)); std::shared_ptr box( - new controller(std::move(nbi), versionbitmap)); + new controller(std::move(nbi), versionbitmap, FLAGS_ofdpa_grpc_port)); rofl::csockaddr baddr(AF_INET, std::string("0.0.0.0"), FLAGS_port); box->dpt_sock_listen(baddr); diff --git a/src/of-dpa/controller.cpp b/src/of-dpa/controller.cpp index 5937554fe..f3a9681cf 100644 --- a/src/of-dpa/controller.cpp +++ b/src/of-dpa/controller.cpp @@ -8,7 +8,10 @@ #include #include +#include + #include "controller.hpp" +#include "ofdpa_client.hpp" #include "ofdpa_datatypes.h" #include "utils/utils.hpp" #include "utils/rofl-utils.hpp" @@ -39,6 +42,36 @@ void controller::handle_dpt_open(rofl::crofdpt &dpt) { // set max queue size in rofl dpt.set_conn(rofl::cauxid(0)).set_txqueue_max_size(128 * 1024); + rofl::csockaddr raddr = dpt.set_conn(rofl::cauxid(0)).get_raddr(); + std::string buf; + + switch (raddr.get_family()) { + case AF_INET: { + rofl::caddress_in4 addr; + addr.set_addr_nbo(raddr.ca_s4addr->sin_addr.s_addr); + buf = addr.str(); + } break; + case AF_INET6: { + rofl::caddress_in6 addr; + addr.unpack(raddr.ca_s6addr->sin6_addr.s6_addr, 16); + buf = addr.str(); + } break; + default: + LOG(FATAL) << __FUNCTION__ << ": invalid socket address " << raddr; + } + + std::string remote = buf + ":" + std::to_string(ofdpa_grpc_port); + + VLOG(1) << __FUNCTION__ << ": remote=" << remote; + + std::shared_ptr chan = + grpc::CreateChannel(remote, grpc::InsecureChannelCredentials()); + + ofdpa = std::make_shared(chan); + + // open connection already + chan->GetState(true); + dpt.send_features_request(rofl::cauxid(0), 1); dpt.send_desc_stats_request(rofl::cauxid(0), 0, 1); @@ -553,6 +586,46 @@ int controller::lag_remove_member(uint32_t lag_id, uint32_t port_id) noexcept { return 0; } +int controller::overlay_tunnel_add(uint32_t tunnel_id) noexcept { + int rv = 0; + try { + rofl::crofdpt &dpt = set_dpt(dptid, true); + dpt.send_flow_mod_message( + rofl::cauxid(0), + fm_driver.enable_overlay_tunnel(dpt.get_version(), tunnel_id)); + } catch (rofl::eRofBaseNotFound &e) { + LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; + rv = -EINVAL; + } catch (rofl::eRofConnNotConnected &e) { + LOG(ERROR) << ": not connected msg=" << e.what(); + rv = -ENOTCONN; + } catch (std::exception &e) { + LOG(ERROR) << ": caught unknown exception: " << e.what(); + rv = -EINVAL; + } + return rv; +} + +int controller::overlay_tunnel_remove(uint32_t tunnel_id) noexcept { + int rv = 0; + try { + rofl::crofdpt &dpt = set_dpt(dptid, true); + dpt.send_flow_mod_message( + rofl::cauxid(0), + fm_driver.disable_overlay_tunnel(dpt.get_version(), tunnel_id)); + } catch (rofl::eRofBaseNotFound &e) { + LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; + rv = -EINVAL; + } catch (rofl::eRofConnNotConnected &e) { + LOG(ERROR) << ": not connected msg=" << e.what(); + rv = -ENOTCONN; + } catch (std::exception &e) { + LOG(ERROR) << ": caught unknown exception: " << e.what(); + rv = -EINVAL; + } + return rv; +} + int controller::l2_addr_remove_all_in_vlan(uint32_t port, uint16_t vid) noexcept { int rv = 0; @@ -626,6 +699,64 @@ int controller::l2_addr_remove(uint32_t port, uint16_t vid, return rv; } +int controller::l2_overlay_addr_add(uint32_t lport, uint32_t tunnel_id, + const rofl::cmacaddr &mac, + bool permanent) noexcept { + int rv = 0; + try { + rofl::crofdpt &dpt = set_dpt(dptid, true); + + if (!permanent) + fm_driver.set_idle_timeout(300); + + dpt.send_flow_mod_message(rofl::cauxid(0), + fm_driver.add_bridging_unicast_overlay( + dpt.get_version(), lport, tunnel_id, mac)); + + if (!permanent) + fm_driver.set_idle_timeout(default_idle_timeout); + + } catch (rofl::eRofBaseNotFound &e) { + LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; + rv = -EINVAL; + } catch (rofl::eRofConnNotConnected &e) { + LOG(ERROR) << ": not connected msg=" << e.what(); + rv = -ENOTCONN; + } catch (std::exception &e) { + LOG(ERROR) << ": caught unknown exception: " << e.what(); + rv = -EINVAL; + } + return rv; +} + +int controller::l2_overlay_addr_remove(uint32_t tunnel_id, uint32_t lport_id, + const rofl::cmacaddr &mac) noexcept { + int rv = 0; + try { + rofl::crofdpt &dpt = set_dpt(dptid, true); + if (lport_id) { + dpt.send_flow_mod_message( + rofl::cauxid(0), fm_driver.remove_bridging_unicast_overlay_all_lport( + dpt.get_version(), lport_id)); + dpt.send_barrier_request(rofl::cauxid(0)); + } else { + dpt.send_flow_mod_message(rofl::cauxid(0), + fm_driver.remove_bridging_unicast_overlay( + dpt.get_version(), tunnel_id, mac)); + } + } catch (rofl::eRofBaseNotFound &e) { + LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; + rv = -EINVAL; + } catch (rofl::eRofConnNotConnected &e) { + LOG(ERROR) << ": not connected msg=" << e.what(); + rv = -ENOTCONN; + } catch (std::exception &e) { + LOG(ERROR) << ": caught unknown exception: " << e.what(); + rv = -EINVAL; + } + return rv; +} + int controller::l3_termination_add(uint32_t sport, uint16_t vid, const rofl::caddress_ll &dmac) noexcept { int rv = 0; @@ -1127,6 +1258,7 @@ int controller::ingress_port_vlan_remove(uint32_t port, uint16_t vid, rofl::cauxid(0), fm_driver.disable_port_vid_ingress(dpt.get_version(), port, vid)); } + dpt.send_barrier_request(rofl::cauxid(0)); } catch (rofl::eRofBaseNotFound &e) { LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; rv = -EINVAL; @@ -1223,6 +1355,109 @@ int controller::egress_port_vlan_remove(uint32_t port, uint16_t vid) noexcept { return rv; } +int controller::add_l2_overlay_flood(uint32_t tunnel_id, + uint32_t lport_id) noexcept { + int rv = 0; + try { + auto tunnel_dlf_it = tunnel_dlf_flood.find(tunnel_id); + + if (tunnel_dlf_it == tunnel_dlf_flood.end()) { + std::set empty_set; + tunnel_dlf_it = tunnel_dlf_flood.emplace(tunnel_id, empty_set).first; + } + + tunnel_dlf_it->second.insert(lport_id); + + rofl::crofdpt &dpt = set_dpt(dptid, true); + // create/update new L2 flooding group + // + LOG(INFO) << __FUNCTION__ + << ": create group enable_group_l2_overlay_flood tunnel_id=" + << tunnel_id << ", #dlf=" << tunnel_dlf_it->second.size(); + + for (auto lport : tunnel_dlf_it->second) + LOG(INFO) << __FUNCTION__ << ": lport=" << lport; + + dpt.send_group_mod_message(rofl::cauxid(0), + fm_driver.enable_group_l2_overlay_flood( + dpt.get_version(), tunnel_id, tunnel_id, + tunnel_dlf_it->second, + (tunnel_dlf_it->second.size() > 1))); + + dpt.send_barrier_request(rofl::cauxid(0)); + + // if (tunnel_dlf_it->second.size() == 1) { + dpt.send_flow_mod_message( + rofl::cauxid(0), + fm_driver.add_bridging_dlf_overlay( + dpt.get_version(), tunnel_id, + fm_driver.group_id_l2_overlay_flood(tunnel_id, tunnel_id))); + // } + + } catch (rofl::eRofBaseNotFound &e) { + LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; + rv = -EINVAL; + } catch (rofl::eRofConnNotConnected &e) { + LOG(ERROR) << ": not connected msg=" << e.what(); + rv = -ENOTCONN; + } catch (std::exception &e) { + LOG(ERROR) << ": caught unknown exception: " << e.what(); + rv = -EINVAL; + } + return rv; +} + +int controller::del_l2_overlay_flood(uint32_t tunnel_id, + uint32_t lport_id) noexcept { + int rv = 0; + try { + auto tunnel_dlf_it = tunnel_dlf_flood.find(tunnel_id); + + if (tunnel_dlf_it == tunnel_dlf_flood.end()) { + // nothing in this group + VLOG(1) << __FUNCTION__ << ": invalid tunnel_id=" << tunnel_id; + return 0; + } + + auto elements_erased = tunnel_dlf_it->second.erase(lport_id); + if (elements_erased == 0) { + // nothing to do, lport already deleted + VLOG(1) << __FUNCTION__ << ": lport_id=" << lport_id + << " not existing in tunnel_id=" << tunnel_id; + return 0; + } + + rofl::crofdpt &dpt = set_dpt(dptid, true); + + if (tunnel_dlf_it->second.size()) { + // create/update new L2 flooding group + dpt.send_group_mod_message(rofl::cauxid(0), + fm_driver.enable_group_l2_overlay_flood( + dpt.get_version(), tunnel_id, tunnel_id, + tunnel_dlf_it->second, true)); + } else { + dpt.send_flow_mod_message( + rofl::cauxid(0), + fm_driver.remove_bridging_dlf_overlay(dpt.get_version(), tunnel_id)); + dpt.send_barrier_request(rofl::cauxid(0)); + dpt.send_group_mod_message(rofl::cauxid(0), + fm_driver.disable_group_l2_overlay_flood( + dpt.get_version(), tunnel_id, tunnel_id)); + } + + } catch (rofl::eRofBaseNotFound &e) { + LOG(ERROR) << ": caught rofl::eRofBaseNotFound"; + rv = -EINVAL; + } catch (rofl::eRofConnNotConnected &e) { + LOG(ERROR) << ": not connected msg=" << e.what(); + rv = -ENOTCONN; + } catch (std::exception &e) { + LOG(ERROR) << ": caught unknown exception: " << e.what(); + rv = -EINVAL; + } + return rv; +} + int controller::egress_bridge_port_vlan_add(uint32_t port, uint16_t vid, bool untagged) noexcept { int rv = 0; @@ -1427,4 +1662,93 @@ int controller::get_statistics(uint64_t port_no, uint32_t number_of_counters, return rv; } +int controller::tunnel_tenant_create(uint32_t tunnel_id, + uint32_t vni) noexcept { + return ofdpa->ofdpaTunnelTenantCreate(tunnel_id, vni); +} + +int controller::tunnel_tenant_delete(uint32_t tunnel_id) noexcept { + return ofdpa->ofdpaTunnelTenantDelete(tunnel_id); +} + +int controller::tunnel_next_hop_create(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) noexcept { + return ofdpa->ofdpaTunnelNextHopCreate(next_hop_id, src_mac, dst_mac, + physical_port, vlan_id); +} + +int controller::tunnel_next_hop_modify(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) noexcept { + return ofdpa->ofdpaTunnelNextHopModify(next_hop_id, src_mac, dst_mac, + physical_port, vlan_id); +} + +int controller::tunnel_next_hop_delete(uint32_t next_hop_id) noexcept { + return ofdpa->ofdpaTunnelNextHopDelete(next_hop_id); +} + +int controller::tunnel_access_port_create(uint32_t port_id, + const std::string &port_name, + uint32_t physical_port, + uint16_t vlan_id, + bool untagged) noexcept { + return ofdpa->ofdpaTunnelAccessPortCreate(port_id, port_name, physical_port, + vlan_id, untagged); +} + +int controller::tunnel_port_delete(uint32_t port_id) noexcept { + return ofdpa->ofdpaTunnelPortDelete(port_id); +} + +int controller::tunnel_enpoint_create( + uint32_t port_id, const std::string &port_name, uint32_t remote_ipv4, + uint32_t local_ipv4, uint32_t ttl, uint32_t next_hop_id, + uint32_t terminator_udp_dst_port, uint32_t initiator_udp_dst_port, + uint32_t udp_src_port_if_no_entropy, bool use_entropy) noexcept { + + return ofdpa->ofdpaTunnelEndpointPortCreate( + port_id, port_name, remote_ipv4, local_ipv4, ttl, next_hop_id, + terminator_udp_dst_port, initiator_udp_dst_port, + udp_src_port_if_no_entropy, use_entropy); +} + +int controller::tunnel_port_tenant_add(uint32_t lport_id, + uint32_t tunnel_id) noexcept { + int rv = ofdpa->ofdpaTunnelPortTenantAdd(lport_id, tunnel_id); + + if (rv < 0) { + LOG(ERROR) << __FUNCTION__ << ": failed to add port " << lport_id + << " to tenant " << tunnel_id; + } + + return rv; +} + +int controller::tunnel_port_tenant_remove(uint32_t lport_id, + uint32_t tunnel_id) noexcept { + int rv; + int cnt = 0; + do { + // XXX TODO this is totally crap even if it works for now + + rv = ofdpa->ofdpaTunnelPortTenantDelete(lport_id, tunnel_id); + + VLOG(2) << __FUNCTION__ << ": rv=" << rv << ", cnt=" << cnt + << ", lport_id=" << lport_id << ", tunnel_id=" << tunnel_id; + + cnt++; + } while (rv < 0 && cnt < 100); + + assert(rv == 0); + + if (rv < 0) { + LOG(ERROR) << __FUNCTION__ << ": failed to remove port " << lport_id + << " from tenant " << tunnel_id; + } + + return rv; +} + } // namespace basebox diff --git a/src/of-dpa/controller.hpp b/src/of-dpa/controller.hpp index 6b2ad1826..fba44585e 100644 --- a/src/of-dpa/controller.hpp +++ b/src/of-dpa/controller.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,9 @@ namespace basebox { +// forward declarations +class ofdpa_client; + class eBaseBoxBase : public std::runtime_error { public: eBaseBoxBase(const std::string &__arg) : std::runtime_error(__arg) {} @@ -51,9 +55,11 @@ class controller : public rofl::crofbase, public: controller(std::unique_ptr nb, const rofl::openflow::cofhello_elem_versionbitmap &versionbitmap = - rofl::openflow::cofhello_elem_versionbitmap()) + rofl::openflow::cofhello_elem_versionbitmap(), + uint16_t ofdpa_grpc_port = 50051) : nb(std::move(nb)), bb_thread(1), egress_interface_id(1), - default_idle_timeout(0), connected(false) { + default_idle_timeout(0), connected(false), ofdpa(nullptr), + ofdpa_grpc_port(ofdpa_grpc_port) { this->nb->register_switch(this); rofl::crofbase::set_versionbitmap(versionbitmap); bb_thread.start(); @@ -133,12 +139,21 @@ class controller : public rofl::crofbase, int lag_add_member(uint32_t lag_id, uint32_t port_id) noexcept override; int lag_remove_member(uint32_t lag_id, uint32_t port_id) noexcept override; + int overlay_tunnel_add(uint32_t tunnel_id) noexcept override; + int overlay_tunnel_remove(uint32_t tunnel_id) noexcept override; + int l2_addr_remove_all_in_vlan(uint32_t port, uint16_t vid) noexcept override; int l2_addr_add(uint32_t port, uint16_t vid, const rofl::caddress_ll &mac, bool filtered, bool permanent) noexcept override; int l2_addr_remove(uint32_t port, uint16_t vid, const rofl::caddress_ll &mac) noexcept override; + int l2_overlay_addr_add(uint32_t lport, uint32_t tunnel_id, + const rofl::cmacaddr &mac, + bool permanent) noexcept override; + int l2_overlay_addr_remove(uint32_t tunnel_id, uint32_t lport_id, + const rofl::cmacaddr &mac) noexcept override; + int l3_termination_add(uint32_t sport, uint16_t vid, const rofl::caddress_ll &dmac) noexcept override; int l3_termination_add_v6(uint32_t sport, uint16_t vid, @@ -194,6 +209,11 @@ class controller : public rofl::crofbase, bool untagged) noexcept override; int egress_port_vlan_remove(uint32_t port, uint16_t vid) noexcept override; + int add_l2_overlay_flood(uint32_t tunnel_id, + uint32_t lport_id) noexcept override; + int del_l2_overlay_flood(uint32_t tunnel_id, + uint32_t lport_id) noexcept override; + int egress_bridge_port_vlan_add(uint32_t port, uint16_t vid, bool untagged) noexcept override; int egress_bridge_port_vlan_remove(uint32_t port, @@ -210,12 +230,48 @@ class controller : public rofl::crofbase, int subscribe_to(enum swi_flags flags) noexcept override; + /* tunnel */ + int tunnel_tenant_create(uint32_t tunnel_id, uint32_t vni) noexcept override; + int tunnel_tenant_delete(uint32_t tunnel_id) noexcept override; + + int tunnel_next_hop_create(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) noexcept override; + int tunnel_next_hop_modify(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) noexcept override; + int tunnel_next_hop_delete(uint32_t next_hop_id) noexcept override; + + int tunnel_access_port_create(uint32_t port_id, const std::string &port_name, + uint32_t physical_port, uint16_t vlan_id, + bool untagged) noexcept override; + int tunnel_enpoint_create(uint32_t port_id, const std::string &port_name, + uint32_t remote_ipv4, uint32_t local_ipv4, + uint32_t ttl, uint32_t next_hop_id, + uint32_t terminator_udp_dst_port, + uint32_t initiator_udp_dst_port, + uint32_t udp_src_port_if_no_entropy, + bool use_entropy) noexcept override; + int tunnel_port_delete(uint32_t port_id) noexcept override; + + int tunnel_port_tenant_add(uint32_t lport_id, + uint32_t tunnel_id) noexcept override; + int tunnel_port_tenant_remove(uint32_t lport_id, + uint32_t tunnel_id) noexcept override; + + /* print this */ + friend std::ostream &operator<<(std::ostream &os, const controller &box) { + os << "" << std::endl; + return os; + } + private: rofl::cdptid dptid; rofl::openflow::rofl_ofdpa_fm_driver fm_driver; std::mutex l2_domain_mutex; std::map> l2_domain; std::map> lag; + std::map> tunnel_dlf_flood; std::mutex conn_mutex; rofl::cthread bb_thread; std::mutex stats_mutex; @@ -224,6 +280,8 @@ class controller : public rofl::crofbase, std::set freed_egress_interfaces_ids; uint16_t default_idle_timeout; bool connected; + std::shared_ptr ofdpa; + uint16_t ofdpa_grpc_port; enum timer_t { /* handle_timeout will be called as well from crofbase, hence we need some diff --git a/src/of-dpa/ofdpa_client.cpp b/src/of-dpa/ofdpa_client.cpp new file mode 100644 index 000000000..5c30b9c36 --- /dev/null +++ b/src/of-dpa/ofdpa_client.cpp @@ -0,0 +1,276 @@ +#include + +#include "ofdpa_client.hpp" + +using namespace ofdpa; +using namespace grpc; + +namespace basebox { + +ofdpa_client::ofdpa_client(std::shared_ptr channel) + : stub_(ofdpa::OfdpaRpc::NewStub(channel)) {} + +OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelTenantCreate(uint32_t tunnel_id, uint32_t vni) { + // TODO maybe use ofdpa_datatypes as parameters + + ::TunnelTenantCreate request; + request.set_tunnel_id(tunnel_id); + + ::OfdpaTunnelTenantConfig *config = request.mutable_config(); + config->set_proto(::OFDPA_TUNNEL_PROTO_VXLAN); + config->set_virtual_network_id(vni); + + ::OfdpaStatus response; + ::ClientContext context; + + ::Status rv = stub_->ofdpaTunnelTenantCreate(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelTenantDelete(uint32_t tunnel_id) { + + ::ofdpa::TunnelId request; + + request.set_tunnel_id(tunnel_id); + ::OfdpaStatus response; + ::ClientContext context; + + ::Status rv = stub_->ofdpaTunnelTenantDelete(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelNextHopCreate(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) { + ::TunnelNextHopCreate request; + request.set_next_hop_id(next_hop_id); + ::OfdpaTunnelNextHopConfig *config = request.mutable_config(); + config->set_protocol(OFDPA_TUNNEL_PROTO_VXLAN); + config->set_src_mac_addr(src_mac); // XXX validate? + config->set_dst_mac_addr(dst_mac); // XXX validate? + config->set_physical_port_num(physical_port); + config->set_vlan_id(vlan_id); // XXX validate? + + ::OfdpaStatus response; + ::ClientContext context; + + ::Status rv = stub_->ofdpaTunnelNextHopCreate(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelNextHopDelete(uint32_t next_hop_id) { + ::NextHopId request; + request.set_next_hop_id(next_hop_id); + + ::OfdpaStatus response; + ::ClientContext context; + + ::Status rv = stub_->ofdpaTunnelNextHopDelete(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +ofdpa::OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelNextHopModify(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) { + ::TunnelNextHopCreate request; + request.set_next_hop_id(next_hop_id); + ::OfdpaTunnelNextHopConfig *config = request.mutable_config(); + config->set_protocol(OFDPA_TUNNEL_PROTO_VXLAN); + config->set_src_mac_addr(src_mac); // XXX validate? + config->set_dst_mac_addr(dst_mac); // XXX validate? + config->set_physical_port_num(physical_port); + config->set_vlan_id(vlan_id); // XXX validate? + + ::OfdpaStatus response; + ::ClientContext context; + + ::Status rv = stub_->ofdpaTunnelNextHopModify(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +TunnelPortCreate make_tunnel_port(uint32_t port_id, + const std::string &port_name, + OfdpaTunnelPortType type) { + TunnelPortCreate tunnel_port; + tunnel_port.set_port_num(port_id); + tunnel_port.set_name(port_name); + OfdpaTunnelPortConfig *config = tunnel_port.mutable_config(); + config->set_type(type); + config->set_tunnel_proto(OFDPA_TUNNEL_PROTO_VXLAN); + return tunnel_port; +} + +OfdpaAccessPortConfig make_access_port_config(uint32_t physical_port, + uint32_t vlan_id, bool untagged) { + ::OfdpaAccessPortConfig config; + config.set_pysical_port_num(physical_port); + config.set_vlan_id(vlan_id); + config.set_untagged(untagged); + return config; +} + +OfdpaEndpointConfig make_endpoint_config(uint32_t remote, uint32_t local, + uint32_t ttl, uint32_t next_hop_id, + uint32_t terminator_udp_dst_port, + uint32_t initiator_udp_dst_port, + uint32_t udp_src_port_if_no_entropy, + bool use_entropy) { + OfdpaEndpointConfig config; + config.set_remote_endpoint(remote); + config.set_local_endpoint(local); + config.set_ttl(ttl); + config.set_next_hop_id(next_hop_id); + + OfdpaVxlanProtoInfo *info = config.mutable_info()->mutable_vxlan_info(); + info->set_initiator_udp_dst_port(initiator_udp_dst_port); /* remote port */ + info->set_terminator_udp_dst_port(terminator_udp_dst_port); /* local port; + must be the + same for all + tunnels */ + info->set_udp_src_port_if_no_entropy(0); + info->set_use_entropy( + use_entropy); /* must be the same accross all vxlan tunnels */ + + return config; +} + +OfdpaStatus::OfdpaStatusCode ofdpa_client::ofdpaTunnelAccessPortCreate( + uint32_t port_id, const std::string &port_name, uint32_t physical_port, + uint16_t vlan_id, bool untagged) { + // XXX TODO check parameters + TunnelPortCreate request = + make_tunnel_port(port_id, port_name, OFDPA_TUNNEL_PORT_TYPE_ACCESS); + + request.mutable_config() + ->mutable_config() + ->mutable_access_port_config() + ->CopyFrom(make_access_port_config(physical_port, vlan_id, untagged)); + + return ofdpaTunnelPortCreate(request); +} + +OfdpaStatus::OfdpaStatusCode ofdpa_client::ofdpaTunnelEndpointPortCreate( + uint32_t port_id, const std::string &port_name, uint32_t remote_ipv4, + uint32_t local_ipv4, uint32_t ttl, uint32_t next_hop_id, + uint32_t terminator_udp_dst_port, uint32_t initiator_udp_dst_port, + uint32_t udp_src_port_if_no_entropy, bool use_entropy) { + // XXX TODO check parameters + TunnelPortCreate request = + make_tunnel_port(port_id, port_name, OFDPA_TUNNEL_PORT_TYPE_ENDPOINT); + request.mutable_config() + ->mutable_config() + ->mutable_endpoint_config() + ->CopyFrom(make_endpoint_config( + remote_ipv4, local_ipv4, ttl, next_hop_id, terminator_udp_dst_port, + initiator_udp_dst_port, udp_src_port_if_no_entropy, use_entropy)); + + return ofdpaTunnelPortCreate(request); +} + +OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelPortCreate(const ::ofdpa::TunnelPortCreate &request) { + ::OfdpaStatus response; + ::ClientContext context; + ::Status rv = stub_->ofdpaTunnelPortCreate(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +ofdpa::OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelPortDelete(uint32_t lport_id) { + ::PortNum request; + request.set_port_num(lport_id); + ::OfdpaStatus response; + ::ClientContext context; + + ::Status rv = stub_->ofdpaTunnelPortDelete(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelPortTenantAdd(uint32_t port_id, uint32_t tunnel_id) { + ::TunnelPortTenantAdd request; + + request.set_port_num(port_id); + request.set_tunnel_id(tunnel_id); + + ::OfdpaStatus response; + ::ClientContext context; + ::Status rv = stub_->ofdpaTunnelPortTenantAdd(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +ofdpa::OfdpaStatus::OfdpaStatusCode +ofdpa_client::ofdpaTunnelPortTenantDelete(uint32_t port_id, + uint32_t tunnel_id) { + ::TunnelPortTenantAdd request; + + request.set_port_num(port_id); + request.set_tunnel_id(tunnel_id); + + ::OfdpaStatus response; + ::ClientContext context; + ::Status rv = + stub_->ofdpaTunnelPortTenantDelete(&context, request, &response); + + if (not rv.ok()) { + // LOG status + return ofdpa::OfdpaStatus::OFDPA_E_RPC; + } + + return response.status(); +} + +} // namespace basebox diff --git a/src/of-dpa/ofdpa_client.hpp b/src/of-dpa/ofdpa_client.hpp new file mode 100644 index 000000000..727b8454d --- /dev/null +++ b/src/of-dpa/ofdpa_client.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include "api/ofdpa.grpc.pb.h" + +namespace grpc { +class Channel; +} + +namespace basebox { + +class ofdpa_client { +public: + ofdpa_client(std::shared_ptr channel); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelTenantCreate(uint32_t tunnel_id, uint32_t vni); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelTenantDelete(uint32_t tunnel_id); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelNextHopCreate(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelNextHopDelete(uint32_t next_hop_id); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelNextHopModify(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelAccessPortCreate(uint32_t port_id, const std::string &port_name, + uint32_t physical_port, uint16_t vlan_id, + bool untagged); + + ofdpa::OfdpaStatus::OfdpaStatusCode ofdpaTunnelEndpointPortCreate( + uint32_t port_id, const std::string &port_name, uint32_t remote_ipv4, + uint32_t local_ipv4, uint32_t ttl, uint32_t next_hop_id, + uint32_t terminator_udp_dst_port, uint32_t initiator_udp_dst_port, + uint32_t udp_src_port_if_no_entropy, bool use_entropy); + + ofdpa::OfdpaStatus::OfdpaStatusCode ofdpaTunnelPortDelete(uint32_t lport_id); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelPortTenantAdd(uint32_t port_id, uint32_t tunnel_id); + + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelPortTenantDelete(uint32_t port_id, uint32_t tunnel_id); + +private: + ofdpa::OfdpaStatus::OfdpaStatusCode + ofdpaTunnelPortCreate(const ::ofdpa::TunnelPortCreate &request); + + std::unique_ptr stub_; +}; + +} // namespace basebox diff --git a/src/sai.hpp b/src/sai.hpp index 0ff4b3825..9b4e4600d 100644 --- a/src/sai.hpp +++ b/src/sai.hpp @@ -39,6 +39,9 @@ class switch_interface { virtual int lag_add_member(uint32_t lag_id, uint32_t port_id) noexcept = 0; virtual int lag_remove_member(uint32_t lag_id, uint32_t port_id) noexcept = 0; + virtual int overlay_tunnel_add(uint32_t tunnel_id) noexcept = 0; + virtual int overlay_tunnel_remove(uint32_t tunnel_id) noexcept = 0; + virtual int l2_addr_remove_all_in_vlan(uint32_t port, uint16_t vid) noexcept = 0; virtual int l2_addr_add(uint32_t port, uint16_t vid, @@ -47,6 +50,12 @@ class switch_interface { virtual int l2_addr_remove(uint32_t port, uint16_t vid, const rofl::caddress_ll &mac) noexcept = 0; + virtual int l2_overlay_addr_add(uint32_t lport, uint32_t tunnel_id, + const rofl::cmacaddr &mac, + bool permanent) noexcept = 0; + virtual int l2_overlay_addr_remove(uint32_t tunnel_id, uint32_t lport_id, + const rofl::cmacaddr &mac) noexcept = 0; + virtual int l3_termination_add(uint32_t sport, uint16_t vid, const rofl::caddress_ll &dmac) noexcept = 0; virtual int l3_termination_add_v6(uint32_t sport, uint16_t vid, @@ -105,6 +114,12 @@ class switch_interface { virtual int egress_port_vlan_add(uint32_t port, uint16_t vid, bool untagged) noexcept = 0; virtual int egress_port_vlan_remove(uint32_t port, uint16_t vid) noexcept = 0; + + virtual int add_l2_overlay_flood(uint32_t tunnel_id, + uint32_t lport_id) noexcept = 0; + virtual int del_l2_overlay_flood(uint32_t tunnel_id, + uint32_t lport_id) noexcept = 0; + virtual int egress_bridge_port_vlan_add(uint32_t port, uint16_t vid, bool untagged) noexcept = 0; virtual int egress_bridge_port_vlan_remove(uint32_t port, @@ -118,6 +133,35 @@ class switch_interface { virtual int get_statistics(uint64_t port_no, uint32_t number_of_counters, const sai_port_stat_t *counter_ids, uint64_t *counters) noexcept = 0; + + virtual int tunnel_tenant_create(uint32_t tunnel_id, + uint32_t vni) noexcept = 0; + virtual int tunnel_tenant_delete(uint32_t tunnel_id) noexcept = 0; + + virtual int tunnel_next_hop_create(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) noexcept = 0; + virtual int tunnel_next_hop_modify(uint32_t next_hop_id, uint64_t src_mac, + uint64_t dst_mac, uint32_t physical_port, + uint16_t vlan_id) noexcept = 0; + virtual int tunnel_next_hop_delete(uint32_t next_hop_id) noexcept = 0; + + virtual int tunnel_access_port_create(uint32_t port_id, + const std::string &port_name, + uint32_t physical_port, + uint16_t vlan_id, + bool untagged) noexcept = 0; + virtual int tunnel_enpoint_create( + uint32_t port_id, const std::string &port_name, uint32_t remote_ipv4, + uint32_t local_ipv4, uint32_t ttl, uint32_t next_hop_id, + uint32_t terminator_udp_dst_port, uint32_t initiator_udp_dst_port, + uint32_t udp_src_port_if_no_entropy, bool use_entropy) noexcept = 0; + virtual int tunnel_port_delete(uint32_t port_id) noexcept = 0; + + virtual int tunnel_port_tenant_add(uint32_t port_id, + uint32_t tunnel_id) noexcept = 0; + virtual int tunnel_port_tenant_remove(uint32_t port_id, + uint32_t tunnel_id) noexcept = 0; }; class nbi { @@ -127,10 +171,12 @@ class nbi { PORT_EVENT_ADD, PORT_EVENT_DEL, }; + enum port_status { PORT_STATUS_LOWER_DOWN = 0x01, PORT_STATUS_ADMIN_DOWN = 0x02, }; + struct port_notification_data { enum port_event ev; uint32_t port_id;