GBP Endpoint Learning

Learning GBP endpoints over vxlan-gbp tunnels

Change-Id: I1db9fda5a16802d9ad8b4efd4e475614f3b21502
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
This commit is contained in:
Neale Ranns
2018-10-10 07:22:51 -07:00
committed by Damjan Marion
parent c3df1e9a0a
commit 93cc3ee3b3
74 changed files with 9904 additions and 1068 deletions

View File

@ -68,16 +68,22 @@ endif()
if(GBP_FILE)
list(APPEND VOM_SOURCES
gbp_recirc_cmds.cpp
gbp_recirc.cpp
gbp_subnet_cmds.cpp
gbp_subnet.cpp
gbp_contract_cmds.cpp
gbp_contract.cpp
gbp_bridge_domain_cmds.cpp
gbp_bridge_domain.cpp
gbp_endpoint_cmds.cpp
gbp_endpoint.cpp
gbp_endpoint_group_cmds.cpp
gbp_endpoint_group.cpp
gbp_contract_cmds.cpp
gbp_contract.cpp
gbp_recirc_cmds.cpp
gbp_recirc.cpp
gbp_route_domain_cmds.cpp
gbp_route_domain.cpp
gbp_subnet_cmds.cpp
gbp_subnet.cpp
gbp_vxlan.cpp
gbp_vxlan_cmds.cpp
)
endif()

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_bridge_domain.hpp"
#include "vom/gbp_bridge_domain_cmds.hpp"
#include "vom/interface.hpp"
#include "vom/l2_binding.hpp"
#include "vom/singular_db_funcs.hpp"
namespace VOM {
/**
* A DB of al the interfaces, key on the name
*/
singular_db<uint32_t, gbp_bridge_domain> gbp_bridge_domain::m_db;
gbp_bridge_domain::event_handler gbp_bridge_domain::m_evh;
/**
* Construct a new object matching the desried state
*/
gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd)
: m_id(bd.id())
, m_bd(bd.singular())
{
}
gbp_bridge_domain::gbp_bridge_domain(const bridge_domain& bd,
const interface& bvi,
const interface& uu_fwd)
: m_id(bd.id())
, m_bd(bd.singular())
, m_bvi(bvi.singular())
, m_uu_fwd(uu_fwd.singular())
{
}
gbp_bridge_domain::gbp_bridge_domain(const gbp_bridge_domain& bd)
: m_id(bd.id())
, m_bd(bd.m_bd)
{
}
const gbp_bridge_domain::key_t
gbp_bridge_domain::key() const
{
return (m_bd->key());
}
uint32_t
gbp_bridge_domain::id() const
{
return (m_bd->id());
}
bool
gbp_bridge_domain::operator==(const gbp_bridge_domain& b) const
{
bool equal = true;
if (m_bvi && b.m_bvi)
equal &= (m_bvi->key() == b.m_bvi->key());
else if (!m_bvi && !b.m_bvi)
;
else
equal = false;
if (m_uu_fwd && b.m_uu_fwd)
equal &= (m_uu_fwd->key() == b.m_uu_fwd->key());
else if (!m_uu_fwd && !b.m_uu_fwd)
;
else
equal = false;
return ((m_bd->key() == b.m_bd->key()) && equal);
}
void
gbp_bridge_domain::sweep()
{
if (rc_t::OK == m_id.rc()) {
HW::enqueue(new gbp_bridge_domain_cmds::delete_cmd(m_id));
}
HW::write();
}
void
gbp_bridge_domain::replay()
{
if (rc_t::OK == m_id.rc()) {
if (m_bvi && m_uu_fwd)
HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(m_id, m_bvi->handle(),
m_uu_fwd->handle()));
else
HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(
m_id, handle_t::INVALID, handle_t::INVALID));
}
}
gbp_bridge_domain::~gbp_bridge_domain()
{
sweep();
// not in the DB anymore.
m_db.release(m_id.data(), this);
}
std::string
gbp_bridge_domain::to_string() const
{
std::ostringstream s;
s << "gbp-bridge-domain:[" << m_bd->to_string() << "]";
return (s.str());
}
std::shared_ptr<gbp_bridge_domain>
gbp_bridge_domain::find(const key_t& key)
{
return (m_db.find(key));
}
void
gbp_bridge_domain::update(const gbp_bridge_domain& desired)
{
/*
* the desired state is always that the interface should be created
*/
if (rc_t::OK != m_id.rc()) {
if (m_bvi && m_uu_fwd)
HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(m_id, m_bvi->handle(),
m_uu_fwd->handle()));
else
HW::enqueue(new gbp_bridge_domain_cmds::create_cmd(
m_id, handle_t::INVALID, handle_t::INVALID));
}
}
std::shared_ptr<gbp_bridge_domain>
gbp_bridge_domain::find_or_add(const gbp_bridge_domain& temp)
{
return (m_db.find_or_add(temp.m_id.data(), temp));
}
std::shared_ptr<gbp_bridge_domain>
gbp_bridge_domain::singular() const
{
return find_or_add(*this);
}
void
gbp_bridge_domain::dump(std::ostream& os)
{
db_dump(m_db, os);
}
void
gbp_bridge_domain::event_handler::handle_populate(const client_db::key_t& key)
{
/*
* dump VPP Bridge domains
*/
std::shared_ptr<gbp_bridge_domain_cmds::dump_cmd> cmd =
std::make_shared<gbp_bridge_domain_cmds::dump_cmd>();
HW::enqueue(cmd);
HW::write();
for (auto& record : *cmd) {
auto& payload = record.get_payload();
std::shared_ptr<interface> uu_fwd =
interface::find(payload.bd.uu_fwd_sw_if_index);
std::shared_ptr<interface> bvi =
interface::find(payload.bd.bvi_sw_if_index);
if (uu_fwd && bvi) {
gbp_bridge_domain bd(payload.bd.bd_id, *bvi, *uu_fwd);
OM::commit(key, bd);
VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
} else {
gbp_bridge_domain bd(payload.bd.bd_id);
OM::commit(key, bd);
VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
}
}
}
gbp_bridge_domain::event_handler::event_handler()
{
OM::register_listener(this);
inspect::register_handler({ "gbd", "gbridge" }, "GBP Bridge Domains", this);
}
void
gbp_bridge_domain::event_handler::handle_replay()
{
m_db.replay();
}
dependency_t
gbp_bridge_domain::event_handler::order() const
{
return (dependency_t::TABLE);
}
void
gbp_bridge_domain::event_handler::show(std::ostream& os)
{
db_dump(m_db, os);
}
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 __VOM_GBP_BRIDGE_DOMAIN_H__
#define __VOM_GBP_BRIDGE_DOMAIN_H__
#include "vom/bridge_domain.hpp"
#include "vom/interface.hpp"
#include "vom/singular_db.hpp"
#include "vom/types.hpp"
namespace VOM {
/**
* A entry in the ARP termination table of a Bridge Domain
*/
class gbp_bridge_domain : public object_base
{
public:
/**
* The key for a bridge_domain is the pari of EPG-IDs
*/
typedef bridge_domain::key_t key_t;
/**
* Construct a GBP bridge_domain
*/
gbp_bridge_domain(const bridge_domain& bd);
gbp_bridge_domain(const bridge_domain& bd,
const interface& bvi,
const interface& uu_fwd);
/**
* Copy Construct
*/
gbp_bridge_domain(const gbp_bridge_domain& r);
/**
* Destructor
*/
~gbp_bridge_domain();
/**
* Return the object's key
*/
const key_t key() const;
/**
* Return the bridge domain's VPP ID
*/
uint32_t id() const;
/**
* comparison operator
*/
bool operator==(const gbp_bridge_domain& bdae) const;
/**
* Return the matching 'singular instance'
*/
std::shared_ptr<gbp_bridge_domain> singular() const;
/**
* Find the instnace of the bridge_domain domain in the OM
*/
static std::shared_ptr<gbp_bridge_domain> find(const key_t& k);
/**
* Dump all bridge_domain-doamin into the stream provided
*/
static void dump(std::ostream& os);
/**
* replay the object to create it in hardware
*/
void replay(void);
/**
* Convert to string for debugging
*/
std::string to_string() const;
private:
/**
* Class definition for listeners to OM events
*/
class event_handler : public OM::listener, public inspect::command_handler
{
public:
event_handler();
virtual ~event_handler() = default;
/**
* Handle a populate event
*/
void handle_populate(const client_db::key_t& key);
/**
* Handle a replay event
*/
void handle_replay();
/**
* Show the object in the Singular DB
*/
void show(std::ostream& os);
/**
* Get the sortable Id of the listener
*/
dependency_t order() const;
};
/**
* event_handler to register with OM
*/
static event_handler m_evh;
/**
* Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
*/
void update(const gbp_bridge_domain& obj);
/**
* Find or add the instance of the bridge_domain domain in the OM
*/
static std::shared_ptr<gbp_bridge_domain> find_or_add(
const gbp_bridge_domain& temp);
/*
* It's the VPPHW class that updates the objects in HW
*/
friend class OM;
/**
* It's the singular_db class that calls replay()
*/
friend class singular_db<key_t, gbp_bridge_domain>;
/**
* Sweep/reap the object if still stale
*/
void sweep(void);
/**
* HW configuration for the result of creating the endpoint
*/
HW::item<uint32_t> m_id;
std::shared_ptr<bridge_domain> m_bd;
std::shared_ptr<interface> m_bvi;
std::shared_ptr<interface> m_uu_fwd;
/**
* A map of all bridge_domains
*/
static singular_db<key_t, gbp_bridge_domain> m_db;
};
}; // namespace
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_bridge_domain_cmds.hpp"
namespace VOM {
namespace gbp_bridge_domain_cmds {
create_cmd::create_cmd(HW::item<uint32_t>& item,
const handle_t bvi,
const handle_t uu_fwd)
: rpc_cmd(item)
, m_bvi(bvi)
, m_uu_fwd(uu_fwd)
{
}
bool
create_cmd::operator==(const create_cmd& other) const
{
return ((m_hw_item.data() == other.m_hw_item.data()) &&
(m_bvi == other.m_bvi) && (m_uu_fwd == other.m_uu_fwd));
}
rc_t
create_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.bd.bd_id = m_hw_item.data();
payload.bd.bvi_sw_if_index = m_bvi.value();
payload.bd.uu_fwd_sw_if_index = m_uu_fwd.value();
VAPI_CALL(req.execute());
return (wait());
}
std::string
create_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-bridge-domain: " << m_hw_item.to_string()
<< " bvi:" << m_bvi.to_string() << " uu-fwd:" << m_uu_fwd.to_string();
return (s.str());
}
delete_cmd::delete_cmd(HW::item<uint32_t>& item)
: rpc_cmd(item)
{
}
bool
delete_cmd::operator==(const delete_cmd& other) const
{
return (m_hw_item.data() == other.m_hw_item.data());
}
rc_t
delete_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.bd_id = m_hw_item.data();
VAPI_CALL(req.execute());
wait();
m_hw_item.set(rc_t::NOOP);
return rc_t::OK;
}
std::string
delete_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-bridge-domain: " << m_hw_item.to_string();
return (s.str());
}
bool
dump_cmd::operator==(const dump_cmd& other) const
{
return (true);
}
rc_t
dump_cmd::issue(connection& con)
{
m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
VAPI_CALL(m_dump->execute());
wait();
return rc_t::OK;
}
std::string
dump_cmd::to_string() const
{
return ("gbp-bridge-domain-dump");
}
}; // namespace gbp_bridge_domain_cmds
}; // namespace VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 __VOM_GBP_BRIDGE_DOMAIN_CMDS_H__
#define __VOM_GBP_BRIDGE_DOMAIN_CMDS_H__
#include "vom/dump_cmd.hpp"
#include "vom/gbp_bridge_domain.hpp"
#include "vom/rpc_cmd.hpp"
#include <vapi/gbp.api.vapi.hpp>
namespace VOM {
namespace gbp_bridge_domain_cmds {
/**
* A command class that creates an Bridge-Domain
*/
class create_cmd
: public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_bridge_domain_add>
{
public:
/**
* Constructor
*/
create_cmd(HW::item<uint32_t>& item,
const handle_t bvi,
const handle_t uu_fwd);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const create_cmd& i) const;
private:
const handle_t m_bvi;
const handle_t m_uu_fwd;
};
/**
* A cmd class that Delete an Bridge-Domain
*/
class delete_cmd
: public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_bridge_domain_del>
{
public:
/**
* Constructor
*/
delete_cmd(HW::item<uint32_t>& item);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const delete_cmd& i) const;
};
/**
* A cmd class that Dumps all the bridge domains
*/
class dump_cmd : public VOM::dump_cmd<vapi::Gbp_bridge_domain_dump>
{
public:
/**
* Constructor
*/
dump_cmd() = default;
dump_cmd(const dump_cmd& d) = default;
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const dump_cmd& i) const;
private:
/**
* HW reutrn code
*/
HW::item<bool> item;
};
}; // gbp_bridge_domain_cmds
}; // VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -91,7 +91,7 @@ private:
};
/**
* A cmd class that Dumps all the GBP endpoints
* A cmd class that Dumps all the GBP contracts
*/
class dump_cmd : public VOM::dump_cmd<vapi::Gbp_contract_dump>
{

View File

@ -26,8 +26,8 @@ gbp_endpoint_group::event_handler gbp_endpoint_group::m_evh;
gbp_endpoint_group::gbp_endpoint_group(epg_id_t epg_id,
const interface& itf,
const route_domain& rd,
const bridge_domain& bd)
const gbp_route_domain& rd,
const gbp_bridge_domain& bd)
: m_hw(false)
, m_epg_id(epg_id)
, m_itf(itf.singular())
@ -64,10 +64,10 @@ gbp_endpoint_group::id() const
}
bool
gbp_endpoint_group::operator==(const gbp_endpoint_group& gbpe) const
gbp_endpoint_group::operator==(const gbp_endpoint_group& gg) const
{
return (key() == gbpe.key() && (m_itf == gbpe.m_itf) && (m_rd == gbpe.m_rd) &&
(m_bd == gbpe.m_bd));
return (key() == gg.key() && (m_itf == gg.m_itf) && (m_rd == gg.m_rd) &&
(m_bd == gg.m_bd));
}
void
@ -84,7 +84,7 @@ gbp_endpoint_group::replay()
{
if (m_hw) {
HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
m_hw, m_epg_id, m_bd->id(), m_rd->table_id(), m_itf->handle()));
m_hw, m_epg_id, m_bd->id(), m_rd->id(), m_itf->handle()));
}
}
@ -104,7 +104,7 @@ gbp_endpoint_group::update(const gbp_endpoint_group& r)
{
if (rc_t::OK != m_hw.rc()) {
HW::enqueue(new gbp_endpoint_group_cmds::create_cmd(
m_hw, m_epg_id, m_bd->id(), m_rd->table_id(), m_itf->handle()));
m_hw, m_epg_id, m_bd->id(), m_rd->id(), m_itf->handle()));
}
}
@ -159,12 +159,13 @@ gbp_endpoint_group::event_handler::handle_populate(const client_db::key_t& key)
std::shared_ptr<interface> itf =
interface::find(payload.epg.uplink_sw_if_index);
std::shared_ptr<route_domain> rd =
route_domain::find(payload.epg.ip4_table_id);
std::shared_ptr<bridge_domain> bd = bridge_domain::find(payload.epg.bd_id);
std::shared_ptr<gbp_route_domain> rd =
gbp_route_domain::find(payload.epg.rd_id);
std::shared_ptr<gbp_bridge_domain> bd =
gbp_bridge_domain::find(payload.epg.bd_id);
VOM_LOG(log_level_t::DEBUG) << "data: [" << payload.epg.uplink_sw_if_index
<< ", " << payload.epg.ip4_table_id << ", "
<< ", " << payload.epg.rd_id << ", "
<< payload.epg.bd_id << "]";
if (itf && bd && rd) {

View File

@ -20,8 +20,8 @@
#include "vom/singular_db.hpp"
#include "vom/types.hpp"
#include "vom/bridge_domain.hpp"
#include "vom/route_domain.hpp"
#include "vom/gbp_bridge_domain.hpp"
#include "vom/gbp_route_domain.hpp"
namespace VOM {
@ -46,8 +46,11 @@ public:
*/
gbp_endpoint_group(epg_id_t epg_id,
const interface& itf,
const route_domain& rd,
const bridge_domain& bd);
const gbp_route_domain& rd,
const gbp_bridge_domain& bd);
gbp_endpoint_group(epg_id_t epg_id,
const gbp_route_domain& rd,
const gbp_bridge_domain& bd);
/**
* Copy Construct
@ -179,12 +182,12 @@ private:
/**
* The route-domain the EPG uses
*/
std::shared_ptr<route_domain> m_rd;
std::shared_ptr<gbp_route_domain> m_rd;
/**
* The bridge-domain the EPG uses
*/
std::shared_ptr<bridge_domain> m_bd;
std::shared_ptr<gbp_bridge_domain> m_bd;
/**
* A map of all bridge_domains

View File

@ -44,12 +44,10 @@ create_cmd::issue(connection& con)
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.is_add = 1;
payload.epg.uplink_sw_if_index = m_itf.value();
payload.epg.epg_id = m_epg_id;
payload.epg.bd_id = m_bd_id;
payload.epg.ip4_table_id = m_rd_id;
payload.epg.ip6_table_id = m_rd_id;
payload.epg.rd_id = m_rd_id;
VAPI_CALL(req.execute());
@ -85,8 +83,7 @@ delete_cmd::issue(connection& con)
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.is_add = 0;
payload.epg.epg_id = m_epg_id;
payload.epg_id = m_epg_id;
VAPI_CALL(req.execute());

View File

@ -27,8 +27,7 @@ namespace gbp_endpoint_group_cmds {
/**
* A command class that creates or updates the GBP endpoint_group
*/
class create_cmd
: public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_add_del>
class create_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_add>
{
public:
/**
@ -65,8 +64,7 @@ private:
/**
* A cmd class that deletes a GBP endpoint_group
*/
class delete_cmd
: public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_add_del>
class delete_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_endpoint_group_del>
{
public:
/**

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_route_domain.hpp"
#include "vom/gbp_route_domain_cmds.hpp"
#include "vom/interface.hpp"
#include "vom/l2_binding.hpp"
#include "vom/singular_db_funcs.hpp"
namespace VOM {
/**
* A DB of al the interfaces, key on the name
*/
singular_db<uint32_t, gbp_route_domain> gbp_route_domain::m_db;
gbp_route_domain::event_handler gbp_route_domain::m_evh;
/**
* Construct a new object matching the desried state
*/
gbp_route_domain::gbp_route_domain(const gbp_route_domain& rd)
: m_id(rd.id())
, m_rd(rd.m_rd)
{
}
gbp_route_domain::gbp_route_domain(const route_domain& rd,
const interface& ip4_uu_fwd,
const interface& ip6_uu_fwd)
: m_id(rd.table_id())
, m_rd(rd.singular())
, m_ip4_uu_fwd(ip4_uu_fwd.singular())
, m_ip6_uu_fwd(ip6_uu_fwd.singular())
{
}
gbp_route_domain::gbp_route_domain(const route_domain& rd)
: m_id(rd.table_id())
, m_rd(rd.singular())
{
}
const gbp_route_domain::key_t
gbp_route_domain::key() const
{
return (m_rd->key());
}
uint32_t
gbp_route_domain::id() const
{
return (m_rd->table_id());
}
bool
gbp_route_domain::operator==(const gbp_route_domain& b) const
{
bool equal = true;
if (m_ip4_uu_fwd && b.m_ip4_uu_fwd)
equal &= (m_ip4_uu_fwd->key() == b.m_ip4_uu_fwd->key());
else if (!m_ip4_uu_fwd && !b.m_ip4_uu_fwd)
;
else
equal = false;
if (m_ip6_uu_fwd && b.m_ip6_uu_fwd)
equal &= (m_ip6_uu_fwd->key() == b.m_ip6_uu_fwd->key());
else if (!m_ip6_uu_fwd && !b.m_ip6_uu_fwd)
;
else
equal = false;
return ((m_rd->key() == b.m_rd->key()) && equal);
}
void
gbp_route_domain::sweep()
{
if (rc_t::OK == m_id.rc()) {
HW::enqueue(new gbp_route_domain_cmds::delete_cmd(m_id));
}
HW::write();
}
void
gbp_route_domain::replay()
{
if (rc_t::OK == m_id.rc()) {
if (m_ip4_uu_fwd && m_ip6_uu_fwd)
HW::enqueue(new gbp_route_domain_cmds::create_cmd(
m_id, m_ip4_uu_fwd->handle(), m_ip6_uu_fwd->handle()));
else
HW::enqueue(new gbp_route_domain_cmds::create_cmd(m_id, handle_t::INVALID,
handle_t::INVALID));
}
}
gbp_route_domain::~gbp_route_domain()
{
sweep();
// not in the DB anymore.
m_db.release(m_id.data(), this);
}
std::string
gbp_route_domain::to_string() const
{
std::ostringstream s;
s << "gbp-route-domain:[" << m_rd->to_string() << "]";
return (s.str());
}
std::shared_ptr<gbp_route_domain>
gbp_route_domain::find(const key_t& key)
{
return (m_db.find(key));
}
void
gbp_route_domain::update(const gbp_route_domain& desired)
{
/*
* the desired state is always that the interface should be created
*/
if (rc_t::OK != m_id.rc()) {
if (m_ip4_uu_fwd && m_ip6_uu_fwd)
HW::enqueue(new gbp_route_domain_cmds::create_cmd(
m_id, m_ip4_uu_fwd->handle(), m_ip6_uu_fwd->handle()));
else
HW::enqueue(new gbp_route_domain_cmds::create_cmd(m_id, handle_t::INVALID,
handle_t::INVALID));
}
}
std::shared_ptr<gbp_route_domain>
gbp_route_domain::find_or_add(const gbp_route_domain& temp)
{
return (m_db.find_or_add(temp.m_id.data(), temp));
}
std::shared_ptr<gbp_route_domain>
gbp_route_domain::singular() const
{
return find_or_add(*this);
}
void
gbp_route_domain::dump(std::ostream& os)
{
db_dump(m_db, os);
}
void
gbp_route_domain::event_handler::handle_populate(const client_db::key_t& key)
{
/*
* dump VPP Route domains
*/
std::shared_ptr<gbp_route_domain_cmds::dump_cmd> cmd =
std::make_shared<gbp_route_domain_cmds::dump_cmd>();
HW::enqueue(cmd);
HW::write();
for (auto& record : *cmd) {
auto& payload = record.get_payload();
std::shared_ptr<interface> ip6_uu_fwd =
interface::find(payload.rd.ip6_uu_sw_if_index);
std::shared_ptr<interface> ip4_uu_fwd =
interface::find(payload.rd.ip4_uu_sw_if_index);
if (ip6_uu_fwd && ip4_uu_fwd) {
gbp_route_domain rd(payload.rd.rd_id, *ip4_uu_fwd, *ip6_uu_fwd);
OM::commit(key, rd);
VOM_LOG(log_level_t::DEBUG) << "dump: " << rd.to_string();
} else {
gbp_route_domain rd(payload.rd.rd_id);
OM::commit(key, rd);
VOM_LOG(log_level_t::DEBUG) << "dump: " << rd.to_string();
}
}
}
gbp_route_domain::event_handler::event_handler()
{
OM::register_listener(this);
inspect::register_handler({ "grd", "groute" }, "GBP Route Domains", this);
}
void
gbp_route_domain::event_handler::handle_replay()
{
m_db.replay();
}
dependency_t
gbp_route_domain::event_handler::order() const
{
return (dependency_t::TABLE);
}
void
gbp_route_domain::event_handler::show(std::ostream& os)
{
db_dump(m_db, os);
}
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 __VOM_GBP_ROUTE_DOMAIN_H__
#define __VOM_GBP_ROUTE_DOMAIN_H__
#include "vom/interface.hpp"
#include "vom/route_domain.hpp"
#include "vom/singular_db.hpp"
#include "vom/types.hpp"
namespace VOM {
/**
* A entry in the ARP termination table of a Route Domain
*/
class gbp_route_domain : public object_base
{
public:
/**
* The key for a route_domain is the pari of EPG-IDs
*/
typedef route_domain::key_t key_t;
/**
* Construct a GBP route_domain
*/
gbp_route_domain(const route_domain& rd);
gbp_route_domain(const route_domain& rd,
const interface& ip4_uu_fwd,
const interface& ip6_uu_fwd);
/**
* Copy Construct
*/
gbp_route_domain(const gbp_route_domain& r);
/**
* Destructor
*/
~gbp_route_domain();
/**
* Return the object's key
*/
const key_t key() const;
/**
* Return the route domain's VPP ID
*/
uint32_t id() const;
/**
* comparison operator
*/
bool operator==(const gbp_route_domain& rdae) const;
/**
* Return the matching 'singular instance'
*/
std::shared_ptr<gbp_route_domain> singular() const;
/**
* Find the instnace of the route_domain domain in the OM
*/
static std::shared_ptr<gbp_route_domain> find(const key_t& k);
/**
* Dump all route_domain-doamin into the stream provided
*/
static void dump(std::ostream& os);
/**
* replay the object to create it in hardware
*/
void replay(void);
/**
* Convert to string for debugging
*/
std::string to_string() const;
private:
/**
* Class definition for listeners to OM events
*/
class event_handler : public OM::listener, public inspect::command_handler
{
public:
event_handler();
virtual ~event_handler() = default;
/**
* Handle a populate event
*/
void handle_populate(const client_db::key_t& key);
/**
* Handle a replay event
*/
void handle_replay();
/**
* Show the object in the Singular DB
*/
void show(std::ostream& os);
/**
* Get the sortable Id of the listener
*/
dependency_t order() const;
};
/**
* event_handler to register with OM
*/
static event_handler m_evh;
/**
* Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
*/
void update(const gbp_route_domain& obj);
/**
* Find or add the instance of the route_domain domain in the OM
*/
static std::shared_ptr<gbp_route_domain> find_or_add(
const gbp_route_domain& temp);
/*
* It's the VPPHW class that updates the objects in HW
*/
friend class OM;
/**
* It's the singular_db class that calls replay()
*/
friend class singular_db<key_t, gbp_route_domain>;
/**
* Sweep/reap the object if still stale
*/
void sweep(void);
/**
* HW configuration for the result of creating the endpoint
*/
HW::item<uint32_t> m_id;
std::shared_ptr<route_domain> m_rd;
std::shared_ptr<interface> m_ip4_uu_fwd;
std::shared_ptr<interface> m_ip6_uu_fwd;
/**
* A map of all route_domains
*/
static singular_db<key_t, gbp_route_domain> m_db;
};
}; // namespace
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_route_domain_cmds.hpp"
namespace VOM {
namespace gbp_route_domain_cmds {
create_cmd::create_cmd(HW::item<uint32_t>& item,
const handle_t ip4_uu_fwd,
const handle_t ip6_uu_fwd)
: rpc_cmd(item)
, m_ip4_uu_fwd(ip4_uu_fwd)
, m_ip6_uu_fwd(ip6_uu_fwd)
{
}
bool
create_cmd::operator==(const create_cmd& other) const
{
return ((m_hw_item.data() == other.m_hw_item.data()) &&
(m_ip4_uu_fwd == other.m_ip4_uu_fwd) &&
(m_ip6_uu_fwd == other.m_ip6_uu_fwd));
}
rc_t
create_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.rd.rd_id = m_hw_item.data();
payload.rd.ip4_uu_sw_if_index = m_ip4_uu_fwd.value();
payload.rd.ip6_uu_sw_if_index = m_ip6_uu_fwd.value();
VAPI_CALL(req.execute());
return (wait());
}
std::string
create_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-route-domain: " << m_hw_item.to_string()
<< " ip4-uu-fwd:" << m_ip4_uu_fwd.to_string()
<< " ip6-uu-fwd:" << m_ip6_uu_fwd.to_string();
return (s.str());
}
delete_cmd::delete_cmd(HW::item<uint32_t>& item)
: rpc_cmd(item)
{
}
bool
delete_cmd::operator==(const delete_cmd& other) const
{
return (m_hw_item.data() == other.m_hw_item.data());
}
rc_t
delete_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.rd_id = m_hw_item.data();
VAPI_CALL(req.execute());
wait();
m_hw_item.set(rc_t::NOOP);
return rc_t::OK;
}
std::string
delete_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-route-domain: " << m_hw_item.to_string();
return (s.str());
}
bool
dump_cmd::operator==(const dump_cmd& other) const
{
return (true);
}
rc_t
dump_cmd::issue(connection& con)
{
m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
VAPI_CALL(m_dump->execute());
wait();
return rc_t::OK;
}
std::string
dump_cmd::to_string() const
{
return ("gbp-route-domain-dump");
}
}; // namespace gbp_route_domain_cmds
}; // namespace VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 __VOM_GBP_ROUTE_DOMAIN_CMDS_H__
#define __VOM_GBP_ROUTE_DOMAIN_CMDS_H__
#include "vom/dump_cmd.hpp"
#include "vom/gbp_route_domain.hpp"
#include "vom/rpc_cmd.hpp"
#include <vapi/gbp.api.vapi.hpp>
namespace VOM {
namespace gbp_route_domain_cmds {
/**
* A command class that creates an Route-Domain
*/
class create_cmd
: public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_route_domain_add>
{
public:
/**
* Constructor
*/
create_cmd(HW::item<uint32_t>& item,
const handle_t ip4_uu_fwd,
const handle_t ip6_uu_fwd);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const create_cmd& i) const;
private:
const handle_t m_ip4_uu_fwd;
const handle_t m_ip6_uu_fwd;
};
/**
* A cmd class that Delete an Route-Domain
*/
class delete_cmd
: public rpc_cmd<HW::item<uint32_t>, vapi::Gbp_route_domain_del>
{
public:
/**
* Constructor
*/
delete_cmd(HW::item<uint32_t>& item);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const delete_cmd& i) const;
};
/**
* A cmd class that Dumps all the route domains
*/
class dump_cmd : public VOM::dump_cmd<vapi::Gbp_route_domain_dump>
{
public:
/**
* Constructor
*/
dump_cmd() = default;
dump_cmd(const dump_cmd& d) = default;
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const dump_cmd& i) const;
private:
/**
* HW reutrn code
*/
HW::item<bool> item;
};
}; // gbp_route_domain_cmds
}; // VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -25,31 +25,38 @@ gbp_subnet::type_t::type_t(int v, const std::string s)
{
}
const gbp_subnet::type_t gbp_subnet::type_t::INTERNAL(0, "internal");
const gbp_subnet::type_t gbp_subnet::type_t::EXTERNAL(1, "external");
const gbp_subnet::type_t gbp_subnet::type_t::STITCHED_INTERNAL(
0,
"stitched-internal");
const gbp_subnet::type_t gbp_subnet::type_t::STITCHED_EXTERNAL(
1,
"stitched-external");
const gbp_subnet::type_t gbp_subnet::type_t::TRANSPORT(1, "transport");
singular_db<gbp_subnet::key_t, gbp_subnet> gbp_subnet::m_db;
gbp_subnet::event_handler gbp_subnet::m_evh;
gbp_subnet::gbp_subnet(const route_domain& rd, const route::prefix_t& prefix)
gbp_subnet::gbp_subnet(const gbp_route_domain& rd,
const route::prefix_t& prefix,
const type_t& type)
: m_hw(false)
, m_rd(rd.singular())
, m_prefix(prefix)
, m_type(type_t::INTERNAL)
, m_type(type)
, m_recirc(nullptr)
, m_epg(nullptr)
{
}
gbp_subnet::gbp_subnet(const route_domain& rd,
gbp_subnet::gbp_subnet(const gbp_route_domain& rd,
const route::prefix_t& prefix,
const gbp_recirc& recirc,
const gbp_endpoint_group& epg)
: m_hw(false)
, m_rd(rd.singular())
, m_prefix(prefix)
, m_type(type_t::EXTERNAL)
, m_type(type_t::STITCHED_EXTERNAL)
, m_recirc(recirc.singular())
, m_epg(epg.singular())
{
@ -88,8 +95,7 @@ void
gbp_subnet::sweep()
{
if (m_hw) {
HW::enqueue(
new gbp_subnet_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix));
HW::enqueue(new gbp_subnet_cmds::delete_cmd(m_hw, m_rd->id(), m_prefix));
}
HW::write();
}
@ -99,7 +105,7 @@ gbp_subnet::replay()
{
if (m_hw) {
HW::enqueue(new gbp_subnet_cmds::create_cmd(
m_hw, m_rd->table_id(), m_prefix, (m_type == type_t::INTERNAL),
m_hw, m_rd->id(), m_prefix, m_type,
(m_recirc ? m_recirc->handle() : handle_t::INVALID),
(m_epg ? m_epg->id() : ~0)));
}
@ -126,7 +132,7 @@ gbp_subnet::update(const gbp_subnet& r)
{
if (rc_t::OK != m_hw.rc()) {
HW::enqueue(new gbp_subnet_cmds::create_cmd(
m_hw, m_rd->table_id(), m_prefix, (m_type == type_t::INTERNAL),
m_hw, m_rd->id(), m_prefix, m_type,
(m_recirc ? m_recirc->handle() : handle_t::INVALID),
(m_epg ? m_epg->id() : ~0)));
} else {
@ -136,7 +142,7 @@ gbp_subnet::update(const gbp_subnet& r)
m_type = r.m_type;
HW::enqueue(new gbp_subnet_cmds::create_cmd(
m_hw, m_rd->table_id(), m_prefix, (m_type == type_t::INTERNAL),
m_hw, m_rd->id(), m_prefix, m_type,
(m_recirc ? m_recirc->handle() : handle_t::INVALID),
(m_epg ? m_epg->id() : ~0)));
}
@ -192,15 +198,24 @@ gbp_subnet::event_handler::handle_populate(const client_db::key_t& key)
auto& payload = record.get_payload();
route::prefix_t pfx = from_api(payload.subnet.prefix);
std::shared_ptr<route_domain> rd =
route_domain::find(payload.subnet.table_id);
std::shared_ptr<gbp_route_domain> rd =
gbp_route_domain::find(payload.subnet.rd_id);
if (rd) {
if (payload.subnet.is_internal) {
gbp_subnet gs(*rd, pfx);
switch (payload.subnet.type) {
case GBP_API_SUBNET_TRANSPORT: {
gbp_subnet gs(*rd, pfx, type_t::TRANSPORT);
OM::commit(key, gs);
VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
} else {
break;
}
case GBP_API_SUBNET_STITCHED_INTERNAL: {
gbp_subnet gs(*rd, pfx, type_t::STITCHED_INTERNAL);
OM::commit(key, gs);
VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
break;
}
case GBP_API_SUBNET_STITCHED_EXTERNAL: {
std::shared_ptr<interface> itf =
interface::find(payload.subnet.sw_if_index);
std::shared_ptr<gbp_endpoint_group> epg =
@ -218,6 +233,7 @@ gbp_subnet::event_handler::handle_populate(const client_db::key_t& key)
}
}
}
}
}
dependency_t
@ -231,6 +247,15 @@ gbp_subnet::event_handler::show(std::ostream& os)
{
db_dump(m_db, os);
}
std::ostream&
operator<<(std::ostream& os, const gbp_subnet::key_t& key)
{
os << "[" << key.first << ", " << key.second << "]";
return os;
}
} // namespace VOM
/*

View File

@ -16,9 +16,11 @@
#ifndef __VOM_GBP_SUBNET_H__
#define __VOM_GBP_SUBNET_H__
#include <ostream>
#include "vom/gbp_endpoint_group.hpp"
#include "vom/gbp_recirc.hpp"
#include "vom/route.hpp"
#include "vom/gbp_route_domain.hpp"
#include "vom/singular_db.hpp"
namespace VOM {
@ -31,17 +33,41 @@ public:
/**
* The key for a GBP subnet; table and prefix
*/
typedef std::pair<route_domain::key_t, route::prefix_t> key_t;
typedef std::pair<gbp_route_domain::key_t, route::prefix_t> key_t;
struct type_t : public enum_base<type_t>
{
/**
* Internal subnet is reachable through the source EPG's
* uplink interface.
*/
const static type_t STITCHED_INTERNAL;
/**
* External subnet requires NAT translation before egress.
*/
const static type_t STITCHED_EXTERNAL;
/**
* A transport subnet, sent via the RD's UU-fwd interface
*/
const static type_t TRANSPORT;
private:
type_t(int v, const std::string s);
};
/**
* Construct an internal GBP subnet
*/
gbp_subnet(const route_domain& rd, const route::prefix_t& prefix);
gbp_subnet(const gbp_route_domain& rd,
const route::prefix_t& prefix,
const type_t& type);
/**
* Construct an external GBP subnet
*/
gbp_subnet(const route_domain& rd,
gbp_subnet(const gbp_route_domain& rd,
const route::prefix_t& prefix,
const gbp_recirc& recirc,
const gbp_endpoint_group& epg);
@ -92,23 +118,6 @@ public:
std::string to_string() const;
private:
struct type_t : public enum_base<type_t>
{
/**
* Internal subnet is reachable through the source EPG's
* uplink interface.
*/
const static type_t INTERNAL;
/**
* External subnet requires NAT translation before egress.
*/
const static type_t EXTERNAL;
private:
type_t(int v, const std::string s);
};
/**
* Class definition for listeners to OM events
*/
@ -177,7 +186,7 @@ private:
/**
* the route domain the prefix is in
*/
const std::shared_ptr<route_domain> m_rd;
const std::shared_ptr<gbp_route_domain> m_rd;
/**
* prefix to match
@ -205,6 +214,8 @@ private:
static singular_db<key_t, gbp_subnet> m_db;
};
std::ostream& operator<<(std::ostream& os, const gbp_subnet::key_t& key);
}; // namespace
/*

View File

@ -22,13 +22,13 @@ namespace gbp_subnet_cmds {
create_cmd::create_cmd(HW::item<bool>& item,
route::table_id_t rd,
const route::prefix_t& prefix,
bool internal,
const gbp_subnet::type_t& type,
const handle_t& itf,
epg_id_t epg_id)
: rpc_cmd(item)
, m_rd(rd)
, m_prefix(prefix)
, m_internal(internal)
, m_type(type)
, m_itf(itf)
, m_epg_id(epg_id)
{
@ -38,8 +38,21 @@ bool
create_cmd::operator==(const create_cmd& other) const
{
return ((m_itf == other.m_itf) && (m_rd == other.m_rd) &&
(m_prefix == other.m_prefix) && (m_itf == other.m_itf) &&
(m_epg_id == other.m_epg_id));
(m_prefix == other.m_prefix) && (m_type == other.m_type) &&
(m_itf == other.m_itf) && (m_epg_id == other.m_epg_id));
}
static vapi_enum_gbp_subnet_type
gbp_subnet_type_to_api(const gbp_subnet::type_t& type)
{
if (gbp_subnet::type_t::STITCHED_INTERNAL == type)
return (GBP_API_SUBNET_STITCHED_INTERNAL);
if (gbp_subnet::type_t::STITCHED_EXTERNAL == type)
return (GBP_API_SUBNET_STITCHED_EXTERNAL);
if (gbp_subnet::type_t::TRANSPORT == type)
return (GBP_API_SUBNET_TRANSPORT);
return (GBP_API_SUBNET_STITCHED_INTERNAL);
}
rc_t
@ -49,8 +62,8 @@ create_cmd::issue(connection& con)
auto& payload = req.get_request().get_payload();
payload.is_add = 1;
payload.subnet.is_internal = m_internal;
payload.subnet.table_id = m_rd;
payload.subnet.type = gbp_subnet_type_to_api(m_type);
payload.subnet.rd_id = m_rd;
payload.subnet.sw_if_index = m_itf.value();
payload.subnet.epg_id = m_epg_id;
payload.subnet.prefix = to_api(m_prefix);
@ -64,9 +77,9 @@ std::string
create_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-subnet-create: " << m_hw_item.to_string()
<< "internal:" << m_internal << ", " << m_rd << ":" << m_prefix.to_string()
<< " itf:" << m_itf << " epg-id:" << m_epg_id;
s << "gbp-subnet-create: " << m_hw_item.to_string() << "type:" << m_type
<< ", " << m_rd << ":" << m_prefix.to_string() << " itf:" << m_itf
<< " epg-id:" << m_epg_id;
return (s.str());
}
@ -93,13 +106,9 @@ delete_cmd::issue(connection& con)
auto& payload = req.get_request().get_payload();
payload.is_add = 0;
payload.subnet.table_id = m_rd;
payload.subnet.rd_id = m_rd;
payload.subnet.prefix = to_api(m_prefix);
payload.subnet.is_internal = 0;
payload.subnet.sw_if_index = ~0;
payload.subnet.epg_id = ~0;
VAPI_CALL(req.execute());
return (wait());

View File

@ -36,7 +36,7 @@ public:
create_cmd(HW::item<bool>& item,
route::table_id_t rd,
const route::prefix_t& prefix,
bool internal,
const gbp_subnet::type_t& type,
const handle_t& itf,
epg_id_t epg_id);
@ -58,7 +58,7 @@ public:
private:
const route::table_id_t m_rd;
const route::prefix_t m_prefix;
const bool m_internal;
const gbp_subnet::type_t& m_type;
const handle_t m_itf;
const epg_id_t m_epg_id;
};

View File

@ -0,0 +1,231 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_vxlan.hpp"
#include "vom/gbp_vxlan_cmds.hpp"
#include "vom/interface.hpp"
#include "vom/singular_db_funcs.hpp"
namespace VOM {
const std::string GBP_VXLAN_NAME = "gbp-vxlan";
/**
* A DB of al the interfaces, key on the name
*/
singular_db<gbp_vxlan::key_t, gbp_vxlan> gbp_vxlan::m_db;
gbp_vxlan::event_handler gbp_vxlan::m_evh;
gbp_vxlan::gbp_vxlan(uint32_t vni, const gbp_route_domain& grd)
: interface(mk_name(vni),
interface::type_t::UNKNOWN,
interface::admin_state_t::UP)
, m_vni(vni)
, m_gbd()
, m_grd(grd.singular())
{
}
gbp_vxlan::gbp_vxlan(uint32_t vni, const gbp_bridge_domain& gbd)
: interface(mk_name(vni),
interface::type_t::UNKNOWN,
interface::admin_state_t::UP)
, m_vni(vni)
, m_gbd(gbd.singular())
, m_grd()
{
}
gbp_vxlan::gbp_vxlan(const gbp_vxlan& vt)
: interface(vt)
, m_vni(vt.m_vni)
, m_gbd(vt.m_gbd)
, m_grd(vt.m_grd)
{
}
std::string
gbp_vxlan::mk_name(uint32_t vni)
{
std::ostringstream s;
s << GBP_VXLAN_NAME << "-" << vni;
return (s.str());
}
const gbp_vxlan::key_t
gbp_vxlan::key() const
{
return (m_vni);
}
bool
gbp_vxlan::operator==(const gbp_vxlan& vt) const
{
return (m_vni == vt.m_vni);
}
void
gbp_vxlan::sweep()
{
if (rc_t::OK == m_hdl) {
HW::enqueue(new gbp_vxlan_cmds::delete_cmd(m_hdl, m_vni));
}
HW::write();
}
void
gbp_vxlan::replay()
{
if (rc_t::OK == m_hdl) {
if (m_grd)
HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, false,
m_grd->id()));
else if (m_gbd)
HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, true,
m_gbd->id()));
}
}
gbp_vxlan::~gbp_vxlan()
{
sweep();
m_db.release(key(), this);
}
std::string
gbp_vxlan::to_string() const
{
std::ostringstream s;
s << "gbp-vxlan:[" << m_vni << "]";
return (s.str());
}
std::shared_ptr<gbp_vxlan>
gbp_vxlan::find(const key_t key)
{
return (m_db.find(key));
}
void
gbp_vxlan::update(const gbp_vxlan& desired)
{
/*
* the desired state is always that the interface should be created
*/
if (rc_t::OK != m_hdl) {
if (m_grd)
HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, false,
m_grd->id()));
else if (m_gbd)
HW::enqueue(new gbp_vxlan_cmds::create_cmd(m_hdl, name(), m_vni, true,
m_gbd->id()));
}
}
std::shared_ptr<gbp_vxlan>
gbp_vxlan::find_or_add(const gbp_vxlan& temp)
{
return (m_db.find_or_add(temp.key(), temp));
}
std::shared_ptr<gbp_vxlan>
gbp_vxlan::singular() const
{
return find_or_add(*this);
}
std::shared_ptr<interface>
gbp_vxlan::singular_i() const
{
return find_or_add(*this);
}
void
gbp_vxlan::dump(std::ostream& os)
{
db_dump(m_db, os);
}
void
gbp_vxlan::event_handler::handle_populate(const client_db::key_t& key)
{
/*
* dump VPP Bridge domains
*/
std::shared_ptr<gbp_vxlan_cmds::dump_cmd> cmd =
std::make_shared<gbp_vxlan_cmds::dump_cmd>();
HW::enqueue(cmd);
HW::write();
for (auto& record : *cmd) {
auto& payload = record.get_payload();
if (GBP_VXLAN_TUNNEL_MODE_L3 == payload.tunnel.mode) {
auto rd = gbp_route_domain::find(payload.tunnel.bd_rd_id);
if (rd) {
gbp_vxlan vt(payload.tunnel.vni, *rd);
OM::commit(key, vt);
VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
}
} else {
auto bd = gbp_bridge_domain::find(payload.tunnel.bd_rd_id);
if (bd) {
gbp_vxlan vt(payload.tunnel.vni, *bd);
OM::commit(key, vt);
VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
}
}
}
}
gbp_vxlan::event_handler::event_handler()
{
OM::register_listener(this);
inspect::register_handler({ "gvt", "gbp-vxlan-tunnel" }, "GBP VXLAN Tunnels",
this);
}
void
gbp_vxlan::event_handler::handle_replay()
{
m_db.replay();
}
dependency_t
gbp_vxlan::event_handler::order() const
{
return (dependency_t::BINDING);
}
void
gbp_vxlan::event_handler::show(std::ostream& os)
{
db_dump(m_db, os);
}
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 __VOM_GBP_VXLAN_H__
#define __VOM_GBP_VXLAN_H__
#include "vom/gbp_bridge_domain.hpp"
#include "vom/gbp_route_domain.hpp"
#include "vom/hw.hpp"
#include "vom/inspect.hpp"
#include "vom/interface.hpp"
#include "vom/singular_db.hpp"
namespace VOM {
/**
* A representation of a GBP_VXLAN Tunnel in VPP
*/
class gbp_vxlan : public interface
{
public:
/**
* The VNI is the key
*/
typedef uint32_t key_t;
/**
* Construct a new object matching the desried state
*/
gbp_vxlan(uint32_t vni, const gbp_bridge_domain& gbd);
gbp_vxlan(uint32_t vni, const gbp_route_domain& grd);
/*
* Destructor
*/
~gbp_vxlan();
/**
* Copy constructor
*/
gbp_vxlan(const gbp_vxlan& o);
bool operator==(const gbp_vxlan& vt) const;
/**
* Return the matching 'singular instance'
*/
std::shared_ptr<gbp_vxlan> singular() const;
/**
* Return the object's key
*/
const key_t key() const;
/**
* Debug rpint function
*/
virtual std::string to_string() const;
/**
* Return VPP's handle to this object
*/
const handle_t& handle() const;
/**
* Dump all L3Configs into the stream provided
*/
static void dump(std::ostream& os);
/**
* Find the GBP_VXLAN tunnel in the OM
*/
static std::shared_ptr<gbp_vxlan> find(const key_t k);
private:
/**
* Class definition for listeners to OM events
*/
class event_handler : public OM::listener, public inspect::command_handler
{
public:
event_handler();
virtual ~event_handler() = default;
/**
* Handle a populate event
*/
void handle_populate(const client_db::key_t& key);
/**
* Handle a replay event
*/
void handle_replay();
/**
* Show the object in the Singular DB
*/
void show(std::ostream& os);
/**
* Get the sortable Id of the listener
*/
dependency_t order() const;
};
/**
* Event handle to register with OM
*/
static event_handler m_evh;
/**
* Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
*/
void update(const gbp_vxlan& obj);
/**
* Return the matching 'instance' of the sub-interface
* over-ride from the base class
*/
std::shared_ptr<interface> singular_i() const;
/**
* Find the GBP_VXLAN tunnel in the OM
*/
static std::shared_ptr<gbp_vxlan> find_or_add(const gbp_vxlan& temp);
/*
* It's the VPPHW class that updates the objects in HW
*/
friend class OM;
/**
* It's the singular_db class that calls replay()
*/
friend class singular_db<key_t, gbp_vxlan>;
/**
* Sweep/reap the object if still stale
*/
void sweep(void);
/**
* replay the object to create it in hardware
*/
void replay(void);
/**
* Tunnel VNI/key
*/
uint32_t m_vni;
std::shared_ptr<gbp_bridge_domain> m_gbd;
std::shared_ptr<gbp_route_domain> m_grd;
/**
* A map of all VLAN tunnela against thier key
*/
static singular_db<key_t, gbp_vxlan> m_db;
/**
* Construct a unique name for the tunnel
*/
static std::string mk_name(uint32_t vni);
};
}; // namespace VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_vxlan_cmds.hpp"
#include <vapi/tap.api.vapi.hpp>
namespace VOM {
namespace gbp_vxlan_cmds {
create_cmd::create_cmd(HW::item<handle_t>& item,
const std::string& name,
uint32_t vni,
bool is_l2,
uint32_t bd_rd)
: interface::create_cmd<vapi::Gbp_vxlan_tunnel_add>(item, name)
, m_vni(vni)
, m_is_l2(is_l2)
, m_bd_rd(bd_rd)
{
}
rc_t
create_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.tunnel.vni = m_vni;
payload.tunnel.bd_rd_id = m_bd_rd;
if (m_is_l2)
payload.tunnel.mode = GBP_VXLAN_TUNNEL_MODE_L2;
else
payload.tunnel.mode = GBP_VXLAN_TUNNEL_MODE_L3;
VAPI_CALL(req.execute());
wait();
if (m_hw_item.rc() == rc_t::OK) {
insert_interface();
}
return (m_hw_item.rc());
}
std::string
create_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-vxlan-create: " << m_hw_item.to_string() << " vni:" << m_vni
<< " bd/rd:" << m_bd_rd;
return (s.str());
}
delete_cmd::delete_cmd(HW::item<handle_t>& item, uint32_t vni)
: interface::delete_cmd<vapi::Gbp_vxlan_tunnel_del>(item)
, m_vni(vni)
{
}
rc_t
delete_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.vni = m_vni;
VAPI_CALL(req.execute());
wait();
m_hw_item.set(rc_t::NOOP);
remove_interface();
return rc_t::OK;
}
std::string
delete_cmd::to_string() const
{
std::ostringstream s;
s << "gbp-vxlan-delete: " << m_hw_item.to_string() << " vni:" << m_vni;
return (s.str());
}
dump_cmd::dump_cmd()
{
}
bool
dump_cmd::operator==(const dump_cmd& other) const
{
return (true);
}
rc_t
dump_cmd::issue(connection& con)
{
m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
VAPI_CALL(m_dump->execute());
wait();
return rc_t::OK;
}
std::string
dump_cmd::to_string() const
{
return ("gbp-vxlan-dump");
}
} // namespace gbp_vxlan_cmds
} // namespace VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 __VOM_GBP_VXLAN_CMDS_H__
#define __VOM_GBP_VXLAN_CMDS_H__
#include "vom/dump_cmd.hpp"
#include "vom/gbp_vxlan.hpp"
#include "vom/interface.hpp"
#include <vapi/gbp.api.vapi.hpp>
namespace VOM {
namespace gbp_vxlan_cmds {
/**
* A command class that creates an Bridge-Domain
*/
class create_cmd : public interface::create_cmd<vapi::Gbp_vxlan_tunnel_add>
{
public:
/**
* Constructor
*/
create_cmd(HW::item<handle_t>& item,
const std::string& name,
uint32_t vni,
bool is_l2,
uint32_t bd_rd);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const create_cmd& i) const;
private:
uint32_t m_vni;
bool m_is_l2;
uint32_t m_bd_rd;
};
/**
* A cmd class that Delete an Bridge-Domain
*/
class delete_cmd : public interface::delete_cmd<vapi::Gbp_vxlan_tunnel_del>
{
public:
/**
* Constructor
*/
delete_cmd(HW::item<handle_t>& item, uint32_t vni);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const delete_cmd& i) const;
private:
uint32_t m_vni;
};
/**
* A cmd class that Dumps all the bridge domains
*/
class dump_cmd : public VOM::dump_cmd<vapi::Gbp_vxlan_tunnel_dump>
{
public:
/**
* Constructor
*/
dump_cmd();
dump_cmd(const dump_cmd& d);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const dump_cmd& i) const;
private:
/**
* HW reutrn code
*/
HW::item<bool> item;
};
}; // gbp_vxlan_cmds
}; // VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* 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 "vom/gbp_vxlan_tunnel.hpp"
#include "vom/gbp_vxlan_tunnel_cmds.hpp"
#include "vom/interface.hpp"
#include "vom/singular_db_funcs.hpp"
namespace VOM {
/**
* A DB of al the interfaces, key on the name
*/
singular_db<uint32_t, gbp_vxlan_tunnel> gbp_vxlan_tunnel::m_db;
gbp_vxlan_tunnel::event_handler gbp_vxlan_tunnel::m_evh;
/**
* Construct a new object matching the desried state
*/
gbp_vxlan_tunnel::gbp_vxlan_tunnel(const vxlan_tunnel& vt)
: interface(vt)
, m_vni(vt.m_vni)
{
}
gbp_vxlan_tunnel::gbp_vxlan_tunnel(uint32_t vni)
: interface(mk_name(vni),
interface::type_t::UNKNOWN,
interface::admin_state_t::UP)
, m_vni(vt.m_vni)
{
}
const gbp_vxlan_tunnel::key_t
gbp_vxlan_tunnel::key() const
{
return (m_vni);
}
bool
gbp_vxlan_tunnel::operator==(const gbp_vxlan_tunnel& vt) const
{
return (m_vni == vt.m_vni);
}
void
gbp_vxlan_tunnel::sweep()
{
if (rc_t::OK == m_id.rc()) {
HW::enqueue(new gbp_vxlan_tunnel_cmds::delete_cmd(m_vni));
}
HW::write();
}
void
gbp_vxlan_tunnel::replay()
{
if (rc_t::OK == m_hdl) {
HW::enqueue(new gbp_vxlan_tunnel_cmds::create_cmd(m_vni));
}
}
gbp_vxlan_tunnel::~gbp_vxlan_tunnel()
{
sweep();
m_db.release(m_id.data(), this);
}
std::string
gbp_vxlan_tunnel::to_string() const
{
std::ostringstream s;
s << "gbp-vxlan:[" << m_vni << "]";
return (s.str());
}
std::shared_ptr<gbp_vxlan_tunnel>
gbp_vxlan_tunnel::find(const key_t& key)
{
return (m_db.find(key));
}
void
gbp_vxlan_tunnel::update(const gbp_vxlan_tunnel& desired)
{
/*
* the desired state is always that the interface should be created
*/
if (rc_t::OK != m_hdl) {
HW::enqueue(new gbp_vxlan_tunnel_cmds::create_cmd(m_vni));
}
}
std::shared_ptr<gbp_vxlan_tunnel>
gbp_vxlan_tunnel::find_or_add(const gbp_vxlan_tunnel& temp)
{
return (m_db.find_or_add(temp.m_id.data(), temp));
}
std::shared_ptr<gbp_vxlan_tunnel>
gbp_vxlan_tunnel::singular() const
{
return find_or_add(*this);
}
void
gbp_vxlan_tunnel::dump(std::ostream& os)
{
db_dump(m_db, os);
}
void
gbp_vxlan_tunnel::event_handler::handle_populate(const client_db::key_t& key)
{
/*
* dump VPP Bridge domains
*/
std::shared_ptr<gbp_vxlan_tunnel_cmds::dump_cmd> cmd =
std::make_shared<gbp_vxlan_tunnel_cmds::dump_cmd>();
HW::enqueue(cmd);
HW::write();
for (auto& record : *cmd) {
auto& payload = record.get_payload();
gbp_vxlan_tunnel vt(payload.tunnel.vni, );
OM::commit(key, vt);
VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
}
else
{
gbp_vxlan_tunnel vt(payload.vt.vt_id);
OM::commit(key, vt);
VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
}
}
}
gbp_vxlan_tunnel::event_handler::event_handler()
{
OM::register_listener(this);
inspect::register_handler({ "gvt", "gbp-vxlan-tunnel" }, "GBP VXLAN Tunnels",
this);
}
void
gbp_vxlan_tunnel::event_handler::handle_replay()
{
m_db.replay();
}
dependency_t
gbp_vxlan_tunnel::event_handler::order() const
{
return (dependency_t::INTERFACE);
}
void
gbp_vxlan_tunnel::event_handler::show(std::ostream& os)
{
db_dump(m_db, os);
}
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -38,6 +38,10 @@ interface_factory::new_interface(const vapi_payload_sw_interface_details& vd)
l2_address_t l2_address(vd.l2_address, vd.l2_address_length);
std::string tag = "";
if (interface::type_t::UNKNOWN == type) {
return sp;
}
sp = interface::find(hdl);
if (sp) {
sp->set(state);

View File

@ -13,17 +13,23 @@
add_vpp_plugin(gbp
SOURCES
gbp_subnet.c
gbp_api.c
gbp_bridge_domain.c
gbp_classify.c
gbp_contract.c
gbp_endpoint.c
gbp_endpoint_group.c
gbp_classify.c
gbp_recirc.c
gbp_policy.c
gbp_policy_dpo.c
gbp_fwd.c
gbp_fwd_dpo.c
gbp_api.c
gbp_itf.c
gbp_learn.c
gbp_policy.c
gbp_policy_dpo.c
gbp_recirc.c
gbp_route_domain.c
gbp_scanner.c
gbp_subnet.c
gbp_vxlan.c
API_FILES
gbp.api

View File

@ -19,16 +19,96 @@ option version = "2.0.0";
import "vnet/ip/ip_types.api";
import "vnet/ethernet/ethernet_types.api";
typedef gbp_bridge_domain
{
u32 bd_id;
u32 bvi_sw_if_index;
u32 uu_fwd_sw_if_index;
};
autoreply define gbp_bridge_domain_add
{
u32 client_index;
u32 context;
vl_api_gbp_bridge_domain_t bd;
};
autoreply define gbp_bridge_domain_del
{
u32 client_index;
u32 context;
u32 bd_id;
};
autoreply define gbp_bridge_domain_dump
{
u32 client_index;
u32 context;
};
define gbp_bridge_domain_details
{
u32 context;
vl_api_gbp_bridge_domain_t bd;
};
typedef gbp_route_domain
{
u32 rd_id;
u32 ip4_table_id;
u32 ip6_table_id;
u32 ip4_uu_sw_if_index;
u32 ip6_uu_sw_if_index;
};
autoreply define gbp_route_domain_add
{
u32 client_index;
u32 context;
vl_api_gbp_route_domain_t rd;
};
autoreply define gbp_route_domain_del
{
u32 client_index;
u32 context;
u32 rd_id;
};
autoreply define gbp_route_domain_dump
{
u32 client_index;
u32 context;
};
define gbp_route_domain_details
{
u32 context;
vl_api_gbp_route_domain_t rd;
};
/** \brief Endpoint
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
*/
enum gbp_endpoint_flags
{
NONE = 0,
BOUNCE = 0x1,
REMOTE = 0x2,
LEARNT = 0x4,
/* hey Ole WTF */
REMOTE_LEARNT = 0x6,
};
typedef gbp_endpoint_tun
{
vl_api_address_t src;
vl_api_address_t dst;
};
typedef gbp_endpoint
{
u32 sw_if_index;
u16 epg_id;
vl_api_gbp_endpoint_flags_t flags;
vl_api_mac_address_t mac;
vl_api_gbp_endpoint_tun_t tun;
u8 n_ips;
vl_api_address_t ips[n_ips];
};
@ -63,6 +143,8 @@ define gbp_endpoint_dump
define gbp_endpoint_details
{
u32 context;
f64 age;
u32 handle;
vl_api_gbp_endpoint_t endpoint;
};
@ -70,18 +152,22 @@ typeonly define gbp_endpoint_group
{
u16 epg_id;
u32 bd_id;
u32 ip4_table_id;
u32 ip6_table_id;
u32 rd_id;
u32 uplink_sw_if_index;
};
autoreply define gbp_endpoint_group_add_del
autoreply define gbp_endpoint_group_add
{
u32 client_index;
u32 context;
u8 is_add;
vl_api_gbp_endpoint_group_t epg;
};
autoreply define gbp_endpoint_group_del
{
u32 client_index;
u32 context;
u16 epg_id;
};
define gbp_endpoint_group_dump
{
@ -122,12 +208,19 @@ define gbp_recirc_details
vl_api_gbp_recirc_t recirc;
};
enum gbp_subnet_type
{
GBP_API_SUBNET_TRANSPORT,
GBP_API_SUBNET_STITCHED_INTERNAL,
GBP_API_SUBNET_STITCHED_EXTERNAL,
};
typeonly define gbp_subnet
{
u32 table_id;
u32 rd_id;
u32 sw_if_index;
u16 epg_id;
u8 is_internal;
vl_api_gbp_subnet_type_t type;
vl_api_prefix_t prefix;
};
@ -178,6 +271,70 @@ define gbp_contract_details
vl_api_gbp_contract_t contract;
};
/**
* @brief Set the time throeshold after which an endpoint is
considered inative and is aged/reaped by the scanner
* @param threshold In seconds
*/
autoreply define gbp_endpoint_learn_set_inactive_threshold
{
u32 client_index;
u32 context;
u32 threshold;
};
/**
* @brief Configure a 'base' tunnel from which learned tunnels
* are permitted to derive
* A base tunnel consists only of the VNI, any src,dst IP
* pair is thus allowed.
*/
enum gbp_vxlan_tunnel_mode
{
GBP_VXLAN_TUNNEL_MODE_L2,
GBP_VXLAN_TUNNEL_MODE_L3,
};
typedef gbp_vxlan_tunnel
{
u32 vni;
vl_api_gbp_vxlan_tunnel_mode_t mode;
u32 bd_rd_id;
};
define gbp_vxlan_tunnel_add
{
u32 client_index;
u32 context;
vl_api_gbp_vxlan_tunnel_t tunnel;
};
define gbp_vxlan_tunnel_add_reply
{
u32 context;
i32 retval;
u32 sw_if_index;
};
autoreply define gbp_vxlan_tunnel_del
{
u32 client_index;
u32 context;
u32 vni;
};
define gbp_vxlan_tunnel_dump
{
u32 client_index;
u32 context;
};
define gbp_vxlan_tunnel_details
{
u32 context;
vl_api_gbp_vxlan_tunnel_t tunnel;
};
/*
* Local Variables:
* eval: (c-set-style "gnu")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2018 Cisco and/or its affiliates.
* 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 __GBP_BRIDGE_DOMAIN_H__
#define __GBP_BRIDGE_DOMAIN_H__
#include <plugins/gbp/gbp_types.h>
#include <vnet/fib/fib_types.h>
/**
* A bridge Domain Representation.
* This is a standard bridge-domain plus all the attributes it must
* have to supprt the GBP model.
*/
typedef struct gpb_bridge_domain_t_
{
/**
* Bridge-domain ID
*/
u32 gb_bd_id;
u32 gb_bd_index;
/**
* The BD's BVI interface (obligatory)
*/
u32 gb_bvi_sw_if_index;
/**
* The BD's MAC spine-proxy interface (optional)
*/
u32 gb_uu_fwd_sw_if_index;
/**
* The BD's VNI interface on which packets from unkown endpoints
* arrive
*/
u32 gb_vni_sw_if_index;
/**
* locks/references to the BD so it does not get deleted (from the API)
* whilst it is still being used
*/
u32 gb_locks;
} gbp_bridge_domain_t;
extern int gbp_bridge_domain_add_and_lock (u32 bd_id,
u32 bvi_sw_if_index,
u32 uu_fwd_sw_if_index);
extern void gbp_bridge_domain_unlock (index_t gbi);
extern index_t gbp_bridge_domain_find_and_lock (u32 bd_id);
extern int gbp_bridge_domain_delete (u32 bd_id);
extern gbp_bridge_domain_t *gbp_bridge_domain_get (index_t i);
typedef int (*gbp_bridge_domain_cb_t) (gbp_bridge_domain_t * gb, void *ctx);
extern void gbp_bridge_domain_walk (gbp_bridge_domain_cb_t bgpe, void *ctx);
extern u8 *format_gbp_bridge_domain (u8 * s, va_list * args);
#endif
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -18,6 +18,8 @@
#include <plugins/gbp/gbp.h>
#include <vnet/l2/l2_input.h>
#include <vnet/l2/feat_bitmap.h>
#include <vnet/fib/fib_table.h>
#include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
typedef enum gbp_src_classify_type_t_
{
@ -56,7 +58,7 @@ always_inline uword
gbp_classify_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame,
gbp_src_classify_type_t type, u8 is_l3)
gbp_src_classify_type_t type, dpo_proto_t dproto)
{
gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
u32 n_left_from, *from, *to_next;
@ -75,7 +77,7 @@ gbp_classify_inline (vlib_main_t * vm,
while (n_left_from > 0 && n_left_to_next > 0)
{
u32 next0, bi0, src_epg, sw_if_index0;
const gbp_endpoint_t *gep0;
const gbp_endpoint_t *ge0;
vlib_buffer_t *b0;
bi0 = from[0];
@ -88,6 +90,7 @@ gbp_classify_inline (vlib_main_t * vm,
b0 = vlib_get_buffer (vm, bi0);
sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_NONE;
if (GBP_SRC_CLASSIFY_NULL == type)
{
@ -98,10 +101,46 @@ gbp_classify_inline (vlib_main_t * vm,
}
else
{
gep0 = gbp_endpoint_get_itf (sw_if_index0);
src_epg = gep0->ge_epg_id;
if (is_l3)
if (DPO_PROTO_ETHERNET == dproto)
{
const ethernet_header_t *h0;
h0 = vlib_buffer_get_current (b0);
next0 =
vnet_l2_feature_next (b0, gscm->l2_input_feat_next[type],
L2INPUT_FEAT_GBP_SRC_CLASSIFY);
ge0 = gbp_endpoint_find_mac (h0->src_address,
vnet_buffer (b0)->l2.bd_index);
}
else if (DPO_PROTO_IP4 == dproto)
{
const ip4_header_t *h0;
h0 = vlib_buffer_get_current (b0);
ge0 = gbp_endpoint_find_ip4
(&h0->src_address,
fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
sw_if_index0));
/*
* Go straight to looukp, do not pass go, do not collect $200
*/
next0 = 0;
}
else if (DPO_PROTO_IP6 == dproto)
{
const ip6_header_t *h0;
h0 = vlib_buffer_get_current (b0);
ge0 = gbp_endpoint_find_ip6
(&h0->src_address,
fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6,
sw_if_index0));
/*
* Go straight to lookup, do not pass go, do not collect $200
*/
@ -109,10 +148,15 @@ gbp_classify_inline (vlib_main_t * vm,
}
else
{
next0 =
vnet_l2_feature_next (b0, gscm->l2_input_feat_next[type],
L2INPUT_FEAT_GBP_SRC_CLASSIFY);
ge0 = NULL;
next0 = 0;
ASSERT (0);
}
if (PREDICT_TRUE (NULL != ge0))
src_epg = ge0->ge_epg_id;
else
src_epg = EPG_INVALID;
}
vnet_buffer2 (b0)->gbp.src_epg = src_epg;
@ -139,28 +183,32 @@ static uword
gbp_src_classify (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
return (gbp_classify_inline (vm, node, frame, GBP_SRC_CLASSIFY_PORT, 0));
return (gbp_classify_inline (vm, node, frame,
GBP_SRC_CLASSIFY_PORT, DPO_PROTO_ETHERNET));
}
static uword
gbp_null_classify (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
return (gbp_classify_inline (vm, node, frame, GBP_SRC_CLASSIFY_NULL, 0));
return (gbp_classify_inline (vm, node, frame,
GBP_SRC_CLASSIFY_NULL, DPO_PROTO_ETHERNET));
}
static uword
gbp_ip4_src_classify (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
return (gbp_classify_inline (vm, node, frame, 0, 1));
return (gbp_classify_inline (vm, node, frame,
GBP_SRC_CLASSIFY_PORT, DPO_PROTO_IP4));
}
static uword
gbp_ip6_src_classify (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
return (gbp_classify_inline (vm, node, frame, 0, 1));
return (gbp_classify_inline (vm, node, frame,
GBP_SRC_CLASSIFY_PORT, DPO_PROTO_IP6));
}

Some files were not shown because too many files have changed in this diff Show More