aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extras/vom/vom/CMakeLists.txt3
-rw-r--r--extras/vom/vom/gbp_ext_itf.cpp193
-rw-r--r--extras/vom/vom/gbp_ext_itf.hpp186
-rw-r--r--extras/vom/vom/gbp_ext_itf_cmds.cpp135
-rw-r--r--extras/vom/vom/gbp_ext_itf_cmds.hpp134
-rw-r--r--extras/vom/vom/gbp_subnet.cpp21
-rw-r--r--extras/vom/vom/gbp_subnet.hpp14
-rw-r--r--src/plugins/gbp/CMakeLists.txt1
-rw-r--r--src/plugins/gbp/gbp.api39
-rw-r--r--src/plugins/gbp/gbp_api.c95
-rw-r--r--src/plugins/gbp/gbp_bridge_domain.c10
-rw-r--r--src/plugins/gbp/gbp_bridge_domain.h1
-rw-r--r--src/plugins/gbp/gbp_classify.c283
-rw-r--r--src/plugins/gbp/gbp_endpoint.c36
-rw-r--r--src/plugins/gbp/gbp_endpoint.h9
-rw-r--r--src/plugins/gbp/gbp_ext_itf.c203
-rw-r--r--src/plugins/gbp/gbp_ext_itf.h81
-rw-r--r--src/plugins/gbp/gbp_itf.c6
-rw-r--r--src/plugins/gbp/gbp_policy_dpo.c213
-rw-r--r--src/plugins/gbp/gbp_policy_dpo.h18
-rw-r--r--src/plugins/gbp/gbp_recirc.c28
-rw-r--r--src/plugins/gbp/gbp_recirc.h9
-rw-r--r--src/plugins/gbp/gbp_route_domain.c10
-rw-r--r--src/plugins/gbp/gbp_route_domain.h1
-rw-r--r--src/plugins/gbp/gbp_scanner.c43
-rw-r--r--src/plugins/gbp/gbp_scanner.h3
-rw-r--r--src/plugins/gbp/gbp_subnet.c97
-rw-r--r--src/plugins/gbp/gbp_subnet.h1
-rw-r--r--src/vnet/l2/l2_input.h1
-rw-r--r--test/test_gbp.py359
-rw-r--r--test/vpp_papi_provider.py13
31 files changed, 1955 insertions, 291 deletions
diff --git a/extras/vom/vom/CMakeLists.txt b/extras/vom/vom/CMakeLists.txt
index 7413df8d834..f68a7409362 100644
--- a/extras/vom/vom/CMakeLists.txt
+++ b/extras/vom/vom/CMakeLists.txt
@@ -76,6 +76,8 @@ if(GBP_FILE)
gbp_endpoint.cpp
gbp_endpoint_group_cmds.cpp
gbp_endpoint_group.cpp
+ gbp_ext_itf.cpp
+ gbp_ext_itf_cmds.cpp
gbp_recirc_cmds.cpp
gbp_recirc.cpp
gbp_route_domain_cmds.cpp
@@ -196,6 +198,7 @@ if(GBP_FILE)
gbp_bridge_domain.hpp
gbp_endpoint.hpp
gbp_endpoint_group.hpp
+ gbp_ext_itf.hpp
gbp_recirc.hpp
gbp_route_domain.hpp
gbp_rule.hpp
diff --git a/extras/vom/vom/gbp_ext_itf.cpp b/extras/vom/vom/gbp_ext_itf.cpp
new file mode 100644
index 00000000000..4b7302ddaaa
--- /dev/null
+++ b/extras/vom/vom/gbp_ext_itf.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_ext_itf.hpp"
+#include "vom/gbp_ext_itf_cmds.hpp"
+#include "vom/singular_db_funcs.hpp"
+
+namespace VOM {
+
+singular_db<gbp_ext_itf::key_t, gbp_ext_itf> gbp_ext_itf::m_db;
+
+gbp_ext_itf::event_handler gbp_ext_itf::m_evh;
+
+gbp_ext_itf::gbp_ext_itf(const interface& itf,
+ const gbp_bridge_domain& gbd,
+ const gbp_route_domain& grd)
+ : m_hw(false)
+ , m_itf(itf.singular())
+ , m_bd(gbd.singular())
+ , m_rd(grd.singular())
+{
+}
+
+gbp_ext_itf::gbp_ext_itf(const gbp_ext_itf& gbpe)
+ : m_hw(gbpe.m_hw)
+ , m_itf(gbpe.m_itf)
+ , m_bd(gbpe.m_bd)
+ , m_rd(gbpe.m_rd)
+{
+}
+
+gbp_ext_itf::~gbp_ext_itf()
+{
+ sweep();
+ m_db.release(key(), this);
+}
+
+const gbp_ext_itf::key_t
+gbp_ext_itf::key() const
+{
+ return (m_itf->key());
+}
+
+const handle_t&
+gbp_ext_itf::handle() const
+{
+ return m_itf->handle();
+}
+
+bool
+gbp_ext_itf::operator==(const gbp_ext_itf& gei) const
+{
+ return ((key() == gei.key()) && (m_itf == gei.m_itf) && (m_rd == gei.m_rd) &&
+ (m_bd == gei.m_bd));
+}
+
+void
+gbp_ext_itf::sweep()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_ext_itf_cmds::delete_cmd(m_hw, m_itf->handle()));
+ }
+ HW::write();
+}
+
+void
+gbp_ext_itf::replay()
+{
+ if (m_hw) {
+ HW::enqueue(new gbp_ext_itf_cmds::create_cmd(m_hw, m_itf->handle(),
+ m_bd->id(), m_rd->id()));
+ }
+}
+
+std::string
+gbp_ext_itf::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-ext_itf:[" << m_itf->to_string() << ", " << m_bd->to_string()
+ << ", " << m_rd->to_string() << "]";
+
+ return (s.str());
+}
+
+void
+gbp_ext_itf::update(const gbp_ext_itf& r)
+{
+ if (rc_t::OK != m_hw.rc()) {
+ HW::enqueue(new gbp_ext_itf_cmds::create_cmd(m_hw, m_itf->handle(),
+ m_bd->id(), m_rd->id()));
+ }
+}
+
+std::shared_ptr<gbp_ext_itf>
+gbp_ext_itf::find_or_add(const gbp_ext_itf& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<gbp_ext_itf>
+gbp_ext_itf::find(const key_t& k)
+{
+ return (m_db.find(k));
+}
+
+std::shared_ptr<gbp_ext_itf>
+gbp_ext_itf::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+gbp_ext_itf::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+gbp_ext_itf::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "gbp-ext-itf" }, "GBP External-Itfs", this);
+}
+
+void
+gbp_ext_itf::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+void
+gbp_ext_itf::event_handler::handle_populate(const client_db::key_t& key)
+{
+ std::shared_ptr<gbp_ext_itf_cmds::dump_cmd> cmd =
+ std::make_shared<gbp_ext_itf_cmds::dump_cmd>();
+
+ HW::enqueue(cmd);
+ HW::write();
+
+ for (auto& record : *cmd) {
+ auto& payload = record.get_payload();
+
+ std::shared_ptr<interface> itf =
+ interface::find(payload.ext_itf.sw_if_index);
+ std::shared_ptr<gbp_bridge_domain> gbd =
+ gbp_bridge_domain::find(payload.ext_itf.bd_id);
+ std::shared_ptr<gbp_route_domain> grd =
+ gbp_route_domain::find(payload.ext_itf.rd_id);
+
+ VOM_LOG(log_level_t::DEBUG) << "data: [" << payload.ext_itf.sw_if_index
+ << ", " << payload.ext_itf.bd_id << ", "
+ << payload.ext_itf.rd_id << "]";
+
+ if (itf && gbd && grd) {
+ gbp_ext_itf ext_itf(*itf, *gbd, *grd);
+ OM::commit(key, ext_itf);
+
+ VOM_LOG(log_level_t::DEBUG) << "read: " << ext_itf.to_string();
+ }
+ }
+}
+
+dependency_t
+gbp_ext_itf::event_handler::order() const
+{
+ return (dependency_t::BINDING);
+}
+
+void
+gbp_ext_itf::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+} // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_ext_itf.hpp b/extras/vom/vom/gbp_ext_itf.hpp
new file mode 100644
index 00000000000..20d9b6eff9b
--- /dev/null
+++ b/extras/vom/vom/gbp_ext_itf.hpp
@@ -0,0 +1,186 @@
+/*
+ * 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 __VOM_GBP_EXT_ITF_H__
+#define __VOM_GBP_EXT_ITF_H__
+
+#include "vom/gbp_bridge_domain.hpp"
+#include "vom/gbp_route_domain.hpp"
+#include "vom/interface.hpp"
+#include "vom/singular_db.hpp"
+
+namespace VOM {
+/**
+ * A enternal interface for GBP
+ */
+class gbp_ext_itf : public object_base
+{
+public:
+ /**
+ * The key for a GBP ext_itf interface
+ */
+ typedef interface::key_t key_t;
+
+ /**
+ * Construct a GBP ext_itf
+ */
+ gbp_ext_itf(const interface& itf,
+ const gbp_bridge_domain& gbd,
+ const gbp_route_domain& grd);
+
+ /**
+ * Copy Construct
+ */
+ gbp_ext_itf(const gbp_ext_itf& r);
+
+ /**
+ * Destructor
+ */
+ ~gbp_ext_itf();
+
+ /**
+ * Return the object's key
+ */
+ const key_t key() const;
+
+ /**
+ * comparison operator
+ */
+ bool operator==(const gbp_ext_itf& bdae) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<gbp_ext_itf> singular() const;
+
+ /**
+ * Find the instnace of the ext_itf interface in the OM
+ */
+ static std::shared_ptr<gbp_ext_itf> 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;
+
+ /**
+ * return the ext_itfulation interface's handle
+ */
+ const handle_t& handle() 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_ext_itf& obj);
+
+ /**
+ * Find or add the instnace of the bridge_domain domain in the OM
+ */
+ static std::shared_ptr<gbp_ext_itf> find_or_add(const gbp_ext_itf& 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_ext_itf>;
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the ext_itf
+ */
+ HW::item<bool> m_hw;
+
+ /**
+ * The interface the ext_itf is attached to.
+ */
+ std::shared_ptr<interface> m_itf;
+
+ /**
+ * The BD & RD the ext_itf is in
+ */
+ std::shared_ptr<gbp_bridge_domain> m_bd;
+ std::shared_ptr<gbp_route_domain> m_rd;
+
+ /**
+ * A map of all bridge_domains
+ */
+ static singular_db<key_t, gbp_ext_itf> m_db;
+};
+
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_ext_itf_cmds.cpp b/extras/vom/vom/gbp_ext_itf_cmds.cpp
new file mode 100644
index 00000000000..b2090ea0fa5
--- /dev/null
+++ b/extras/vom/vom/gbp_ext_itf_cmds.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#include "vom/gbp_ext_itf_cmds.hpp"
+
+namespace VOM {
+namespace gbp_ext_itf_cmds {
+
+create_cmd::create_cmd(HW::item<bool>& item,
+ const handle_t& itf,
+ uint32_t bd_id,
+ uint32_t rd_id)
+ : rpc_cmd(item)
+ , m_itf(itf)
+ , m_bd_id(bd_id)
+ , m_rd_id(rd_id)
+{
+}
+
+bool
+create_cmd::operator==(const create_cmd& other) const
+{
+ return ((m_itf == other.m_itf) && (m_bd_id == other.m_bd_id) &&
+ (m_rd_id == other.m_rd_id));
+}
+
+rc_t
+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.ext_itf.sw_if_index = m_itf.value();
+ payload.ext_itf.bd_id = m_bd_id;
+ payload.ext_itf.rd_id = m_rd_id;
+
+ VAPI_CALL(req.execute());
+
+ return (wait());
+}
+
+std::string
+create_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-ext_itf-create: " << m_hw_item.to_string() << " itf:" << m_itf
+ << " bd-id:" << m_bd_id << " rd-id:" << m_rd_id;
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<bool>& item, const handle_t& itf)
+ : rpc_cmd(item)
+ , m_itf(itf)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return (m_itf == other.m_itf);
+}
+
+rc_t
+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.ext_itf.sw_if_index = m_itf.value();
+ payload.ext_itf.bd_id = ~0;
+ payload.ext_itf.rd_id = ~0;
+
+ VAPI_CALL(req.execute());
+
+ return (wait());
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "gbp-ext-itf-delete: " << m_hw_item.to_string() << " itf:" << m_itf;
+
+ 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-ext-itf-dump");
+}
+
+}; // namespace gbp_ext_itf_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_ext_itf_cmds.hpp b/extras/vom/vom/gbp_ext_itf_cmds.hpp
new file mode 100644
index 00000000000..51052b9a360
--- /dev/null
+++ b/extras/vom/vom/gbp_ext_itf_cmds.hpp
@@ -0,0 +1,134 @@
+/*
+ * 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_EXT_ITF_CMDS_H__
+#define __VOM_GBP_EXT_ITF_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/gbp_ext_itf.hpp"
+
+#include <vapi/gbp.api.vapi.hpp>
+
+namespace VOM {
+namespace gbp_ext_itf_cmds {
+
+/**
+* A command class that creates or updates the GBP ext_itf
+*/
+class create_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_ext_itf_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ create_cmd(HW::item<bool>& item,
+ const handle_t& itf,
+ uint32_t bd_id,
+ uint32_t rd_id);
+
+ /**
+ * 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_itf;
+ const uint32_t m_bd_id;
+ const uint32_t m_rd_id;
+};
+
+/**
+ * A cmd class that deletes a GBP ext_itf
+ */
+class delete_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_ext_itf_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<bool>& item, const handle_t& itf);
+
+ /**
+ * 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:
+ const handle_t m_itf;
+};
+
+/**
+ * A cmd class that Dumps all the GBP ext_itfs
+ */
+class dump_cmd : public VOM::dump_cmd<vapi::Gbp_ext_itf_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_cmd() = 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;
+};
+}; // namespace gbp_ext_itf_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/gbp_subnet.cpp b/extras/vom/vom/gbp_subnet.cpp
index 2221c616dbb..8404dcd2e65 100644
--- a/extras/vom/vom/gbp_subnet.cpp
+++ b/extras/vom/vom/gbp_subnet.cpp
@@ -62,6 +62,18 @@ gbp_subnet::gbp_subnet(const gbp_route_domain& rd,
{
}
+gbp_subnet::gbp_subnet(const gbp_route_domain& rd,
+ const route::prefix_t& prefix,
+ const gbp_endpoint_group& epg)
+ : m_hw(false)
+ , m_rd(rd.singular())
+ , m_prefix(prefix)
+ , m_type(type_t::L3_OUT)
+ , m_recirc(nullptr)
+ , m_epg(epg.singular())
+{
+}
+
gbp_subnet::gbp_subnet(const gbp_subnet& o)
: m_hw(o.m_hw)
, m_rd(o.m_rd)
@@ -215,6 +227,15 @@ gbp_subnet::event_handler::handle_populate(const client_db::key_t& key)
VOM_LOG(log_level_t::DEBUG) << "read: " << gs.to_string();
break;
}
+ case GBP_API_SUBNET_L3_OUT: {
+ std::shared_ptr<gbp_endpoint_group> epg =
+ gbp_endpoint_group::find(payload.subnet.epg_id);
+
+ gbp_subnet gs(*rd, pfx, *epg);
+ 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);
diff --git a/extras/vom/vom/gbp_subnet.hpp b/extras/vom/vom/gbp_subnet.hpp
index e08f1a25e11..f18aa01431e 100644
--- a/extras/vom/vom/gbp_subnet.hpp
+++ b/extras/vom/vom/gbp_subnet.hpp
@@ -53,6 +53,11 @@ public:
*/
const static type_t TRANSPORT;
+ /**
+ * A transport subnet, sent via the RD's UU-fwd interface
+ */
+ const static type_t L3_OUT;
+
private:
type_t(int v, const std::string s);
};
@@ -65,7 +70,7 @@ public:
const type_t& type);
/**
- * Construct an external GBP subnet
+ * Construct an stitched external GBP subnet
*/
gbp_subnet(const gbp_route_domain& rd,
const route::prefix_t& prefix,
@@ -73,6 +78,13 @@ public:
const gbp_endpoint_group& epg);
/**
+ * Construct an l3-out GBP subnet
+ */
+ gbp_subnet(const gbp_route_domain& rd,
+ const route::prefix_t& prefix,
+ const gbp_endpoint_group& epg);
+
+ /**
* Copy Construct
*/
gbp_subnet(const gbp_subnet& r);
diff --git a/src/plugins/gbp/CMakeLists.txt b/src/plugins/gbp/CMakeLists.txt
index 377197a7c08..4b511413b82 100644
--- a/src/plugins/gbp/CMakeLists.txt
+++ b/src/plugins/gbp/CMakeLists.txt
@@ -19,6 +19,7 @@ add_vpp_plugin(gbp
gbp_contract.c
gbp_endpoint.c
gbp_endpoint_group.c
+ gbp_ext_itf.c
gbp_fwd.c
gbp_fwd_dpo.c
gbp_itf.c
diff --git a/src/plugins/gbp/gbp.api b/src/plugins/gbp/gbp.api
index 6bdcc5d7e0c..bf7c167a42f 100644
--- a/src/plugins/gbp/gbp.api
+++ b/src/plugins/gbp/gbp.api
@@ -95,12 +95,13 @@ define gbp_route_domain_details
enum gbp_endpoint_flags
{
- NONE = 0,
- BOUNCE = 0x1,
- REMOTE = 0x2,
- LEARNT = 0x4,
+ GBP_API_ENDPOINT_FLAG_NONE = 0,
+ GBP_API_ENDPOINT_FLAG_BOUNCE = 0x1,
+ GBP_API_ENDPOINT_FLAG_REMOTE = 0x2,
+ GBP_API_ENDPOINT_FLAG_LEARNT = 0x4,
/* hey Ole WTF */
- REMOTE_LEARNT = 0x6,
+ GBP_API_ENDPOINT_FLAG_REMOTE_LEARNT = 0x6,
+ GBP_API_ENDPOINT_FLAG_EXTERNAL = 0x8,
};
typedef gbp_endpoint_tun
@@ -220,6 +221,7 @@ enum gbp_subnet_type
GBP_API_SUBNET_TRANSPORT,
GBP_API_SUBNET_STITCHED_INTERNAL,
GBP_API_SUBNET_STITCHED_EXTERNAL,
+ GBP_API_SUBNET_L3_OUT,
};
typeonly define gbp_subnet
@@ -379,6 +381,33 @@ define gbp_vxlan_tunnel_details
vl_api_gbp_vxlan_tunnel_t tunnel;
};
+typeonly define gbp_ext_itf
+{
+ u32 sw_if_index;
+ u32 bd_id;
+ u32 rd_id;
+};
+
+autoreply define gbp_ext_itf_add_del
+{
+ u32 client_index;
+ u32 context;
+ u8 is_add;
+ vl_api_gbp_ext_itf_t ext_itf;
+};
+
+define gbp_ext_itf_dump
+{
+ u32 client_index;
+ u32 context;
+};
+
+define gbp_ext_itf_details
+{
+ u32 context;
+ vl_api_gbp_ext_itf_t ext_itf;
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/plugins/gbp/gbp_api.c b/src/plugins/gbp/gbp_api.c
index 4402ec15b8c..5f87db8f83c 100644
--- a/src/plugins/gbp/gbp_api.c
+++ b/src/plugins/gbp/gbp_api.c
@@ -30,6 +30,7 @@
#include <gbp/gbp_vxlan.h>
#include <gbp/gbp_bridge_domain.h>
#include <gbp/gbp_route_domain.h>
+#include <gbp/gbp_ext_itf.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
@@ -75,6 +76,8 @@
_(GBP_ROUTE_DOMAIN_DUMP, gbp_route_domain_dump) \
_(GBP_RECIRC_ADD_DEL, gbp_recirc_add_del) \
_(GBP_RECIRC_DUMP, gbp_recirc_dump) \
+ _(GBP_EXT_ITF_ADD_DEL, gbp_ext_itf_add_del) \
+ _(GBP_EXT_ITF_DUMP, gbp_ext_itf_dump) \
_(GBP_CONTRACT_ADD_DEL, gbp_contract_add_del) \
_(GBP_CONTRACT_DUMP, gbp_contract_dump) \
_(GBP_ENDPOINT_LEARN_SET_INACTIVE_THRESHOLD, gbp_endpoint_learn_set_inactive_threshold) \
@@ -95,12 +98,14 @@ gbp_endpoint_flags_decode (vl_api_gbp_endpoint_flags_t v)
v = ntohl (v);
- if (v & BOUNCE)
+ if (v & GBP_API_ENDPOINT_FLAG_BOUNCE)
f |= GBP_ENDPOINT_FLAG_BOUNCE;
- if (v & REMOTE)
+ if (v & GBP_API_ENDPOINT_FLAG_REMOTE)
f |= GBP_ENDPOINT_FLAG_REMOTE;
- if (v & LEARNT)
+ if (v & GBP_API_ENDPOINT_FLAG_LEARNT)
f |= GBP_ENDPOINT_FLAG_LEARNT;
+ if (v & GBP_API_ENDPOINT_FLAG_EXTERNAL)
+ f |= GBP_ENDPOINT_FLAG_EXTERNAL;
return (f);
}
@@ -112,11 +117,13 @@ gbp_endpoint_flags_encode (gbp_endpoint_flags_t f)
if (f & GBP_ENDPOINT_FLAG_BOUNCE)
- v |= BOUNCE;
+ v |= GBP_API_ENDPOINT_FLAG_BOUNCE;
if (f & GBP_ENDPOINT_FLAG_REMOTE)
- v |= REMOTE;
+ v |= GBP_API_ENDPOINT_FLAG_REMOTE;
if (f & GBP_ENDPOINT_FLAG_LEARNT)
- v |= LEARNT;
+ v |= GBP_API_ENDPOINT_FLAG_LEARNT;
+ if (f & GBP_ENDPOINT_FLAG_EXTERNAL)
+ v |= GBP_API_ENDPOINT_FLAG_EXTERNAL;
v = htonl (v);
@@ -386,6 +393,9 @@ gub_subnet_type_from_api (vl_api_gbp_subnet_type_t a, gbp_subnet_type_t * t)
case GBP_API_SUBNET_TRANSPORT:
*t = GBP_SUBNET_TRANSPORT;
return (0);
+ case GBP_API_SUBNET_L3_OUT:
+ *t = GBP_SUBNET_L3_OUT;
+ return (0);
case GBP_API_SUBNET_STITCHED_INTERNAL:
*t = GBP_SUBNET_STITCHED_INTERNAL;
return (0);
@@ -440,6 +450,9 @@ gub_subnet_type_to_api (gbp_subnet_type_t t)
case GBP_SUBNET_STITCHED_EXTERNAL:
a = GBP_API_SUBNET_STITCHED_EXTERNAL;
break;
+ case GBP_SUBNET_L3_OUT:
+ a = GBP_API_SUBNET_L3_OUT;
+ break;
}
a = clib_host_to_net_u32 (a);
@@ -642,7 +655,7 @@ vl_api_gbp_recirc_add_del_t_handler (vl_api_gbp_recirc_add_del_t * mp)
REPLY_MACRO (VL_API_GBP_RECIRC_ADD_DEL_REPLY + GBP_MSG_BASE);
}
-static int
+static walk_rc_t
gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
{
vl_api_gbp_recirc_details_t *mp;
@@ -651,7 +664,7 @@ gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
ctx = args;
mp = vl_msg_api_alloc (sizeof (*mp));
if (!mp)
- return 1;
+ return (WALK_STOP);
clib_memset (mp, 0, sizeof (*mp));
mp->_vl_msg_id = ntohs (VL_API_GBP_RECIRC_DETAILS + GBP_MSG_BASE);
@@ -663,7 +676,7 @@ gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
vl_api_send_msg (ctx->reg, (u8 *) mp);
- return (1);
+ return (WALK_CONTINUE);
}
static void
@@ -683,6 +696,70 @@ vl_api_gbp_recirc_dump_t_handler (vl_api_gbp_recirc_dump_t * mp)
gbp_recirc_walk (gbp_recirc_send_details, &ctx);
}
+static void
+vl_api_gbp_ext_itf_add_del_t_handler (vl_api_gbp_ext_itf_add_del_t * mp)
+{
+ vl_api_gbp_ext_itf_add_del_reply_t *rmp;
+ u32 sw_if_index;
+ int rv = 0;
+
+ sw_if_index = ntohl (mp->ext_itf.sw_if_index);
+ if (!vnet_sw_if_index_is_api_valid (sw_if_index))
+ goto bad_sw_if_index;
+
+ if (mp->is_add)
+ rv = gbp_ext_itf_add (sw_if_index,
+ ntohl (mp->ext_itf.bd_id),
+ ntohl (mp->ext_itf.rd_id));
+ else
+ rv = gbp_ext_itf_delete (sw_if_index);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_GBP_EXT_ITF_ADD_DEL_REPLY + GBP_MSG_BASE);
+}
+
+static walk_rc_t
+gbp_ext_itf_send_details (gbp_ext_itf_t * gx, void *args)
+{
+ vl_api_gbp_ext_itf_details_t *mp;
+ gbp_walk_ctx_t *ctx;
+
+ ctx = args;
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ if (!mp)
+ return (WALK_STOP);
+
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_GBP_EXT_ITF_DETAILS + GBP_MSG_BASE);
+ mp->context = ctx->context;
+
+ mp->ext_itf.bd_id = ntohl (gbp_bridge_domain_get_bd_id (gx->gx_bd));
+ mp->ext_itf.rd_id = ntohl (gbp_route_domain_get_rd_id (gx->gx_rd));
+ mp->ext_itf.sw_if_index = ntohl (gx->gx_itf);
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_gbp_ext_itf_dump_t_handler (vl_api_gbp_ext_itf_dump_t * mp)
+{
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ gbp_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+
+ gbp_ext_itf_walk (gbp_ext_itf_send_details, &ctx);
+}
+
static int
gbp_contract_rule_action_deocde (vl_api_gbp_rule_action_t in,
gbp_rule_action_t * out)
diff --git a/src/plugins/gbp/gbp_bridge_domain.c b/src/plugins/gbp/gbp_bridge_domain.c
index 298819f87f1..21ffe9cc314 100644
--- a/src/plugins/gbp/gbp_bridge_domain.c
+++ b/src/plugins/gbp/gbp_bridge_domain.c
@@ -56,6 +56,16 @@ gbp_bridge_domain_lock (index_t i)
gb->gb_locks++;
}
+u32
+gbp_bridge_domain_get_bd_id (index_t gbdi)
+{
+ gbp_bridge_domain_t *gb;
+
+ gb = gbp_bridge_domain_get (gbdi);
+
+ return (gb->gb_bd_id);
+}
+
static index_t
gbp_bridge_domain_find (u32 bd_id)
{
diff --git a/src/plugins/gbp/gbp_bridge_domain.h b/src/plugins/gbp/gbp_bridge_domain.h
index cc03320871a..65f133c84da 100644
--- a/src/plugins/gbp/gbp_bridge_domain.h
+++ b/src/plugins/gbp/gbp_bridge_domain.h
@@ -78,6 +78,7 @@ 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 index_t gbp_bridge_domain_index (const gbp_bridge_domain_t *);
+extern u32 gbp_bridge_domain_get_bd_id (index_t gbdi);
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);
diff --git a/src/plugins/gbp/gbp_classify.c b/src/plugins/gbp/gbp_classify.c
index 4846911ed65..94044ae7214 100644
--- a/src/plugins/gbp/gbp_classify.c
+++ b/src/plugins/gbp/gbp_classify.c
@@ -16,6 +16,11 @@
*/
#include <plugins/gbp/gbp.h>
+#include <plugins/gbp/gbp_policy_dpo.h>
+#include <plugins/gbp/gbp_ext_itf.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/dpo/load_balance.h>
#include <vnet/l2/l2_input.h>
#include <vnet/l2/feat_bitmap.h>
#include <vnet/fib/fib_table.h>
@@ -25,9 +30,10 @@ typedef enum gbp_src_classify_type_t_
{
GBP_SRC_CLASSIFY_NULL,
GBP_SRC_CLASSIFY_PORT,
+ GBP_SRC_CLASSIFY_LPM,
} gbp_src_classify_type_t;
-#define GBP_SRC_N_CLASSIFY (GBP_SRC_CLASSIFY_PORT + 1)
+#define GBP_SRC_N_CLASSIFY (GBP_SRC_CLASSIFY_LPM + 1)
/**
* Grouping of global data for the GBP source EPG classification feature
@@ -297,6 +303,276 @@ VNET_FEATURE_INIT (gbp_ip6_src_classify_feat_node, static) =
.runs_before = VNET_FEATURES ("nat66-out2in"),
};
+/* *INDENT-ON* */
+
+typedef enum gbp_lpm_classify_next_t_
+{
+ GPB_LPM_CLASSIFY_DROP,
+} gbp_lpm_classify_next_t;
+
+always_inline dpo_proto_t
+ethertype_to_dpo_proto (const ethernet_header_t * eh0)
+{
+ u16 etype = clib_net_to_host_u16 (eh0->type);
+
+ switch (etype)
+ {
+ case ETHERNET_TYPE_IP4:
+ return (DPO_PROTO_IP4);
+ case ETHERNET_TYPE_IP6:
+ return (DPO_PROTO_IP6);
+ case ETHERNET_TYPE_VLAN:
+ {
+ ethernet_vlan_header_t *vh0;
+
+ vh0 = (ethernet_vlan_header_t *) (eh0 + 1);
+
+ switch (clib_net_to_host_u16 (vh0->type))
+ {
+ case ETHERNET_TYPE_IP4:
+ return (DPO_PROTO_IP4);
+ case ETHERNET_TYPE_IP6:
+ return (DPO_PROTO_IP6);
+ }
+ }
+ }
+
+ return (DPO_PROTO_NONE);
+}
+
+/*
+ * Determine the SRC EPG from a LPM
+ */
+always_inline uword
+gbp_lpm_classify_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame,
+ dpo_proto_t dproto, u8 is_recirc)
+{
+ gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
+ u32 n_left_from, *from, *to_next;
+ u32 next_index;
+
+ next_index = 0;
+ n_left_from = frame->n_vectors;
+ from = vlib_frame_vector_args (frame);
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, sw_if_index0, fib_index0, lbi0;
+ gbp_lpm_classify_next_t next0;
+ const gbp_policy_dpo_t *gpd0;
+ const gbp_ext_itf_t *gx0;
+ const gbp_recirc_t *gr0;
+ const dpo_id_t *dpo0;
+ load_balance_t *lb0;
+ ip4_header_t *ip4_0;
+ ip6_header_t *ip6_0;
+ vlib_buffer_t *b0;
+ epg_id_t src_epg0;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+ next0 = GPB_LPM_CLASSIFY_DROP;
+
+ 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 (DPO_PROTO_IP4 == dproto)
+ ip4_0 = vlib_buffer_get_current (b0);
+ else if (DPO_PROTO_IP4 == dproto)
+ ip6_0 = vlib_buffer_get_current (b0);
+ else if (DPO_PROTO_ETHERNET == dproto)
+ {
+ const ethernet_header_t *eh0;
+
+ eh0 = vlib_buffer_get_current (b0);
+
+ dproto = ethertype_to_dpo_proto (eh0);
+
+ switch (dproto)
+ {
+ case DPO_PROTO_IP4:
+ ip4_0 = (vlib_buffer_get_current (b0) +
+ vnet_buffer (b0)->l2.l2_len);
+ break;
+ case DPO_PROTO_IP6:
+ ip6_0 = (vlib_buffer_get_current (b0) +
+ vnet_buffer (b0)->l2.l2_len);
+ break;
+ default:
+ /* not IP so no LPM classify possible */
+ src_epg0 = EPG_INVALID;
+ goto trace;
+ }
+ }
+
+ if (is_recirc)
+ {
+ gr0 = gbp_recirc_get (sw_if_index0);
+ fib_index0 = gr0->gr_fib_index[dproto];
+
+ vnet_feature_next (&next0, b0);
+ }
+ else
+ {
+ gx0 = gbp_ext_itf_get (sw_if_index0);
+ fib_index0 = gx0->gx_fib_index[dproto];
+
+ next0 = vnet_l2_feature_next
+ (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM],
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+ }
+
+ if (DPO_PROTO_IP4 == dproto)
+ {
+ lbi0 = ip4_fib_forwarding_lookup (fib_index0,
+ &ip4_0->src_address);
+ }
+ else if (DPO_PROTO_IP4 == dproto)
+ {
+ lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
+ &ip6_0->src_address);
+ }
+ else
+ {
+ /* not IP so no LPM classify possible */
+ src_epg0 = EPG_INVALID;
+ goto trace;
+ }
+ lb0 = load_balance_get (lbi0);
+ dpo0 = load_balance_get_bucket_i (lb0, 0);
+
+ if (gbp_policy_dpo_type == dpo0->dpoi_type)
+ {
+ gpd0 = gbp_policy_dpo_get (dpo0->dpoi_index);
+ src_epg0 = gpd0->gpd_epg;
+ }
+ else
+ {
+ /* could not classify => drop */
+ src_epg0 = EPG_INVALID;
+ next0 = GPB_LPM_CLASSIFY_DROP;
+ }
+
+ trace:
+ vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
+
+ if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ gbp_classify_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->src_epg = src_epg0;
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+static uword
+gbp_ip4_lpm_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP4, 1));
+}
+
+static uword
+gbp_ip6_lpm_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP6, 1));
+}
+
+static uword
+gbp_l2_lpm_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (gbp_ip4_lpm_classify_node) = {
+ .function = gbp_ip4_lpm_classify,
+ .name = "ip4-gbp-lpm-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip4_lpm_classify_node, gbp_ip4_lpm_classify);
+
+VLIB_REGISTER_NODE (gbp_ip6_lpm_classify_node) = {
+ .function = gbp_ip6_lpm_classify,
+ .name = "ip6-gbp-lpm-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip6_lpm_classify_node, gbp_ip6_lpm_classify);
+
+VLIB_REGISTER_NODE (gbp_l2_lpm_classify_node) = {
+ .function = gbp_l2_lpm_classify,
+ .name = "l2-gbp-lpm-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "error-drop"
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (gbp_l2_lpm_classify_node, gbp_l2_lpm_classify);
+
+VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
+{
+ .arc_name = "ip4-unicast",
+ .node_name = "ip4-gbp-lpm-classify",
+ .runs_before = VNET_FEATURES ("nat44-out2in"),
+};
+VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
+{
+ .arc_name = "ip6-unicast",
+ .node_name = "ip6-gbp-lpm-classify",
+ .runs_before = VNET_FEATURES ("nat66-out2in"),
+};
+
+/* *INDENT-ON* */
+
static clib_error_t *
gbp_src_classify_init (vlib_main_t * vm)
{
@@ -313,6 +589,11 @@ gbp_src_classify_init (vlib_main_t * vm)
L2INPUT_N_FEAT,
l2input_get_feat_names (),
em->l2_input_feat_next[GBP_SRC_CLASSIFY_PORT]);
+ feat_bitmap_init_next_nodes (vm,
+ gbp_l2_lpm_classify_node.index,
+ L2INPUT_N_FEAT,
+ l2input_get_feat_names (),
+ em->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM]);
return 0;
}
diff --git a/src/plugins/gbp/gbp_endpoint.c b/src/plugins/gbp/gbp_endpoint.c
index e9ced3f9e03..0746b70d57f 100644
--- a/src/plugins/gbp/gbp_endpoint.c
+++ b/src/plugins/gbp/gbp_endpoint.c
@@ -92,7 +92,19 @@ format_gbp_endpoint_flags (u8 * s, va_list * args)
int
gbp_endpoint_is_remote (const gbp_endpoint_t * ge)
{
- return (ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE);
+ return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE));
+}
+
+int
+gbp_endpoint_is_local (const gbp_endpoint_t * ge)
+{
+ return (!(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE));
+}
+
+int
+gbp_endpoint_is_external (const gbp_endpoint_t * ge)
+{
+ return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_EXTERNAL));
}
static void
@@ -625,8 +637,12 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
{
gbp_itf_set_l2_input_feature (gef->gef_itf, gei, L2INPUT_FEAT_GBP_FWD);
- if (gbp_endpoint_is_remote (ge))
+ if (gbp_endpoint_is_remote (ge) || gbp_endpoint_is_external (ge))
{
+ /*
+ * bridged packets to external endpoints should be classifed
+ * based on the EP's/BD's EPG
+ */
gbp_itf_set_l2_output_feature (gef->gef_itf, gei,
L2OUTPUT_FEAT_GBP_POLICY_MAC);
}
@@ -711,6 +727,12 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
ip_sw_if_index, rewrite);
vec_add1 (gef->gef_adjs, ai);
+ /*
+ * if the endpoint is external then routed packet to it must be
+ * classifed to the BD's EPG. but this will happen anyway with
+ * the GBP_MAC classification.
+ */
+
if (NULL != gg)
{
if (gbp_endpoint_is_remote (ge))
@@ -728,6 +750,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
FIB_SOURCE_PLUGIN_HI,
FIB_ENTRY_FLAG_INTERPOSE,
&policy_dpo);
+ dpo_reset (&policy_dpo);
}
/*
@@ -735,7 +758,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
* that if this EP has moved from some other place in the
* 'fabric', upstream devices are informed
*/
- if (!gbp_endpoint_is_remote (ge) && ~0 != gg->gg_uplink_sw_if_index)
+ if (gbp_endpoint_is_local (ge) && ~0 != gg->gg_uplink_sw_if_index)
{
gbp_endpoint_add_itf (gef->gef_itf, gei);
if (FIB_PROTOCOL_IP4 == pfx->fp_proto)
@@ -750,13 +773,14 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
}
}
- if (!gbp_endpoint_is_remote (ge))
+ if (gbp_endpoint_is_local (ge) && !gbp_endpoint_is_external (ge))
{
/*
* non-remote endpoints (i.e. those not arriving on iVXLAN
* tunnels) need to be classifed based on the the input interface.
* We enable the GBP-FWD feature only if the group has an uplink
* interface (on which the GBP-FWD feature would send UU traffic).
+ * External endpoints get classified based on an LPM match
*/
l2input_feat_masks_t feats = L2INPUT_FEAT_GBP_SRC_CLASSIFY;
@@ -1444,6 +1468,10 @@ void
gbp_learn_set_inactive_threshold (u32 threshold)
{
GBP_ENDPOINT_INACTIVE_TIME = threshold;
+
+ vlib_process_signal_event (vlib_get_main (),
+ gbp_scanner_node.index,
+ GBP_ENDPOINT_SCAN_SET_TIME, 0);
}
f64
diff --git a/src/plugins/gbp/gbp_endpoint.h b/src/plugins/gbp/gbp_endpoint.h
index d56e91daa99..4b4c2e0b627 100644
--- a/src/plugins/gbp/gbp_endpoint.h
+++ b/src/plugins/gbp/gbp_endpoint.h
@@ -32,8 +32,9 @@ typedef enum gbp_endpoint_attr_t_
{
GBP_ENDPOINT_ATTR_FIRST = 0,
GBP_ENDPOINT_ATTR_BOUNCE = GBP_ENDPOINT_ATTR_FIRST,
- GBP_ENDPOINT_ATTR_REMOTE = 1,
- GBP_ENDPOINT_ATTR_LEARNT = 2,
+ GBP_ENDPOINT_ATTR_REMOTE,
+ GBP_ENDPOINT_ATTR_LEARNT,
+ GBP_ENDPOINT_ATTR_EXTERNAL,
GBP_ENDPOINT_ATTR_LAST,
} gbp_endpoint_attr_t;
@@ -43,12 +44,14 @@ typedef enum gbp_endpoint_flags_t_
GBP_ENDPOINT_FLAG_BOUNCE = (1 << GBP_ENDPOINT_ATTR_BOUNCE),
GBP_ENDPOINT_FLAG_REMOTE = (1 << GBP_ENDPOINT_ATTR_REMOTE),
GBP_ENDPOINT_FLAG_LEARNT = (1 << GBP_ENDPOINT_ATTR_LEARNT),
+ GBP_ENDPOINT_FLAG_EXTERNAL = (1 << GBP_ENDPOINT_ATTR_EXTERNAL),
} gbp_endpoint_flags_t;
#define GBP_ENDPOINT_ATTR_NAMES { \
[GBP_ENDPOINT_ATTR_BOUNCE] = "bounce", \
[GBP_ENDPOINT_ATTR_REMOTE] = "remote", \
[GBP_ENDPOINT_ATTR_LEARNT] = "learnt", \
+ [GBP_ENDPOINT_ATTR_EXTERNAL] = "external", \
}
extern u8 *format_gbp_endpoint_flags (u8 * s, va_list * args);
@@ -235,6 +238,8 @@ extern void gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx);
extern void gbp_endpoint_scan (vlib_main_t * vm);
extern f64 gbp_endpoint_scan_threshold (void);
extern int gbp_endpoint_is_remote (const gbp_endpoint_t * ge);
+extern int gbp_endpoint_is_local (const gbp_endpoint_t * ge);
+extern int gbp_endpoint_is_external (const gbp_endpoint_t * ge);
extern int gbp_endpoint_is_learnt (const gbp_endpoint_t * ge);
diff --git a/src/plugins/gbp/gbp_ext_itf.c b/src/plugins/gbp/gbp_ext_itf.c
new file mode 100644
index 00000000000..57ff625d64a
--- /dev/null
+++ b/src/plugins/gbp/gbp_ext_itf.c
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#include <plugins/gbp/gbp_ext_itf.h>
+#include <plugins/gbp/gbp_bridge_domain.h>
+#include <plugins/gbp/gbp_route_domain.h>
+#include <plugins/gbp/gbp_itf.h>
+
+/**
+ * Pool of GBP ext_itfs
+ */
+gbp_ext_itf_t *gbp_ext_itf_pool;
+
+/**
+ * external interface configs keyed by sw_if_index
+ */
+index_t *gbp_ext_itf_db;
+
+#define GBP_EXT_ITF_ID 0x00000080
+
+/**
+ * logger
+ */
+vlib_log_class_t gx_logger;
+
+#define GBP_EXT_ITF_DBG(...) \
+ vlib_log_debug (gx_logger, __VA_ARGS__);
+
+u8 *
+format_gbp_ext_itf (u8 * s, va_list * args)
+{
+ gbp_ext_itf_t *gx = va_arg (*args, gbp_ext_itf_t *);
+
+ return (format (s, "%U in %U",
+ format_gbp_itf, gx->gx_itf,
+ format_gbp_bridge_domain, gx->gx_bd));
+}
+
+int
+gbp_ext_itf_add (u32 sw_if_index, u32 bd_id, u32 rd_id)
+{
+ gbp_ext_itf_t *gx;
+ index_t gxi;
+
+ vec_validate_init_empty (gbp_ext_itf_db, sw_if_index, INDEX_INVALID);
+
+ gxi = gbp_ext_itf_db[sw_if_index];
+
+ if (INDEX_INVALID == gxi)
+ {
+ gbp_bridge_domain_t *gb;
+ gbp_route_domain_t *gr;
+ fib_protocol_t fproto;
+ index_t gbi, gri;
+
+ gbi = gbp_bridge_domain_find_and_lock (bd_id);
+
+ if (INDEX_INVALID == gbi)
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+
+ gri = gbp_route_domain_find_and_lock (rd_id);
+
+ if (INDEX_INVALID == gri)
+ {
+ gbp_bridge_domain_unlock (gbi);
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+ }
+
+ pool_get_zero (gbp_ext_itf_pool, gx);
+ gxi = gx - gbp_ext_itf_pool;
+
+ gb = gbp_bridge_domain_get (gbi);
+ gr = gbp_route_domain_get (gri);
+
+ gx->gx_bd = gbi;
+ gx->gx_rd = gri;
+
+ FOR_EACH_FIB_IP_PROTOCOL (fproto)
+ {
+ gx->gx_fib_index[fproto] =
+ gr->grd_fib_index[fib_proto_to_dpo (fproto)];
+ }
+
+ gx->gx_itf = gbp_itf_add_and_lock (sw_if_index, gb->gb_bd_index);
+ gbp_itf_set_l2_input_feature (gx->gx_itf, (gxi | GBP_EXT_ITF_ID),
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+
+ gbp_ext_itf_db[sw_if_index] = gxi;
+
+ GBP_EXT_ITF_DBG ("add: %U", format_gbp_ext_itf, gx);
+
+ return (0);
+ }
+
+ return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
+}
+
+int
+gbp_ext_itf_delete (u32 sw_if_index)
+{
+ gbp_ext_itf_t *gx;
+ index_t gxi;
+
+ gxi = gbp_ext_itf_db[sw_if_index];
+
+ if (INDEX_INVALID != gxi)
+ {
+ gx = pool_elt_at_index (gbp_ext_itf_pool, gxi);
+
+ GBP_EXT_ITF_DBG ("del: %U", format_gbp_ext_itf, gx);
+
+ gbp_itf_set_l2_input_feature (gx->gx_itf,
+ (gxi | GBP_EXT_ITF_ID),
+ L2INPUT_FEAT_NONE);
+ gbp_itf_unlock (gx->gx_itf);
+
+ gbp_route_domain_unlock (gx->gx_rd);
+ gbp_bridge_domain_unlock (gx->gx_bd);
+
+ gbp_ext_itf_db[sw_if_index] = INDEX_INVALID;
+ pool_put (gbp_ext_itf_pool, gx);
+
+ return (0);
+ }
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+}
+
+void
+gbp_ext_itf_walk (gbp_ext_itf_cb_t cb, void *ctx)
+{
+ gbp_ext_itf_t *ge;
+
+ /* *INDENT-OFF* */
+ pool_foreach(ge, gbp_ext_itf_pool,
+ {
+ if (!cb(ge, ctx))
+ break;
+ });
+ /* *INDENT-ON* */
+}
+
+static walk_rc_t
+gbp_ext_itf_show_one (gbp_ext_itf_t * gx, void *ctx)
+{
+ vlib_cli_output (ctx, " %U", format_gbp_ext_itf, gx);
+
+ return (WALK_CONTINUE);
+}
+
+static clib_error_t *
+gbp_ext_itf_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vlib_cli_output (vm, "External-Interfaces:");
+ gbp_ext_itf_walk (gbp_ext_itf_show_one, vm);
+
+ return (NULL);
+}
+
+/*?
+ * Show Group Based Policy external interface and derived information
+ *
+ * @cliexpar
+ * @cliexstart{show gbp ext-itf}
+ * @cliexend
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gbp_ext_itf_show_node, static) = {
+ .path = "show gbp ext-itf",
+ .short_help = "show gbp ext-itf\n",
+ .function = gbp_ext_itf_show,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+gbp_ext_itf_init (vlib_main_t * vm)
+{
+ gx_logger = vlib_log_register_class ("gbp", "ext-itf");
+
+ return (NULL);
+}
+
+VLIB_INIT_FUNCTION (gbp_ext_itf_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/gbp/gbp_ext_itf.h b/src/plugins/gbp/gbp_ext_itf.h
new file mode 100644
index 00000000000..dafcd08a2e4
--- /dev/null
+++ b/src/plugins/gbp/gbp_ext_itf.h
@@ -0,0 +1,81 @@
+/*
+ * 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_EXT_ITF_H__
+#define __GBP_EXT_ITF_H__
+
+#include <gbp/gbp.h>
+
+/**
+ * An external interface maps directly to an oflex L3ExternalInterface.
+ * The special characteristics of an external interface is the way the source
+ * EPG is determined for input packets which, like a recirc interface, is via
+ * a LPM.
+ */
+typedef struct gpb_ext_itf_t_
+{
+ /**
+ * The interface
+ */
+ u32 gx_itf;
+
+ /**
+ * The BD this external interface is a member of
+ */
+ index_t gx_bd;
+
+ /**
+ * The RD this external interface is a member of
+ */
+ index_t gx_rd;
+
+ /**
+ * cached FIB indices from the RD
+ */
+ u32 gx_fib_index[DPO_PROTO_NUM];
+
+} gbp_ext_itf_t;
+
+
+extern int gbp_ext_itf_add (u32 sw_if_index, u32 bd_id, u32 rd_id);
+extern int gbp_ext_itf_delete (u32 sw_if_index);
+
+extern u8 *format_gbp_ext_itf (u8 * s, va_list * args);
+
+typedef walk_rc_t (*gbp_ext_itf_cb_t) (gbp_ext_itf_t * gbpe, void *ctx);
+extern void gbp_ext_itf_walk (gbp_ext_itf_cb_t bgpe, void *ctx);
+
+
+/**
+ * Exposed types for the data-plane
+ */
+extern gbp_ext_itf_t *gbp_ext_itf_pool;
+extern index_t *gbp_ext_itf_db;
+
+always_inline gbp_ext_itf_t *
+gbp_ext_itf_get (u32 sw_if_index)
+{
+ return (pool_elt_at_index (gbp_ext_itf_pool, gbp_ext_itf_db[sw_if_index]));
+}
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/gbp/gbp_itf.c b/src/plugins/gbp/gbp_itf.c
index e1afdfb94dc..7cfe9da0ab0 100644
--- a/src/plugins/gbp/gbp_itf.c
+++ b/src/plugins/gbp/gbp_itf.c
@@ -196,9 +196,9 @@ format_gbp_itf (u8 * s, va_list * args)
s = format (s, "%U locks:%d input-feats:%U output-feats:%U",
format_vnet_sw_if_index_name, vnet_get_main (),
- gi->gi_sw_if_index, gi->gi_locks, format_l2_input_features, 0,
- gi->gi_l2_input_fb, format_l2_output_features, 0,
- gi->gi_l2_output_fb);
+ gi->gi_sw_if_index, gi->gi_locks,
+ format_l2_input_features, gi->gi_l2_input_fb, 0,
+ format_l2_output_features, gi->gi_l2_output_fb, 0);
return (s);
}
diff --git a/src/plugins/gbp/gbp_policy_dpo.c b/src/plugins/gbp/gbp_policy_dpo.c
index 7c53d1bcedb..523e23c4363 100644
--- a/src/plugins/gbp/gbp_policy_dpo.c
+++ b/src/plugins/gbp/gbp_policy_dpo.c
@@ -14,9 +14,6 @@
*/
#include <vnet/dpo/dvr_dpo.h>
-#include <vnet/fib/ip4_fib.h>
-#include <vnet/fib/ip6_fib.h>
-#include <vnet/dpo/load_balance.h>
#include <vnet/dpo/drop_dpo.h>
#include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
@@ -27,31 +24,19 @@
/**
* DPO pool
*/
-static gbp_policy_dpo_t *gbp_policy_dpo_pool;
+gbp_policy_dpo_t *gbp_policy_dpo_pool;
/**
* DPO type registered for these GBP FWD
*/
-static dpo_type_t gbp_policy_dpo_type;
-
-static inline gbp_policy_dpo_t *
-gbp_policy_dpo_get_i (index_t index)
-{
- return (pool_elt_at_index (gbp_policy_dpo_pool, index));
-}
-
-gbp_policy_dpo_t *
-gbp_policy_dpo_get (index_t index)
-{
- return (gbp_policy_dpo_get_i (index));
-}
+dpo_type_t gbp_policy_dpo_type;
static gbp_policy_dpo_t *
gbp_policy_dpo_alloc (void)
{
gbp_policy_dpo_t *gpd;
- pool_get_zero (gbp_policy_dpo_pool, gpd);
+ pool_get_aligned_zero (gbp_policy_dpo_pool, gpd, CLIB_CACHE_LINE_BYTES);
return (gpd);
}
@@ -61,7 +46,7 @@ gbp_policy_dpo_get_from_dpo (const dpo_id_t * dpo)
{
ASSERT (gbp_policy_dpo_type == dpo->dpoi_type);
- return (gbp_policy_dpo_get_i (dpo->dpoi_index));
+ return (gbp_policy_dpo_get (dpo->dpoi_index));
}
static inline index_t
@@ -138,7 +123,7 @@ format_gbp_policy_dpo (u8 * s, va_list * ap)
{
index_t index = va_arg (*ap, index_t);
u32 indent = va_arg (*ap, u32);
- gbp_policy_dpo_t *gpd = gbp_policy_dpo_get_i (index);
+ gbp_policy_dpo_t *gpd = gbp_policy_dpo_get (index);
vnet_main_t *vnm = vnet_get_main ();
s = format (s, "gbp-policy-dpo: %U, epg:%d out:%U",
@@ -293,8 +278,7 @@ gbp_policy_dpo_inline (vlib_main_t * vm,
b0 = vlib_get_buffer (vm, bi0);
gc0 = NULL;
- gpd0 =
- gbp_policy_dpo_get_i (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
+ gpd0 = gbp_policy_dpo_get (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
vnet_buffer (b0)->ip.adj_index[VLIB_TX] = gpd0->gpd_dpo.dpoi_index;
if (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A)
@@ -453,191 +437,6 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_policy_dpo_node, ip4_gbp_policy_dpo)
VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_policy_dpo_node, ip6_gbp_policy_dpo)
/* *INDENT-ON* */
- /**
- * per-packet trace data
- */
-typedef struct gbp_classify_trace_t_
-{
- /* per-pkt trace data */
- epg_id_t src_epg;
-} gbp_classify_trace_t;
-
-typedef enum gbp_lpm_classify_next_t_
-{
- GPB_LPM_CLASSIFY_DROP,
-} gbp_lpm_classify_next_t;
-
-/*
- * Determine the SRC EPG from a LPM
- */
-always_inline uword
-gbp_lpm_classify_inline (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame, fib_protocol_t fproto)
-{
- u32 n_left_from, *from, *to_next;
- u32 next_index;
-
- next_index = 0;
- n_left_from = frame->n_vectors;
- from = vlib_frame_vector_args (frame);
-
- while (n_left_from > 0)
- {
- u32 n_left_to_next;
-
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- u32 bi0, sw_if_index0, fib_index0, lbi0;
- gbp_lpm_classify_next_t next0;
- const gbp_policy_dpo_t *gpd0;
- const gbp_recirc_t *gr0;
- const dpo_id_t *dpo0;
- load_balance_t *lb0;
- ip4_header_t *ip4_0;
- ip6_header_t *ip6_0;
- vlib_buffer_t *b0;
- epg_id_t src_epg0;
-
- bi0 = from[0];
- to_next[0] = bi0;
- from += 1;
- to_next += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
- next0 = GPB_LPM_CLASSIFY_DROP;
-
- b0 = vlib_get_buffer (vm, bi0);
-
- sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
- gr0 = gbp_recirc_get (sw_if_index0);
- fib_index0 = gr0->gr_fib_index[fproto];
-
- if (FIB_PROTOCOL_IP4 == fproto)
- {
- ip4_0 = vlib_buffer_get_current (b0);
- lbi0 = ip4_fib_forwarding_lookup (fib_index0,
- &ip4_0->src_address);
- }
- else
- {
- ip6_0 = vlib_buffer_get_current (b0);
- lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
- &ip6_0->src_address);
- }
-
- lb0 = load_balance_get (lbi0);
- dpo0 = load_balance_get_bucket_i (lb0, 0);
-
- if (gbp_policy_dpo_type == dpo0->dpoi_type)
- {
- gpd0 = gbp_policy_dpo_get_i (dpo0->dpoi_index);
- src_epg0 = gpd0->gpd_epg;
- vnet_feature_next (&next0, b0);
- }
- else
- {
- /* could not classify => drop */
- src_epg0 = 0;
- }
-
- vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
-
- if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
- {
- gbp_classify_trace_t *t =
- vlib_add_trace (vm, node, b0, sizeof (*t));
- t->src_epg = src_epg0;
- }
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
- }
-
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
-
- return frame->n_vectors;
-}
-
-static uword
-gbp_ip4_lpm_classify (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- return (gbp_lpm_classify_inline (vm, node, frame, FIB_PROTOCOL_IP4));
-}
-
-static uword
-gbp_ip6_lpm_classify (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- return (gbp_lpm_classify_inline (vm, node, frame, FIB_PROTOCOL_IP6));
-}
-
- /* packet trace format function */
-static u8 *
-format_gbp_classify_trace (u8 * s, va_list * args)
-{
- CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
- CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
- gbp_classify_trace_t *t = va_arg (*args, gbp_classify_trace_t *);
-
- s = format (s, "src-epg:%d", t->src_epg);
-
- return s;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (gbp_ip4_lpm_classify_node) = {
- .function = gbp_ip4_lpm_classify,
- .name = "ip4-gbp-lpm-classify",
- .vector_size = sizeof (u32),
- .format_trace = format_gbp_classify_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_errors = 0,
- .n_next_nodes = 1,
- .next_nodes = {
- [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
- },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip4_lpm_classify_node, gbp_ip4_lpm_classify);
-
-VLIB_REGISTER_NODE (gbp_ip6_lpm_classify_node) = {
- .function = gbp_ip6_lpm_classify,
- .name = "ip6-gbp-lpm-classify",
- .vector_size = sizeof (u32),
- .format_trace = format_gbp_classify_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_errors = 0,
- .n_next_nodes = 1,
- .next_nodes = {
- [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
- },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip6_lpm_classify_node, gbp_ip6_lpm_classify);
-
-VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
-{
- .arc_name = "ip4-unicast",
- .node_name = "ip4-gbp-lpm-classify",
- .runs_before = VNET_FEATURES ("nat44-out2in"),
-};
-VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
-{
- .arc_name = "ip6-unicast",
- .node_name = "ip6-gbp-lpm-classify",
- .runs_before = VNET_FEATURES ("nat66-out2in"),
-};
-
-/* *INDENT-ON* */
-
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/plugins/gbp/gbp_policy_dpo.h b/src/plugins/gbp/gbp_policy_dpo.h
index 8ee086d1cb0..097205b8255 100644
--- a/src/plugins/gbp/gbp_policy_dpo.h
+++ b/src/plugins/gbp/gbp_policy_dpo.h
@@ -25,6 +25,8 @@
*/
typedef struct gbp_policy_dpo_t_
{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+
/**
* The protocol of packets using this DPO
*/
@@ -46,7 +48,7 @@ typedef struct gbp_policy_dpo_t_
u16 gpd_locks;
/**
- * Stacked DPO on DVR of output interface
+ * Stacked DPO on DVR/ADJ of output interface
*/
dpo_id_t gpd_dpo;
} gbp_policy_dpo_t;
@@ -55,14 +57,24 @@ extern void gbp_policy_dpo_add_or_lock (dpo_proto_t dproto,
epg_id_t epg,
u32 sw_if_index, dpo_id_t * dpo);
-extern gbp_policy_dpo_t *gbp_policy_dpo_get (index_t index);
-
extern dpo_type_t gbp_policy_dpo_get_type (void);
extern vlib_node_registration_t ip4_gbp_policy_dpo_node;
extern vlib_node_registration_t ip6_gbp_policy_dpo_node;
extern vlib_node_registration_t gbp_policy_port_node;
+/**
+ * Types exposed for the Data-plane
+ */
+extern dpo_type_t gbp_policy_dpo_type;
+extern gbp_policy_dpo_t *gbp_policy_dpo_pool;
+
+always_inline gbp_policy_dpo_t *
+gbp_policy_dpo_get (index_t index)
+{
+ return (pool_elt_at_index (gbp_policy_dpo_pool, index));
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/plugins/gbp/gbp_recirc.c b/src/plugins/gbp/gbp_recirc.c
index 59588eafacd..d907be01b3c 100644
--- a/src/plugins/gbp/gbp_recirc.c
+++ b/src/plugins/gbp/gbp_recirc.c
@@ -21,6 +21,8 @@
#include <vnet/dpo/dvr_dpo.h>
#include <vnet/fib/fib_table.h>
+#include <vlib/unix/plugin.h>
+
/**
* Pool of GBP recircs
*/
@@ -36,6 +38,12 @@ index_t *gbp_recirc_db;
*/
vlib_log_class_t gr_logger;
+/**
+ * L2 Emulation enable/disable symbols
+ */
+static void (*l2e_enable) (u32 sw_if_index);
+static void (*l2e_disable) (u32 sw_if_index);
+
#define GBP_RECIRC_DBG(...) \
vlib_log_debug (gr_logger, __VA_ARGS__);
@@ -72,8 +80,7 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
return (VNET_API_ERROR_NO_SUCH_ENTRY);
gbp_endpoint_group_lock (ggi);
- pool_get (gbp_recirc_pool, gr);
- clib_memset (gr, 0, sizeof (*gr));
+ pool_get_zero (gbp_recirc_pool, gr);
gri = gr - gbp_recirc_pool;
gr->gr_epg = epg_id;
@@ -94,7 +101,7 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
gg = gbp_endpoint_group_get (gr->gr_epgi);
FOR_EACH_FIB_IP_PROTOCOL (fproto)
{
- gr->gr_fib_index[fproto] =
+ gr->gr_fib_index[fib_proto_to_dpo (fproto)] =
gbp_endpoint_group_get_fib_index (gg, fproto);
}
@@ -104,6 +111,11 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
gr->gr_itf = gbp_itf_add_and_lock (gr->gr_sw_if_index, gg->gg_bd_index);
/*
+ * set the interface into L2 emulation mode
+ */
+ l2e_enable (gr->gr_sw_if_index);
+
+ /*
* Packets on the recirculation interface are subject to src-EPG
* classification. Recirc interfaces are L2-emulation mode.
* for internal EPGs this is via an LPM on all external subnets.
@@ -195,6 +207,7 @@ gbp_recirc_delete (u32 sw_if_index)
ip4_sw_interface_enable_disable (gr->gr_sw_if_index, 0);
ip6_sw_interface_enable_disable (gr->gr_sw_if_index, 0);
+ l2e_disable (gr->gr_sw_if_index);
gbp_itf_unlock (gr->gr_itf);
@@ -218,12 +231,12 @@ gbp_recirc_walk (gbp_recirc_cb_t cb, void *ctx)
/* *INDENT-ON* */
}
-static int
+static walk_rc_t
gbp_recirc_show_one (gbp_recirc_t * gr, void *ctx)
{
vlib_cli_output (ctx, " %U", format_gbp_recirc, gr);
- return (1);
+ return (WALK_CONTINUE);
}
static clib_error_t *
@@ -256,6 +269,11 @@ gbp_recirc_init (vlib_main_t * vm)
{
gr_logger = vlib_log_register_class ("gbp", "recirc");
+ l2e_enable =
+ vlib_get_plugin_symbol ("l2e_plugin.so", "l2_emulation_enable");
+ l2e_disable =
+ vlib_get_plugin_symbol ("l2e_plugin.so", "l2_emulation_disable");
+
return (NULL);
}
diff --git a/src/plugins/gbp/gbp_recirc.h b/src/plugins/gbp/gbp_recirc.h
index 1d1a88a396b..c577a5f3ea9 100644
--- a/src/plugins/gbp/gbp_recirc.h
+++ b/src/plugins/gbp/gbp_recirc.h
@@ -20,7 +20,10 @@
#include <vnet/fib/fib_types.h>
/**
- * An Endpoint Group representation
+ * A GBP recirculation interface representation
+ * Thes interfaces join Bridge domains that are internal to those that are
+ * NAT external, so the packets can be NAT translated and then undergo the
+ * whole policy process again.
*/
typedef struct gpb_recirc_t_
{
@@ -37,7 +40,7 @@ typedef struct gpb_recirc_t_
/**
* FIB indices the EPG is mapped to
*/
- u32 gr_fib_index[FIB_PROTOCOL_IP_MAX];
+ u32 gr_fib_index[DPO_PROTO_NUM];
/**
* Is the interface for packets post-NAT translation (i.e. ext)
@@ -59,7 +62,7 @@ typedef struct gpb_recirc_t_
extern int gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext);
extern void gbp_recirc_delete (u32 sw_if_index);
-typedef int (*gbp_recirc_cb_t) (gbp_recirc_t * gbpe, void *ctx);
+typedef walk_rc_t (*gbp_recirc_cb_t) (gbp_recirc_t * gbpe, void *ctx);
extern void gbp_recirc_walk (gbp_recirc_cb_t bgpe, void *ctx);
/**
diff --git a/src/plugins/gbp/gbp_route_domain.c b/src/plugins/gbp/gbp_route_domain.c
index df3959edca6..67b6915b463 100644
--- a/src/plugins/gbp/gbp_route_domain.c
+++ b/src/plugins/gbp/gbp_route_domain.c
@@ -231,6 +231,16 @@ gbp_route_domain_unlock (index_t index)
}
}
+u32
+gbp_route_domain_get_rd_id (index_t grdi)
+{
+ gbp_route_domain_t *grd;
+
+ grd = gbp_route_domain_get (grdi);
+
+ return (grd->grd_id);
+}
+
int
gbp_route_domain_delete (u32 rd_id)
{
diff --git a/src/plugins/gbp/gbp_route_domain.h b/src/plugins/gbp/gbp_route_domain.h
index ba5d5e49aca..b83d598ad38 100644
--- a/src/plugins/gbp/gbp_route_domain.h
+++ b/src/plugins/gbp/gbp_route_domain.h
@@ -66,6 +66,7 @@ extern index_t gbp_route_domain_index (const gbp_route_domain_t *);
extern int gbp_route_domain_delete (u32 rd_id);
extern gbp_route_domain_t *gbp_route_domain_get (index_t i);
+extern u32 gbp_route_domain_get_rd_id (index_t i);
typedef int (*gbp_route_domain_cb_t) (gbp_route_domain_t * gb, void *ctx);
extern void gbp_route_domain_walk (gbp_route_domain_cb_t bgpe, void *ctx);
diff --git a/src/plugins/gbp/gbp_scanner.c b/src/plugins/gbp/gbp_scanner.c
index a2d0c9a98cb..90507a60568 100644
--- a/src/plugins/gbp/gbp_scanner.c
+++ b/src/plugins/gbp/gbp_scanner.c
@@ -19,8 +19,16 @@
#include <plugins/gbp/gbp_endpoint.h>
#include <plugins/gbp/gbp_vxlan.h>
+/**
+ * Scanner logger
+ */
vlib_log_class_t gs_logger;
+/**
+ * Scanner state
+ */
+static bool gs_enabled;
+
#define GBP_SCANNER_DBG(...) \
vlib_log_debug (gs_logger, __VA_ARGS__);
@@ -28,13 +36,13 @@ static uword
gbp_scanner (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
{
uword event_type, *event_data = 0;
- bool enabled = 0, do_scan = 0;
+ bool do_scan = 0;
while (1)
{
do_scan = 0;
- if (enabled)
+ if (gs_enabled)
{
/* scan every 'inactive threshold' seconds */
vlib_process_wait_for_event_or_clock (vm,
@@ -55,11 +63,14 @@ gbp_scanner (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
break;
case GBP_ENDPOINT_SCAN_START:
- enabled = 1;
+ gs_enabled = 1;
break;
case GBP_ENDPOINT_SCAN_STOP:
- enabled = 0;
+ gs_enabled = 0;
+ break;
+
+ case GBP_ENDPOINT_SCAN_SET_TIME:
break;
default:
@@ -84,6 +95,30 @@ VLIB_REGISTER_NODE (gbp_scanner_node) = {
};
/* *INDENT-ON* */
+static clib_error_t *
+gbp_scanner_cli (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vlib_cli_output (vm, "GBP-scanner: enabled:%d interval:%f",
+ gs_enabled, gbp_endpoint_scan_threshold ());
+
+ return (NULL);
+}
+
+/*?
+ * Show GBP scanner
+ *
+ * @cliexpar
+ * @cliexstart{show gbp scanner}
+ * @cliexend
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gbp_scanner_cli_node, static) = {
+ .path = "show gbp scanner",
+ .short_help = "show gbp scanner",
+ .function = gbp_scanner_cli,
+};
+/* *INDENT-ON* */
static clib_error_t *
gbp_scanner_init (vlib_main_t * vm)
diff --git a/src/plugins/gbp/gbp_scanner.h b/src/plugins/gbp/gbp_scanner.h
index 070da3892ca..1133167d927 100644
--- a/src/plugins/gbp/gbp_scanner.h
+++ b/src/plugins/gbp/gbp_scanner.h
@@ -22,8 +22,7 @@ typedef enum gbp_scan_event_t_
{
GBP_ENDPOINT_SCAN_START,
GBP_ENDPOINT_SCAN_STOP,
- GBP_VXLAN_SCAN_START,
- GBP_VXLAN_SCAN_STOP,
+ GBP_ENDPOINT_SCAN_SET_TIME,
} gbp_scan_event_t;
extern vlib_node_registration_t gbp_scanner_node;
diff --git a/src/plugins/gbp/gbp_subnet.c b/src/plugins/gbp/gbp_subnet.c
index d9d42997aa7..b0b6db8040e 100644
--- a/src/plugins/gbp/gbp_subnet.c
+++ b/src/plugins/gbp/gbp_subnet.c
@@ -46,7 +46,13 @@ typedef struct gbp_subnet_t_
epg_id_t gs_epg;
u32 gs_sw_if_index;
} gs_stitched_external;
+ struct
+ {
+ epg_id_t gs_epg;
+ } gs_l3_out;
};
+
+ fib_node_index_t gs_fei;
} gbp_subnet_t;
/**
@@ -102,7 +108,7 @@ gbp_subnet_db_del (gbp_subnet_t * gs)
static int
-gbp_subnet_transport_add (const gbp_subnet_t * gs)
+gbp_subnet_transport_add (gbp_subnet_t * gs)
{
dpo_id_t gfd = DPO_INVALID;
gbp_route_domain_t *grd;
@@ -111,14 +117,15 @@ gbp_subnet_transport_add (const gbp_subnet_t * gs)
fproto = gs->gs_key->gsk_pfx.fp_proto;
grd = gbp_route_domain_get (gs->gs_rd);
- fib_table_entry_update_one_path (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx,
- FIB_SOURCE_PLUGIN_HI,
- FIB_ENTRY_FLAG_NONE,
- fib_proto_to_dpo (fproto),
- &ADJ_BCAST_ADDR,
- grd->grd_uu_sw_if_index[fproto],
- ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
+ gs->gs_fei = fib_table_entry_update_one_path (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_PLUGIN_HI,
+ FIB_ENTRY_FLAG_NONE,
+ fib_proto_to_dpo (fproto),
+ &ADJ_BCAST_ADDR,
+ grd->grd_uu_sw_if_index
+ [fproto], ~0, 1, NULL,
+ FIB_ROUTE_PATH_FLAG_NONE);
dpo_reset (&gfd);
@@ -126,17 +133,18 @@ gbp_subnet_transport_add (const gbp_subnet_t * gs)
}
static int
-gbp_subnet_internal_add (const gbp_subnet_t * gs)
+gbp_subnet_internal_add (gbp_subnet_t * gs)
{
dpo_id_t gfd = DPO_INVALID;
gbp_fwd_dpo_add_or_lock (fib_proto_to_dpo (gs->gs_key->gsk_pfx.fp_proto),
&gfd);
- fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx,
- FIB_SOURCE_PLUGIN_HI,
- FIB_ENTRY_FLAG_EXCLUSIVE, &gfd);
+ gs->gs_fei = fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_PLUGIN_HI,
+ FIB_ENTRY_FLAG_EXCLUSIVE,
+ &gfd);
dpo_reset (&gfd);
@@ -155,12 +163,33 @@ gbp_subnet_external_add (gbp_subnet_t * gs, u32 sw_if_index, epg_id_t epg)
gs->gs_stitched_external.gs_epg,
gs->gs_stitched_external.gs_sw_if_index, &gpd);
- fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx,
- FIB_SOURCE_PLUGIN_HI,
- (FIB_ENTRY_FLAG_EXCLUSIVE |
- FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
- &gpd);
+ gs->gs_fei = fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_PLUGIN_HI,
+ (FIB_ENTRY_FLAG_EXCLUSIVE |
+ FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
+ &gpd);
+
+ dpo_reset (&gpd);
+
+ return (0);
+}
+
+static int
+gbp_subnet_l3_out_add (gbp_subnet_t * gs, u32 sw_if_index, epg_id_t epg)
+{
+ dpo_id_t gpd = DPO_INVALID;
+
+ gs->gs_l3_out.gs_epg = epg;
+
+ gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (gs->gs_key->gsk_pfx.fp_proto),
+ gs->gs_l3_out.gs_epg, ~0, &gpd);
+
+ gs->gs_fei = fib_table_entry_special_dpo_add (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_SPECIAL,
+ FIB_ENTRY_FLAG_INTERPOSE,
+ &gpd);
dpo_reset (&gpd);
@@ -190,7 +219,10 @@ gbp_subnet_del (u32 rd_id, const fib_prefix_t * pfx)
gs = pool_elt_at_index (gbp_subnet_pool, gsi);
- fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_PLUGIN_HI);
+ if (GBP_SUBNET_L3_OUT == gs->gs_type)
+ fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_SPECIAL);
+ else
+ fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_PLUGIN_HI);
gbp_subnet_db_del (gs);
gbp_route_domain_unlock (gs->gs_rd);
@@ -243,6 +275,9 @@ gbp_subnet_add (u32 rd_id,
case GBP_SUBNET_TRANSPORT:
rv = gbp_subnet_transport_add (gs);
break;
+ case GBP_SUBNET_L3_OUT:
+ rv = gbp_subnet_l3_out_add (gs, sw_if_index, epg);
+ break;
}
return (rv);
@@ -274,10 +309,13 @@ gbp_subnet_walk (gbp_subnet_cb_t cb, void *ctx)
sw_if_index = gs->gs_stitched_external.gs_sw_if_index;
epg = gs->gs_stitched_external.gs_epg;
break;
+ case GBP_SUBNET_L3_OUT:
+ epg = gs->gs_l3_out.gs_epg;
+ break;
}
if (WALK_STOP == cb (grd->grd_id, &gs->gs_key->gsk_pfx,
- gs->gs_type, epg, sw_if_index, ctx))
+ gs->gs_type, sw_if_index, epg, ctx))
break;
}));
/* *INDENT-ON* */
@@ -302,6 +340,8 @@ format_gbp_subnet_type (u8 * s, va_list * args)
return (format (s, "stitched-external"));
case GBP_SUBNET_TRANSPORT:
return (format (s, "transport"));
+ case GBP_SUBNET_L3_OUT:
+ return (format (s, "l3-out"));
}
return (format (s, "unknown"));
@@ -334,20 +374,17 @@ format_gbp_subnet (u8 * s, va_list * args)
format_vnet_sw_if_index_name,
vnet_get_main (), gs->gs_stitched_external.gs_sw_if_index);
break;
+ case GBP_SUBNET_L3_OUT:
+ s = format (s, " {epg:%d}", gs->gs_l3_out.gs_epg);
+ break;
}
switch (flags)
{
case GBP_SUBNET_SHOW_DETAILS:
{
- fib_node_index_t fei;
-
- fei = fib_table_lookup_exact_match (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx);
-
- s =
- format (s, "\n %U", format_fib_entry, fei,
- FIB_ENTRY_FORMAT_DETAIL);
+ s = format (s, "\n %U", format_fib_entry, gs->gs_fei,
+ FIB_ENTRY_FORMAT_DETAIL);
}
case GBP_SUBNET_SHOW_BRIEF:
break;
diff --git a/src/plugins/gbp/gbp_subnet.h b/src/plugins/gbp/gbp_subnet.h
index b6906dee674..5fbd4b23df0 100644
--- a/src/plugins/gbp/gbp_subnet.h
+++ b/src/plugins/gbp/gbp_subnet.h
@@ -23,6 +23,7 @@ typedef enum gbp_subnet_type_t_
GBP_SUBNET_TRANSPORT,
GBP_SUBNET_STITCHED_INTERNAL,
GBP_SUBNET_STITCHED_EXTERNAL,
+ GBP_SUBNET_L3_OUT,
} gbp_subnet_type_t;
extern int gbp_subnet_add (u32 rd_id,
diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h
index 4a5cf6c8748..93da1277e67 100644
--- a/src/vnet/l2/l2_input.h
+++ b/src/vnet/l2/l2_input.h
@@ -113,6 +113,7 @@ l2input_bd_config (u32 bd_index)
_(GBP_LEARN, "gbp-learn-l2") \
_(GBP_NULL_CLASSIFY, "gbp-null-classify") \
_(GBP_SRC_CLASSIFY, "gbp-src-classify") \
+ _(GBP_LPM_CLASSIFY, "l2-gbp-lpm-classify") \
_(VTR, "l2-input-vtr") \
_(L2_IP_QOS_RECORD, "l2-ip-qos-record") \
_(VPATH, "vpath-input-l2") \
diff --git a/test/test_gbp.py b/test/test_gbp.py
index 68bbfe4a7c9..4a5969213be 100644
--- a/test/test_gbp.py
+++ b/test/test_gbp.py
@@ -196,6 +196,46 @@ class VppGbpRecirc(VppObject):
return False
+class VppGbpExtItf(VppObject):
+ """
+ GBP ExtItfulation Interface
+ """
+
+ def __init__(self, test, itf, bd, rd):
+ self._test = test
+ self.itf = itf
+ self.bd = bd
+ self.rd = rd
+
+ def add_vpp_config(self):
+ self._test.vapi.gbp_ext_itf_add_del(
+ 1,
+ self.itf.sw_if_index,
+ self.bd.bd_id,
+ self.rd.rd_id)
+ self._test.registry.register(self, self._test.logger)
+
+ def remove_vpp_config(self):
+ self._test.vapi.gbp_ext_itf_add_del(
+ 0,
+ self.itf.sw_if_index,
+ self.bd.bd_id,
+ self.rd.rd_id)
+
+ def __str__(self):
+ return self.object_id()
+
+ def object_id(self):
+ return "gbp-ext-itf:[%d]" % (self.itf.sw_if_index)
+
+ def query_vpp_config(self):
+ rs = self._test.vapi.gbp_ext_itf_dump()
+ for r in rs:
+ if r.ext_itf.sw_if_index == self.itf.sw_if_index:
+ return True
+ return False
+
+
class VppGbpSubnet(VppObject):
"""
GBP Subnet
@@ -650,6 +690,8 @@ class TestGBP(VppTestCase):
def test_gbp(self):
""" Group Based Policy """
+ ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
+
#
# Bridge Domains
#
@@ -794,8 +836,6 @@ class TestGBP(VppTestCase):
VppIpInterfaceBind(self, recirc.recirc,
recirc.epg.rd.t6).add_vpp_config()
- self.vapi.sw_interface_set_l2_emulation(
- recirc.recirc.sw_if_index)
self.vapi.nat44_interface_add_del_feature(
recirc.recirc.sw_if_index,
is_inside=0,
@@ -1375,8 +1415,6 @@ class TestGBP(VppTestCase):
is_add=0)
for recirc in recircs:
- self.vapi.sw_interface_set_l2_emulation(
- recirc.recirc.sw_if_index, enable=0)
self.vapi.nat44_interface_add_del_feature(
recirc.recirc.sw_if_index,
is_inside=0,
@@ -1389,6 +1427,7 @@ class TestGBP(VppTestCase):
def test_gbp_learn_l2(self):
""" GBP L2 Endpoint Learning """
+ ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
learnt = [{'mac': '00:00:11:11:11:01',
'ip': '10.0.0.1',
'ip6': '2001:10::2'},
@@ -1550,13 +1589,8 @@ class TestGBP(VppTestCase):
self.sleep(2)
for l in learnt:
self.assertFalse(find_gbp_endpoint(self,
- tep1_sw_if_index,
mac=l['mac']))
- self.logger.info(self.vapi.cli("show gbp endpoint"))
- self.logger.info(self.vapi.cli("show gbp vxlan"))
- self.logger.info(self.vapi.cli("show vxlan-gbp tunnel"))
-
#
# repeat. the do not learn bit is set so the EPs are not learnt
#
@@ -1791,6 +1825,7 @@ class TestGBP(VppTestCase):
def test_gbp_learn_vlan_l2(self):
""" GBP L2 Endpoint w/ VLANs"""
+ ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
learnt = [{'mac': '00:00:11:11:11:01',
'ip': '10.0.0.1',
'ip6': '2001:10::2'},
@@ -1960,6 +1995,7 @@ class TestGBP(VppTestCase):
self.vapi.cli("set logging class gbp debug")
+ ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
routed_dst_mac = "00:0c:0c:0c:0c:0c"
routed_src_mac = "00:22:bd:f8:19:ff"
@@ -2218,7 +2254,7 @@ class TestGBP(VppTestCase):
#
# Add a route to static EP's v4 and v6 subnet
- # packets should be send on the v4/v6 uu=fwd interface resp.
+ # packets should be sent on the v4/v6 uu=fwd interface resp.
#
se_10_24 = VppGbpSubnet(
self, rd1, "10.0.0.0", 24,
@@ -2283,7 +2319,7 @@ class TestGBP(VppTestCase):
epg_220, None,
"10.0.0.88", "11.0.0.88",
"2001:10::88", "3001::88",
- VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
+ ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
self.pg2.local_ip4,
self.pg2.remote_hosts[1].ip4,
mac=None)
@@ -2296,7 +2332,7 @@ class TestGBP(VppTestCase):
epg_220, None,
learnt[0]['ip'], "11.0.0.101",
learnt[0]['ip6'], "3001::101",
- VppEnum.vl_api_gbp_endpoint_flags_t.REMOTE,
+ ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
self.pg2.local_ip4,
self.pg2.remote_hosts[1].ip4,
mac=None)
@@ -2407,6 +2443,7 @@ class TestGBP(VppTestCase):
self.vapi.cli("set logging class gbp debug")
+ ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
routed_dst_mac = "00:0c:0c:0c:0c:0c"
routed_src_mac = "00:22:bd:f8:19:ff"
@@ -2960,6 +2997,304 @@ class TestGBP(VppTestCase):
self.assertEqual(rx[IPv6].src, ep1.ip6.address)
self.assertEqual(rx[IPv6].dst, "2001:10::88")
+ #
+ # cleanup
+ #
+ self.pg7.unconfig_ip4()
+
+ def test_gbp_l3_out(self):
+ """ GBP L3 Out """
+
+ ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t
+ self.vapi.cli("set logging class gbp debug")
+
+ routed_dst_mac = "00:0c:0c:0c:0c:0c"
+ routed_src_mac = "00:22:bd:f8:19:ff"
+
+ #
+ # IP tables
+ #
+ t4 = VppIpTable(self, 1)
+ t4.add_vpp_config()
+ t6 = VppIpTable(self, 1, True)
+ t6.add_vpp_config()
+
+ rd1 = VppGbpRouteDomain(self, 2, t4, t6)
+ rd1.add_vpp_config()
+
+ self.loop0.set_mac(self.router_mac.address)
+
+ #
+ # Bind the BVI to the RD
+ #
+ VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config()
+ VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config()
+
+ #
+ # Pg7 hosts a BD's BUM
+ # Pg1 some other l3 interface
+ #
+ self.pg7.config_ip4()
+ self.pg7.resolve_arp()
+
+ #
+ # a GBP external bridge domains for the EPs
+ #
+ bd1 = VppBridgeDomain(self, 1)
+ bd1.add_vpp_config()
+ gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
+ gbd1.add_vpp_config()
+
+ #
+ # The Endpoint-groups in which the external endpoints exist
+ #
+ epg_220 = VppGbpEndpointGroup(self, 220, rd1, gbd1,
+ None, gbd1.bvi,
+ "10.0.0.128",
+ "2001:10::128")
+ epg_220.add_vpp_config()
+
+ # the BVIs have the subnets applied ...
+ ip4_addr = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 24)
+ ip4_addr.add_vpp_config()
+ ip6_addr = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 64)
+ ip6_addr.add_vpp_config()
+
+ # ... which are L3-out subnets
+ l3o_1 = VppGbpSubnet(
+ self, rd1, "10.0.0.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
+ epg=200)
+ l3o_1.add_vpp_config()
+
+ #
+ # an external interface attached to the outside world and the
+ # external BD
+ #
+ vlan_100 = VppDot1QSubint(self, self.pg0, 100)
+ vlan_100.admin_up()
+ ext_itf = VppGbpExtItf(self, vlan_100, bd1, rd1)
+ ext_itf.add_vpp_config()
+
+ #
+ # a multicast vxlan-gbp tunnel for broadcast in the BD
+ #
+ tun_bm = VppVxlanGbpTunnel(self, self.pg7.local_ip4,
+ "239.1.1.1", 88,
+ mcast_itf=self.pg7)
+ tun_bm.add_vpp_config()
+ bp_bm = VppBridgeDomainPort(self, bd1, tun_bm,
+ port_type=L2_PORT_TYPE.NORMAL)
+ bp_bm.add_vpp_config()
+
+ #
+ # an unicast vxlan-gbp for inter-BD traffic
+ #
+ vx_tun_l3 = VppGbpVxlanTunnel(
+ self, 444, rd1.rd_id,
+ VppEnum.vl_api_gbp_vxlan_tunnel_mode_t.GBP_VXLAN_TUNNEL_MODE_L3)
+ vx_tun_l3.add_vpp_config()
+
+ #
+ # packets destined to unkown addresses in the BVI's subnet
+ # are ARP'd for
+ #
+ p4 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ Dot1Q(vlan=100) /
+ IP(src="10.0.0.1", dst="10.0.0.88") /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+ p6 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ Dot1Q(vlan=100) /
+ IPv6(src="2001:10::1", dst="2001:10::88") /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
+
+ for rx in rxs:
+ self.assertEqual(rx[Ether].src, self.pg7.local_mac)
+ # self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
+ self.assertEqual(rx[IP].src, self.pg7.local_ip4)
+ self.assertEqual(rx[IP].dst, "239.1.1.1")
+ self.assertEqual(rx[VXLAN].vni, 88)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ # policy is not applied since we don't know where it's going
+ self.assertFalse(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ inner = rx[VXLAN].payload
+
+ self.assertTrue(inner.haslayer(ARP))
+
+ #
+ # An external Endpoint
+ #
+ eep = VppGbpEndpoint(self, vlan_100,
+ epg_220, None,
+ "10.0.0.1", "11.0.0.1",
+ "2001:10::1", "3001::1",
+ ep_flags.GBP_API_ENDPOINT_FLAG_EXTERNAL)
+ eep.add_vpp_config()
+
+ #
+ # A remote endpoint
+ #
+ rep = VppGbpEndpoint(self, vx_tun_l3,
+ epg_220, None,
+ "10.0.0.101", "11.0.0.101",
+ "2001:10::101", "3001::101",
+ ep_flags.GBP_API_ENDPOINT_FLAG_REMOTE,
+ self.pg7.local_ip4,
+ self.pg7.remote_ip4,
+ mac=None)
+ rep.add_vpp_config()
+
+ #
+ # remote to external
+ #
+ p = (Ether(src=self.pg7.remote_mac,
+ dst=self.pg7.local_mac) /
+ IP(src=self.pg7.remote_ip4,
+ dst=self.pg7.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=444, gpid=220, flags=0x88) /
+ Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ IP(src="10.0.0.101", dst="10.0.0.1") /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
+
+ #
+ # A subnet reachable through the external EP
+ #
+ ip_220 = VppIpRoute(self, "10.220.0.0", 24,
+ [VppRoutePath(eep.ip4.address,
+ eep.epg.bvi.sw_if_index)],
+ table_id=t4.table_id)
+ ip_220.add_vpp_config()
+
+ l3o_220 = VppGbpSubnet(
+ self, rd1, "10.220.0.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
+ epg=220)
+ l3o_220.add_vpp_config()
+
+ p = (Ether(src=self.pg7.remote_mac,
+ dst=self.pg7.local_mac) /
+ IP(src=self.pg7.remote_ip4,
+ dst=self.pg7.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=444, gpid=220, flags=0x88) /
+ Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ IP(src="10.0.0.101", dst="10.220.0.1") /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg7, p * 1, self.pg0)
+
+ #
+ # another external subnet, this time in a different EPG
+ #
+ ip_200 = VppIpRoute(self, "10.200.0.0", 24,
+ [VppRoutePath(eep.ip4.address,
+ eep.epg.bvi.sw_if_index)],
+ table_id=t4.table_id)
+ ip_200.add_vpp_config()
+
+ l3o_200 = VppGbpSubnet(
+ self, rd1, "10.200.0.0", 24,
+ VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_L3_OUT,
+ epg=200)
+ l3o_200.add_vpp_config()
+
+ p = (Ether(src=self.pg7.remote_mac,
+ dst=self.pg7.local_mac) /
+ IP(src=self.pg7.remote_ip4,
+ dst=self.pg7.local_ip4) /
+ UDP(sport=1234, dport=48879) /
+ VXLAN(vni=444, gpid=220, flags=0x88) /
+ Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ IP(src="10.0.0.101", dst="10.200.0.1") /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ #
+ # packets dropped due to lack of contract.
+ #
+ rxs = self.send_and_assert_no_replies(self.pg7, p * 1)
+
+ #
+ # from the the subnet in EPG 220 beyond the external to remote
+ #
+ p4 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ Dot1Q(vlan=100) /
+ IP(src="10.220.0.1", dst=rep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
+
+ for rx in rxs:
+ self.assertEqual(rx[Ether].src, self.pg7.local_mac)
+ self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
+ self.assertEqual(rx[IP].src, self.pg7.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
+ self.assertEqual(rx[VXLAN].vni, 444)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ self.assertTrue(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ #
+ # from the the subnet in EPG 200 beyond the external to remote
+ # dropped due to no contract
+ #
+ p4 = (Ether(src=self.pg0.remote_mac, dst=self.router_mac.address) /
+ Dot1Q(vlan=100) /
+ IP(src="10.200.0.1", dst=rep.ip4.address) /
+ UDP(sport=1234, dport=1234) /
+ Raw('\xa5' * 100))
+
+ rxs = self.send_and_assert_no_replies(self.pg0, p4 * 1)
+
+ #
+ # add a contract
+ #
+ acl = VppGbpAcl(self)
+ rule = acl.create_rule(permit_deny=1, proto=17)
+ rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
+ acl_index = acl.add_vpp_config([rule, rule2])
+ c1 = VppGbpContract(
+ self, 200, 220, acl_index,
+ [VppGbpContractRule(
+ VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+ []),
+ VppGbpContractRule(
+ VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+ [])])
+ c1.add_vpp_config()
+
+ rxs = self.send_and_expect(self.pg0, p4 * 1, self.pg7)
+
+ for rx in rxs:
+ self.assertEqual(rx[Ether].src, self.pg7.local_mac)
+ self.assertEqual(rx[Ether].dst, self.pg7.remote_mac)
+ self.assertEqual(rx[IP].src, self.pg7.local_ip4)
+ self.assertEqual(rx[IP].dst, self.pg7.remote_ip4)
+ self.assertEqual(rx[VXLAN].vni, 444)
+ self.assertTrue(rx[VXLAN].flags.G)
+ self.assertTrue(rx[VXLAN].flags.Instance)
+ self.assertTrue(rx[VXLAN].gpflags.A)
+ self.assertFalse(rx[VXLAN].gpflags.D)
+
+ #
+ # cleanup
+ #
+ self.pg7.unconfig_ip4()
+
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 662732ffb30..370758764df 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -3624,6 +3624,19 @@ class VppPapiProvider(object):
""" GBP recirc Dump """
return self.api(self.papi.gbp_recirc_dump, {})
+ def gbp_ext_itf_add_del(self, is_add, sw_if_index, bd_id, rd_id):
+ """ GBP recirc Add/Del """
+ return self.api(self.papi.gbp_ext_itf_add_del,
+ {'is_add': is_add,
+ 'ext_itf': {
+ 'sw_if_index': sw_if_index,
+ 'bd_id': bd_id,
+ 'rd_id': rd_id}})
+
+ def gbp_ext_itf_dump(self):
+ """ GBP recirc Dump """
+ return self.api(self.papi.gbp_ext_itf_dump, {})
+
def gbp_subnet_add_del(self, is_add, rd_id,
prefix, type,
sw_if_index=0xffffffff,