aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extras/vom/vom/CMakeLists.txt2
-rw-r--r--extras/vom/vom/gbp_contract.cpp48
-rw-r--r--extras/vom/vom/gbp_contract.hpp16
-rw-r--r--extras/vom/vom/gbp_contract_cmds.cpp50
-rw-r--r--extras/vom/vom/gbp_contract_cmds.hpp8
-rw-r--r--extras/vom/vom/gbp_rule.cpp221
-rw-r--r--extras/vom/vom/gbp_rule.hpp281
-rw-r--r--src/plugins/gbp/gbp.api1
-rw-r--r--src/plugins/gbp/gbp_api.c3
-rw-r--r--src/plugins/gbp/gbp_contract.h3
10 files changed, 619 insertions, 14 deletions
diff --git a/extras/vom/vom/CMakeLists.txt b/extras/vom/vom/CMakeLists.txt
index 82c221130f6..7413df8d834 100644
--- a/extras/vom/vom/CMakeLists.txt
+++ b/extras/vom/vom/CMakeLists.txt
@@ -80,6 +80,7 @@ if(GBP_FILE)
gbp_recirc.cpp
gbp_route_domain_cmds.cpp
gbp_route_domain.cpp
+ gbp_rule.cpp
gbp_subnet_cmds.cpp
gbp_subnet.cpp
gbp_vxlan.cpp
@@ -197,6 +198,7 @@ if(GBP_FILE)
gbp_endpoint_group.hpp
gbp_recirc.hpp
gbp_route_domain.hpp
+ gbp_rule.hpp
gbp_subnet.hpp
gbp_vxlan.hpp
)
diff --git a/extras/vom/vom/gbp_contract.cpp b/extras/vom/vom/gbp_contract.cpp
index 8b27269249c..87b5ed8ff0a 100644
--- a/extras/vom/vom/gbp_contract.cpp
+++ b/extras/vom/vom/gbp_contract.cpp
@@ -14,6 +14,7 @@
*/
#include "vom/gbp_contract.hpp"
+#include "vom/api_types.hpp"
#include "vom/gbp_contract_cmds.hpp"
#include "vom/singular_db_funcs.hpp"
@@ -76,7 +77,7 @@ gbp_contract::replay()
{
if (m_hw) {
HW::enqueue(new gbp_contract_cmds::create_cmd(
- m_hw, m_src_epg_id, m_dst_epg_id, m_acl->handle()));
+ m_hw, m_src_epg_id, m_dst_epg_id, m_acl->handle(), m_gbp_rules));
}
}
@@ -85,20 +86,34 @@ gbp_contract::to_string() const
{
std::ostringstream s;
s << "gbp-contract:[{" << m_src_epg_id << ", " << m_dst_epg_id << "}, "
- << m_acl->to_string() << "]";
+ << m_acl->to_string();
+ if (m_gbp_rules.size()) {
+ auto it = m_gbp_rules.cbegin();
+ while (it != m_gbp_rules.cend()) {
+ s << it->to_string();
+ ++it;
+ }
+ }
+ s << "]";
return (s.str());
}
void
+gbp_contract::set_gbp_rules(const gbp_contract::gbp_rules_t& gbp_rules)
+{
+ m_gbp_rules = gbp_rules;
+}
+
+void
gbp_contract::update(const gbp_contract& r)
{
/*
- * create the table if it is not yet created
- */
+ * create the table if it is not yet created
+ */
if (rc_t::OK != m_hw.rc()) {
HW::enqueue(new gbp_contract_cmds::create_cmd(
- m_hw, m_src_epg_id, m_dst_epg_id, m_acl->handle()));
+ m_hw, m_src_epg_id, m_dst_epg_id, m_acl->handle(), m_gbp_rules));
}
}
@@ -157,7 +172,28 @@ gbp_contract::event_handler::handle_populate(const client_db::key_t& key)
gbp_contract gbpc(payload.contract.src_epg, payload.contract.dst_epg,
*acl);
OM::commit(key, gbpc);
-
+ if (payload.contract.n_rules) {
+ gbp_contract::gbp_rules_t rules;
+ for (u8 i = 0; i < payload.contract.n_rules; i++) {
+ const gbp_rule::action_t action =
+ gbp_rule::action_t::from_int(payload.contract.rules[i].action);
+ const gbp_rule::hash_mode_t hm = gbp_rule::hash_mode_t::from_int(
+ payload.contract.rules[i].nh_set.hash_mode);
+ gbp_rule::next_hops_t nhs;
+ for (u8 j = 0; j < payload.contract.rules[i].nh_set.n_nhs; j++) {
+ gbp_rule::next_hop_t nh(
+ from_api(payload.contract.rules[i].nh_set.nhs[j].ip),
+ from_api(payload.contract.rules[i].nh_set.nhs[j].mac),
+ payload.contract.rules[i].nh_set.nhs[j].bd_id,
+ payload.contract.rules[i].nh_set.nhs[j].rd_id);
+ nhs.insert(nh);
+ }
+ gbp_rule::next_hop_set_t next_hop_set(hm, nhs);
+ gbp_rule gr(i, next_hop_set, action);
+ rules.insert(gr);
+ }
+ gbpc.set_gbp_rules(rules);
+ }
VOM_LOG(log_level_t::DEBUG) << "read: " << gbpc.to_string();
}
}
diff --git a/extras/vom/vom/gbp_contract.hpp b/extras/vom/vom/gbp_contract.hpp
index 7a0696de7b3..53f8f3659ec 100644
--- a/extras/vom/vom/gbp_contract.hpp
+++ b/extras/vom/vom/gbp_contract.hpp
@@ -18,6 +18,7 @@
#include "vom/acl_list.hpp"
#include "vom/gbp_endpoint.hpp"
+#include "vom/gbp_rule.hpp"
#include "vom/interface.hpp"
#include "vom/singular_db.hpp"
#include "vom/types.hpp"
@@ -31,6 +32,11 @@ class gbp_contract : public object_base
{
public:
/**
+ * set of gbp rules
+ */
+ typedef std::set<gbp_rule> gbp_rules_t;
+
+ /**
* The key for a contract is the pari of EPG-IDs
*/
typedef std::pair<epg_id_t, epg_id_t> key_t;
@@ -87,6 +93,11 @@ public:
*/
std::string to_string() const;
+ /**
+ * Set gbp_rules in case of Redirect Contract
+ */
+ void set_gbp_rules(const gbp_rules_t& gbp_rules);
+
private:
/**
* Class definition for listeners to OM events
@@ -169,6 +180,11 @@ private:
std::shared_ptr<ACL::l3_list> m_acl;
/**
+ * The gbp rules applied to traffic between the gourps
+ */
+ gbp_rules_t m_gbp_rules;
+
+ /**
* A map of all bridge_domains
*/
static singular_db<key_t, gbp_contract> m_db;
diff --git a/extras/vom/vom/gbp_contract_cmds.cpp b/extras/vom/vom/gbp_contract_cmds.cpp
index f99092451fe..db49f9751f1 100644
--- a/extras/vom/vom/gbp_contract_cmds.cpp
+++ b/extras/vom/vom/gbp_contract_cmds.cpp
@@ -14,6 +14,7 @@
*/
#include "vom/gbp_contract_cmds.hpp"
+#include "vom/api_types.hpp"
namespace VOM {
namespace gbp_contract_cmds {
@@ -21,11 +22,13 @@ namespace gbp_contract_cmds {
create_cmd::create_cmd(HW::item<bool>& item,
epg_id_t src_epg_id,
epg_id_t dst_epg_id,
- const handle_t& acl)
+ const handle_t& acl,
+ const gbp_contract::gbp_rules_t& gbp_rules)
: rpc_cmd(item)
, m_src_epg_id(src_epg_id)
, m_dst_epg_id(dst_epg_id)
, m_acl(acl)
+ , m_gbp_rules(gbp_rules)
{
}
@@ -33,20 +36,59 @@ bool
create_cmd::operator==(const create_cmd& other) const
{
return ((m_acl == other.m_acl) && (m_src_epg_id == other.m_src_epg_id) &&
- (m_dst_epg_id == other.m_dst_epg_id));
+ (m_dst_epg_id == other.m_dst_epg_id) &&
+ (m_gbp_rules == other.m_gbp_rules));
}
rc_t
create_cmd::issue(connection& con)
{
- msg_t req(con.ctx(), 1, std::ref(*this));
+ u8 size = m_gbp_rules.empty() ? 1 : m_gbp_rules.size();
+ msg_t req(con.ctx(), size, std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.is_add = 1;
payload.contract.acl_index = m_acl.value();
payload.contract.src_epg = m_src_epg_id;
payload.contract.dst_epg = m_dst_epg_id;
-
+ if (size > 1) {
+ u32 ii = 0;
+ auto it = m_gbp_rules.cbegin();
+ payload.contract.n_rules = m_gbp_rules.size();
+ while (it != m_gbp_rules.cend()) {
+ if (it->action() == gbp_rule::action_t::REDIRECT)
+ payload.contract.rules[ii].action = GBP_API_RULE_REDIRECT;
+ else if (it->action() == gbp_rule::action_t::PERMIT)
+ payload.contract.rules[ii].action = GBP_API_RULE_PERMIT;
+ else
+ payload.contract.rules[ii].action = GBP_API_RULE_DENY;
+
+ if (it->nhs().getHashMode() == gbp_rule::hash_mode_t::SYMMETRIC)
+ payload.contract.rules[ii].nh_set.hash_mode =
+ GBP_API_HASH_MODE_SYMMETRIC;
+ else if (it->nhs().getHashMode() == gbp_rule::hash_mode_t::SRC_IP)
+ payload.contract.rules[ii].nh_set.hash_mode = GBP_API_HASH_MODE_SRC_IP;
+ else
+ payload.contract.rules[ii].nh_set.hash_mode = GBP_API_HASH_MODE_DST_IP;
+
+ const gbp_rule::next_hops_t& next_hops = it->nhs().getNextHops();
+ u8 jj = 0, nh_size = (next_hops.size() > 8) ? 8 : next_hops.size();
+ auto nh_it = next_hops.cbegin();
+
+ payload.contract.rules[ii].nh_set.n_nhs = nh_size;
+ while (jj < nh_size) {
+ payload.contract.rules[ii].nh_set.nhs[jj].ip = to_api(nh_it->getIp());
+ payload.contract.rules[ii].nh_set.nhs[jj].mac = to_api(nh_it->getMac());
+ payload.contract.rules[ii].nh_set.nhs[jj].bd_id = nh_it->getBdId();
+ payload.contract.rules[ii].nh_set.nhs[jj].rd_id = nh_it->getRdId();
+ ++nh_it;
+ ++jj;
+ }
+
+ ++it;
+ ++ii;
+ }
+ }
VAPI_CALL(req.execute());
return (wait());
diff --git a/extras/vom/vom/gbp_contract_cmds.hpp b/extras/vom/vom/gbp_contract_cmds.hpp
index 7e4447663fd..4f921f6da94 100644
--- a/extras/vom/vom/gbp_contract_cmds.hpp
+++ b/extras/vom/vom/gbp_contract_cmds.hpp
@@ -25,8 +25,8 @@ namespace VOM {
namespace gbp_contract_cmds {
/**
-* A command class that creates or updates the GBP contract
-*/
+ * A command class that creates or updates the GBP contract
+ */
class create_cmd : public rpc_cmd<HW::item<bool>, vapi::Gbp_contract_add_del>
{
public:
@@ -36,7 +36,8 @@ public:
create_cmd(HW::item<bool>& item,
epg_id_t src_epg_id,
epg_id_t dst_epg_id,
- const handle_t& acl);
+ const handle_t& acl,
+ const gbp_contract::gbp_rules_t& gbp_rules);
/**
* Issue the command to VPP/HW
@@ -57,6 +58,7 @@ private:
const epg_id_t m_src_epg_id;
const epg_id_t m_dst_epg_id;
const handle_t m_acl;
+ const gbp_contract::gbp_rules_t& m_gbp_rules;
};
/**
diff --git a/extras/vom/vom/gbp_rule.cpp b/extras/vom/vom/gbp_rule.cpp
new file mode 100644
index 00000000000..7aa799029ff
--- /dev/null
+++ b/extras/vom/vom/gbp_rule.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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 <sstream>
+
+#include "vom/gbp_rule.hpp"
+
+namespace VOM {
+gbp_rule::next_hop_t::next_hop_t(const boost::asio::ip::address& ip,
+ const mac_address_t& mac,
+ uint32_t bd_id,
+ uint32_t rd_id)
+ : m_ip(ip)
+ , m_mac(mac)
+ , m_bd_id(bd_id)
+ , m_rd_id(rd_id)
+{
+}
+
+std::string
+gbp_rule::next_hop_t::to_string() const
+{
+ std::ostringstream s;
+
+ s << "["
+ << "ip:" << m_ip << " mac:" << m_mac.to_string() << " bd:" << m_bd_id
+ << " rd:" << m_rd_id << "]";
+
+ return (s.str());
+}
+
+bool
+gbp_rule::next_hop_t::operator<(const gbp_rule::next_hop_t& nh) const
+{
+ return (nh.m_ip < m_ip);
+}
+
+bool
+gbp_rule::next_hop_t::operator==(const gbp_rule::next_hop_t& nh) const
+{
+ return ((m_ip == nh.m_ip) && (m_mac == nh.m_mac) && (m_bd_id == nh.m_bd_id) &&
+ (m_rd_id == nh.m_rd_id));
+}
+
+const boost::asio::ip::address&
+gbp_rule::next_hop_t::getIp() const
+{
+ return m_ip;
+}
+
+const mac_address_t&
+gbp_rule::next_hop_t::getMac() const
+{
+ return m_mac;
+}
+
+const uint32_t
+gbp_rule::next_hop_t::getBdId() const
+{
+ return m_bd_id;
+}
+
+const uint32_t
+gbp_rule::next_hop_t::getRdId() const
+{
+ return m_rd_id;
+}
+
+const gbp_rule::hash_mode_t gbp_rule::hash_mode_t::SRC_IP(1, "src-ip");
+const gbp_rule::hash_mode_t gbp_rule::hash_mode_t::DST_IP(0, "dst-ip");
+const gbp_rule::hash_mode_t gbp_rule::hash_mode_t::SYMMETRIC(2, "symmetric");
+
+gbp_rule::hash_mode_t::hash_mode_t(int v, const std::string s)
+ : enum_base(v, s)
+{
+}
+
+const gbp_rule::hash_mode_t&
+gbp_rule::hash_mode_t::from_int(vapi_enum_gbp_hash_mode i)
+{
+ if (i == GBP_API_HASH_MODE_SYMMETRIC)
+ return gbp_rule::hash_mode_t::SYMMETRIC;
+ else if (i == GBP_API_HASH_MODE_SRC_IP)
+ return gbp_rule::hash_mode_t::SRC_IP;
+
+ return gbp_rule::hash_mode_t::DST_IP;
+}
+
+gbp_rule::next_hop_set_t::next_hop_set_t(const gbp_rule::hash_mode_t& hm,
+ gbp_rule::next_hops_t& nhs)
+ : m_hm(hm)
+ , m_nhs(nhs)
+{
+}
+
+std::string
+gbp_rule::next_hop_set_t::to_string() const
+{
+ std::ostringstream s;
+
+ s << "hash-mode:" << m_hm.to_string() << " next-hops:[";
+ auto it = m_nhs.cbegin();
+ while (it != m_nhs.cend()) {
+ s << " " << it->to_string();
+ ++it;
+ }
+ s << " ] next-hop-size:" << m_nhs.size();
+
+ return (s.str());
+}
+
+bool
+gbp_rule::next_hop_set_t::operator==(const next_hop_set_t& nhs) const
+{
+ return ((m_hm == nhs.m_hm) && (m_nhs == nhs.m_nhs));
+}
+
+const gbp_rule::hash_mode_t&
+gbp_rule::next_hop_set_t::getHashMode() const
+{
+ return m_hm;
+}
+
+const gbp_rule::next_hops_t&
+gbp_rule::next_hop_set_t::getNextHops() const
+{
+ return m_nhs;
+}
+
+const gbp_rule::action_t gbp_rule::action_t::REDIRECT(2, "redirect");
+const gbp_rule::action_t gbp_rule::action_t::PERMIT(1, "permit");
+const gbp_rule::action_t gbp_rule::action_t::DENY(0, "deny");
+
+gbp_rule::action_t::action_t(int v, const std::string s)
+ : enum_base(v, s)
+{
+}
+
+const gbp_rule::action_t&
+gbp_rule::action_t::from_int(vapi_enum_gbp_rule_action i)
+{
+ if (i == GBP_API_RULE_REDIRECT)
+ return gbp_rule::action_t::REDIRECT;
+ else if (i == GBP_API_RULE_PERMIT)
+ return gbp_rule::action_t::PERMIT;
+
+ return gbp_rule::action_t::DENY;
+}
+
+gbp_rule::gbp_rule(uint32_t priority,
+ const gbp_rule::next_hop_set_t& nhs,
+ const gbp_rule::action_t& a)
+ : m_priority(priority)
+ , m_nhs(nhs)
+ , m_action(a)
+{
+}
+
+bool
+gbp_rule::operator<(const gbp_rule& other) const
+{
+ return (other.m_priority < m_priority);
+}
+
+bool
+gbp_rule::operator==(const gbp_rule& rule) const
+{
+ return ((m_action == rule.m_action) && (m_nhs == rule.m_nhs) &&
+ (m_priority == rule.m_priority));
+}
+
+std::string
+gbp_rule::to_string() const
+{
+ std::ostringstream s;
+
+ s << "gbp-rule:["
+ << "priority:" << m_priority << " action:" << m_action.to_string()
+ << " next-hop-set:[" << m_nhs.to_string() << "]]";
+
+ return (s.str());
+}
+
+uint32_t
+gbp_rule::priority() const
+{
+ return m_priority;
+}
+
+const gbp_rule::action_t&
+gbp_rule::action() const
+{
+ return m_action;
+}
+
+const gbp_rule::next_hop_set_t&
+gbp_rule::nhs() const
+{
+ return m_nhs;
+}
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/gbp_rule.hpp b/extras/vom/vom/gbp_rule.hpp
new file mode 100644
index 00000000000..bda040939fb
--- /dev/null
+++ b/extras/vom/vom/gbp_rule.hpp
@@ -0,0 +1,281 @@
+/*
+ * 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_RULE_H__
+#define __VOM_GBP_RULE_H__
+
+#include <set>
+
+#include "vom/types.hpp"
+#include <vapi/gbp.api.vapi.h>
+namespace VOM {
+class gbp_rule
+{
+public:
+ /**
+ * Representation of next hop
+ */
+ struct next_hop_t
+ {
+ /**
+ * Constructor for next_hop_t
+ */
+ next_hop_t(const boost::asio::ip::address& ip,
+ const mac_address_t& mac,
+ uint32_t bd_id,
+ uint32_t rd_id);
+
+ /**
+ * default destructor
+ */
+ ~next_hop_t() = default;
+
+ /**
+ * convert to string
+ */
+ std::string to_string() const;
+
+ /**
+ * less-than operator
+ */
+ bool operator<(const next_hop_t& nh) const;
+
+ /**
+ * comparison operator (for testing)
+ */
+ bool operator==(const next_hop_t& nh) const;
+
+ /**
+ * get the IP address
+ */
+ const boost::asio::ip::address& getIp(void) const;
+
+ /**
+ * get the mac address
+ */
+ const mac_address_t& getMac(void) const;
+
+ /**
+ * get the bridge domain Id
+ */
+ const uint32_t getBdId(void) const;
+
+ /**
+ * get the route domain Id
+ */
+ const uint32_t getRdId(void) const;
+
+ private:
+ /**
+ * IP address for next hop
+ */
+ const boost::asio::ip::address m_ip;
+
+ /**
+ * mac address for interface lookup
+ */
+ const mac_address_t m_mac;
+
+ /**
+ * bridge domain in which redirected endpoints exist
+ */
+ const uint32_t m_bd_id;
+
+ /**
+ * route domain in which redirected endpoints exist
+ */
+ const uint32_t m_rd_id;
+ };
+
+ /**
+ * hash mode enum
+ */
+ struct hash_mode_t : public enum_base<hash_mode_t>
+ {
+ /**
+ * Flow Hash is calculated based on SRC IP
+ * in case of load balancing
+ */
+ const static hash_mode_t SRC_IP;
+
+ /**
+ * Flow hash is calculated based on DST IP
+ */
+ const static hash_mode_t DST_IP;
+
+ /**
+ * Flow hash is calculated based on SRC IP,
+ * DST IP and Protocol. SRC IP and DST IP
+ * addresses are sorted before hash such that
+ * a same hash is generated in both directions.
+ */
+ const static hash_mode_t SYMMETRIC;
+
+ /**
+ * create the hash mode from int value
+ */
+ static const hash_mode_t& from_int(vapi_enum_gbp_hash_mode i);
+
+ private:
+ hash_mode_t(int v, const std::string s);
+ };
+
+ /**
+ * unordered set of next hops
+ */
+ typedef std::set<next_hop_t> next_hops_t;
+
+ /**
+ * Representation of set of next hops and
+ * associated hash mode profile
+ */
+ struct next_hop_set_t
+ {
+ /**
+ * Constructor for next_hop_set_t
+ */
+ next_hop_set_t(const hash_mode_t& hm, next_hops_t& nhs);
+
+ /**
+ * Destructor for next_hop_set_t
+ */
+ ~next_hop_set_t() = default;
+
+ /**
+ * convert to string
+ */
+ std::string to_string() const;
+
+ /**
+ * Comparison operator
+ */
+ bool operator==(const next_hop_set_t& nhs) const;
+
+ /**
+ * get the hash mode
+ */
+ const hash_mode_t& getHashMode(void) const;
+
+ /**
+ * get the set of next hops
+ */
+ const next_hops_t& getNextHops(void) const;
+
+ private:
+ /**
+ * hash mode for this rule
+ */
+ const hash_mode_t m_hm;
+
+ /**
+ * set of next hops
+ */
+ const next_hops_t m_nhs;
+ };
+
+ /**
+ * ACL rule action enum
+ */
+ struct action_t : public enum_base<action_t>
+ {
+ /**
+ * Permit action
+ */
+ const static action_t PERMIT;
+
+ /**
+ * Deny action
+ */
+ const static action_t DENY;
+
+ /**
+ * Redirect action
+ */
+ const static action_t REDIRECT;
+
+ /**
+ * create the action from int value
+ */
+ static const action_t& from_int(vapi_enum_gbp_rule_action i);
+
+ private:
+ action_t(int v, const std::string s);
+ };
+
+ /**
+ * Construct a new object matching the desried state
+ */
+ gbp_rule(uint32_t priority, const next_hop_set_t& nhs, const action_t& a);
+
+ /**
+ * Copy Constructor
+ */
+ gbp_rule(const gbp_rule& o) = default;
+
+ /**
+ * Destructor
+ */
+ ~gbp_rule() = default;
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * less-than operator
+ */
+ bool operator<(const gbp_rule& rule) const;
+
+ /**
+ * comparison operator (for testing)
+ */
+ bool operator==(const gbp_rule& rule) const;
+
+ /**
+ * Getters
+ */
+ uint32_t priority() const;
+ const next_hop_set_t& nhs() const;
+ const action_t& action() const;
+
+private:
+ /**
+ * Priority. Used to sort the rules in a list in the order
+ * in which they are applied
+ */
+ uint32_t m_priority;
+
+ /**
+ * set of next hops along with hash mode profile
+ */
+ const next_hop_set_t m_nhs;
+
+ /**
+ * Action on match
+ */
+ const action_t m_action;
+};
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/src/plugins/gbp/gbp.api b/src/plugins/gbp/gbp.api
index 9af8b35b870..6bdcc5d7e0c 100644
--- a/src/plugins/gbp/gbp.api
+++ b/src/plugins/gbp/gbp.api
@@ -263,6 +263,7 @@ enum gbp_hash_mode
{
GBP_API_HASH_MODE_SRC_IP,
GBP_API_HASH_MODE_DST_IP,
+ GBP_API_HASH_MODE_SYMMETRIC,
};
typedef gbp_next_hop_set
diff --git a/src/plugins/gbp/gbp_api.c b/src/plugins/gbp/gbp_api.c
index 6a000721a01..4402ec15b8c 100644
--- a/src/plugins/gbp/gbp_api.c
+++ b/src/plugins/gbp/gbp_api.c
@@ -718,6 +718,9 @@ gbp_hash_mode_decode (vl_api_gbp_hash_mode_t in, gbp_hash_mode_t * out)
case GBP_API_HASH_MODE_DST_IP:
*out = GBP_HASH_MODE_DST_IP;
return (0);
+ case GBP_API_HASH_MODE_SYMMETRIC:
+ *out = GBP_HASH_MODE_SYMMETRIC;
+ return (0);
}
return (-2);
diff --git a/src/plugins/gbp/gbp_contract.h b/src/plugins/gbp/gbp_contract.h
index c1073510413..21e7265a82f 100644
--- a/src/plugins/gbp/gbp_contract.h
+++ b/src/plugins/gbp/gbp_contract.h
@@ -52,7 +52,8 @@ typedef struct gbp_next_hop_t_
#define foreach_gbp_hash_mode \
_(SRC_IP, "src-ip") \
- _(DST_IP, "dst-ip")
+ _(DST_IP, "dst-ip") \
+ _(SYMMETRIC, "symmetric")
typedef enum gbp_hash_mode_t_
{