VOM: mroutes

- fixes in ip.api for dumping mroute path flags

Change-Id: I13b0cfb15d374250ed71bd4e13dda9b798c18204
Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
Neale Ranns
2018-12-27 03:21:28 -08:00
committed by Florin Coras
parent e26c81fc80
commit 7c03ed47d5
17 changed files with 1378 additions and 123 deletions

View File

@ -158,6 +158,7 @@ list(APPEND VOM_SOURCES
neighbour.cpp
neighbour_cmds.cpp
object_base.cpp
mroute_cmds.cpp
om.cpp
pipe.cpp
pipe_cmds.cpp
@ -165,6 +166,7 @@ list(APPEND VOM_SOURCES
ra_config.cpp
ra_prefix.cpp
route.cpp
route_api_types.cpp
route_cmds.cpp
route_domain.cpp
route_domain_cmds.cpp

View File

@ -28,6 +28,21 @@ to_api(const ip_address_t& a, vapi_type_address& v)
memcpy(v.un.ip6, a.to_v6().to_bytes().data(), 16);
}
}
void
to_api(const ip_address_t& a,
vapi_union_address_union& u,
vapi_enum_address_family& af)
{
if (a.is_v4()) {
af = ADDRESS_IP4;
memcpy(u.ip4, a.to_v4().to_bytes().data(), 4);
} else {
af = ADDRESS_IP6;
memcpy(u.ip6, a.to_v6().to_bytes().data(), 16);
}
}
void
to_api(const boost::asio::ip::address& a, vapi_type_ip4_address& v)
{
@ -54,6 +69,26 @@ from_api(const vapi_type_address& v)
return addr;
}
ip_address_t
from_api(const vapi_union_address_union& u, vapi_enum_address_family af)
{
boost::asio::ip::address addr;
if (ADDRESS_IP6 == af) {
std::array<uint8_t, 16> a;
std::copy(u.ip6, u.ip6 + 16, std::begin(a));
boost::asio::ip::address_v6 v6(a);
addr = v6;
} else {
std::array<uint8_t, 4> a;
std::copy(u.ip6, u.ip6 + 4, std::begin(a));
boost::asio::ip::address_v4 v4(a);
addr = v4;
}
return addr;
}
void
to_api(const mac_address_t& a, vapi_type_mac_address& v)
{
@ -80,6 +115,25 @@ to_api(const route::prefix_t& p)
v.address_length = p.mask_width();
return v;
}
route::mprefix_t
from_api(const vapi_type_mprefix& v)
{
return route::mprefix_t(from_api(v.src_address, v.af),
from_api(v.grp_address, v.af), v.grp_address_length);
}
vapi_type_mprefix
to_api(const route::mprefix_t& p)
{
vapi_enum_address_family af;
vapi_type_mprefix v;
to_api(p.grp_address(), v.grp_address, af);
to_api(p.src_address(), v.src_address, af);
v.grp_address_length = p.mask_width();
v.af = af;
return v;
}
};
/*

View File

@ -25,17 +25,24 @@ typedef boost::asio::ip::address ip_address_t;
void to_api(const ip_address_t& a, vapi_type_address& v);
void to_api(const boost::asio::ip::address& a, vapi_type_ip4_address& v);
void to_api(const boost::asio::ip::address& a,
vapi_union_address_union& u,
vapi_enum_address_family& af);
ip_address_t from_api(const vapi_type_address& v);
ip_address_t from_api(const vapi_type_ip4_address& v);
ip_address_t from_api(const vapi_union_address_union& u,
vapi_enum_address_family af);
void to_api(const mac_address_t& a, vapi_type_mac_address& m);
mac_address_t from_api(const vapi_type_mac_address& v);
route::prefix_t from_api(const vapi_type_prefix&);
route::mprefix_t from_api(const vapi_type_mprefix&);
vapi_type_prefix to_api(const route::prefix_t&);
vapi_type_mprefix to_api(const route::mprefix_t&);
};
/*

View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sstream>
#include "vom/api_types.hpp"
#include "vom/mroute_cmds.hpp"
#include "vom/route_api_types.hpp"
namespace VOM {
namespace route {
namespace ip_mroute_cmds {
update_cmd::update_cmd(HW::item<bool>& item,
table_id_t id,
const mprefix_t& mprefix,
const path& path,
const itf_flags_t& flags)
: rpc_cmd(item)
, m_id(id)
, m_mprefix(mprefix)
, m_path(path)
, m_flags(flags)
{
}
bool
update_cmd::operator==(const update_cmd& other) const
{
return ((m_mprefix == other.m_mprefix) && (m_id == other.m_id));
}
rc_t
update_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.table_id = m_id;
payload.is_add = 1;
m_mprefix.to_vpp(&payload.is_ipv6, payload.grp_address, payload.src_address,
&payload.grp_address_length);
to_vpp(m_path, payload);
payload.itf_flags = m_flags.value();
VAPI_CALL(req.execute());
return (wait());
}
std::string
update_cmd::to_string() const
{
std::ostringstream s;
s << "ip-mroute-create: " << m_hw_item.to_string() << " table-id:" << m_id
<< " mprefix:" << m_mprefix.to_string() << " path:" << m_path.to_string()
<< " flags:" << m_flags;
return (s.str());
}
delete_cmd::delete_cmd(HW::item<bool>& item,
table_id_t id,
const mprefix_t& mprefix,
const path& path,
const itf_flags_t& flags)
: rpc_cmd(item)
, m_id(id)
, m_mprefix(mprefix)
, m_path(path)
, m_flags(flags)
{
}
bool
delete_cmd::operator==(const delete_cmd& other) const
{
return ((m_mprefix == other.m_mprefix) && (m_id == other.m_id));
}
rc_t
delete_cmd::issue(connection& con)
{
msg_t req(con.ctx(), std::ref(*this));
auto& payload = req.get_request().get_payload();
payload.table_id = m_id;
payload.is_add = 0;
m_mprefix.to_vpp(&payload.is_ipv6, payload.grp_address, payload.src_address,
&payload.grp_address_length);
to_vpp(m_path, payload);
payload.itf_flags = m_flags.value();
VAPI_CALL(req.execute());
wait();
m_hw_item.set(rc_t::NOOP);
return rc_t::OK;
}
std::string
delete_cmd::to_string() const
{
std::ostringstream s;
s << "ip-mroute-delete: " << m_hw_item.to_string() << " id:" << m_id
<< " mprefix:" << m_mprefix.to_string();
return (s.str());
}
dump_v4_cmd::dump_v4_cmd()
{
}
bool
dump_v4_cmd::operator==(const dump_v4_cmd& other) const
{
return (true);
}
rc_t
dump_v4_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_v4_cmd::to_string() const
{
return ("ip-mroute-v4-dump");
}
dump_v6_cmd::dump_v6_cmd()
{
}
bool
dump_v6_cmd::operator==(const dump_v6_cmd& other) const
{
return (true);
}
rc_t
dump_v6_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_v6_cmd::to_string() const
{
return ("ip-mroute-v6-dump");
}
} // namespace ip_mroute_cmds
} // namespace mroute
} // namespace vom
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,181 @@
/*
* 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_MROUTE_CMDS_H__
#define __VOM_MROUTE_CMDS_H__
#include "vom/dump_cmd.hpp"
#include "vom/route.hpp"
#include "vom/rpc_cmd.hpp"
#include <vapi/ip.api.vapi.hpp>
namespace VOM {
namespace route {
namespace ip_mroute_cmds {
/**
* A command class that creates or updates the route
*/
class update_cmd : public rpc_cmd<HW::item<bool>, vapi::Ip_mroute_add_del>
{
public:
/**
* Constructor
*/
update_cmd(HW::item<bool>& item,
table_id_t id,
const mprefix_t& mprefix,
const path& path,
const itf_flags_t& flags);
/**
* 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 update_cmd& i) const;
private:
route::table_id_t m_id;
mprefix_t m_mprefix;
const path m_path;
const itf_flags_t& m_flags;
};
/**
* A cmd class that deletes a route
*/
class delete_cmd : public rpc_cmd<HW::item<bool>, vapi::Ip_mroute_add_del>
{
public:
/**
* Constructor
*/
delete_cmd(HW::item<bool>& item,
table_id_t id,
const mprefix_t& mprefix,
const path& path,
const itf_flags_t& flags);
/**
* 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:
route::table_id_t m_id;
mprefix_t m_mprefix;
const path m_path;
const itf_flags_t& m_flags;
};
/**
* A cmd class that Dumps ipv4 fib
*/
class dump_v4_cmd : public VOM::dump_cmd<vapi::Ip_mfib_dump>
{
public:
/**
* Constructor
*/
dump_v4_cmd();
dump_v4_cmd(const dump_cmd& d);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const dump_v4_cmd& i) const;
private:
/**
* HW reutrn code
*/
HW::item<bool> item;
};
/**
* A cmd class that Dumps ipv6 fib
*/
class dump_v6_cmd : public VOM::dump_cmd<vapi::Ip6_mfib_dump>
{
public:
/**
* Constructor
*/
dump_v6_cmd();
dump_v6_cmd(const dump_cmd& d);
/**
* Issue the command to VPP/HW
*/
rc_t issue(connection& con);
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* Comparison operator - only used for UT
*/
bool operator==(const dump_v6_cmd& i) const;
private:
/**
* HW reutrn code
*/
HW::item<bool> item;
};
}; // namespace ip_mroute_cmds
}; // namespace route
}; // namespace VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif

View File

@ -190,7 +190,7 @@ route::prefix_t::to_string() const
}
boost::asio::ip::address
from_bytes(uint8_t is_ip6, uint8_t* bytes)
from_bytes(uint8_t is_ip6, const uint8_t* bytes)
{
boost::asio::ip::address addr;
@ -420,6 +420,135 @@ route::prefix_t::high() const
return (pfx);
}
/**
* The all Zeros prefix
*/
const route::mprefix_t route::mprefix_t::ZERO;
const route::mprefix_t route::mprefix_t::ZEROv6;
route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len)
: m_gaddr(gaddr)
, m_saddr()
, m_len(len)
{
}
route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr)
: m_gaddr(gaddr)
, m_saddr()
, m_len(VOM::mask_width(gaddr))
{
}
route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
const boost::asio::ip::address& gaddr)
: m_gaddr(gaddr)
, m_saddr(saddr)
, m_len(2 * VOM::mask_width(gaddr))
{
}
route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
const boost::asio::ip::address& gaddr,
uint16_t len)
: m_gaddr(gaddr)
, m_saddr(saddr)
, m_len(len)
{
}
route::mprefix_t::mprefix_t(const mprefix_t& o)
: m_gaddr(o.m_gaddr)
, m_saddr(o.m_saddr)
, m_len(o.m_len)
{
}
route::mprefix_t::mprefix_t()
: m_gaddr()
, m_saddr()
, m_len(0)
{
}
route::mprefix_t::~mprefix_t()
{
}
const boost::asio::ip::address&
route::mprefix_t::grp_address() const
{
return (m_gaddr);
}
const boost::asio::ip::address&
route::mprefix_t::src_address() const
{
return (m_saddr);
}
uint8_t
route::mprefix_t::mask_width() const
{
return (m_len);
}
void
route::mprefix_t::to_vpp(uint8_t* is_ip6,
uint8_t* saddr,
uint8_t* gaddr,
uint16_t* len) const
{
*len = m_len;
to_bytes(m_saddr, is_ip6, saddr);
to_bytes(m_gaddr, is_ip6, gaddr);
}
route::mprefix_t&
route::mprefix_t::operator=(const route::mprefix_t& o)
{
m_gaddr = o.m_gaddr;
m_saddr = o.m_saddr;
m_len = o.m_len;
return (*this);
}
bool
route::mprefix_t::operator<(const route::mprefix_t& o) const
{
if (m_len == o.m_len) {
if (m_saddr == o.m_saddr)
return (m_gaddr < o.m_gaddr);
else
return (m_saddr < o.m_saddr);
} else {
return (m_len < o.m_len);
}
}
bool
route::mprefix_t::operator==(const route::mprefix_t& o) const
{
return (m_len == o.m_len && m_gaddr == o.m_gaddr && m_saddr == o.m_saddr);
}
bool
route::mprefix_t::operator!=(const route::mprefix_t& o) const
{
return (!(*this == o));
}
std::string
route::mprefix_t::to_string() const
{
std::ostringstream s;
s << "(" << m_saddr.to_string() << "," << m_gaddr.to_string() << "/"
<< std::to_string(m_len) << ")";
return (s.str());
}
}; // namespace VOM
/*

View File

@ -171,8 +171,8 @@ public:
const static prefix_t ZEROv6;
/**
* Convert the prefix into VPP API parameters
*/
* Convert the prefix into VPP API parameters
*/
void to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const;
/**
@ -206,8 +206,120 @@ private:
*/
uint8_t m_len;
};
/**
* A prefix defintion. Address + length
*/
class mprefix_t
{
public:
/**
* Default Constructor - creates ::/0
*/
mprefix_t();
/**
* Constructor for (S,G)
*/
mprefix_t(const boost::asio::ip::address& saddr,
const boost::asio::ip::address& gaddr);
/*
* Constructor for (*,G)
*/
mprefix_t(const boost::asio::ip::address& gaddr);
/*
* Constructor for (*,G/n)
*/
mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len);
/**
*Constructor for (S,G)
*/
mprefix_t(const boost::asio::ip::address& saddr,
const boost::asio::ip::address& gaddr,
uint16_t len);
/**
* Copy Constructor
*/
mprefix_t(const mprefix_t&);
/**
* Destructor
*/
~mprefix_t();
/**
* Get the address
*/
const boost::asio::ip::address& grp_address() const;
const boost::asio::ip::address& src_address() const;
/**
* Get the network mask width
*/
uint8_t mask_width() const;
/**
* Assignement
*/
mprefix_t& operator=(const mprefix_t&);
/**
* Less than operator
*/
bool operator<(const mprefix_t& o) const;
/**
* equals operator
*/
bool operator==(const mprefix_t& o) const;
/**
* not equal opartor
*/
bool operator!=(const mprefix_t& o) const;
/**
* convert to string format for debug purposes
*/
std::string to_string() const;
/**
* The all Zeros prefix
*/
const static mprefix_t ZERO;
/**
* The all Zeros v6 prefix
*/
const static mprefix_t ZEROv6;
/**
* Get the L3 protocol
*/
l3_proto_t l3_proto() const;
void to_vpp(uint8_t* is_ip6,
uint8_t* saddr,
uint8_t* gaddr,
uint16_t* len) const;
private:
/**
* The address
*/
boost::asio::ip::address m_gaddr;
boost::asio::ip::address m_saddr;
/**
* The prefix length
*/
uint8_t m_len;
};
}; // namespace route
boost::asio::ip::address_v4 operator|(const boost::asio::ip::address_v4& addr1,
const boost::asio::ip::address_v4& addr2);
@ -254,7 +366,7 @@ uint32_t mask_width(const boost::asio::ip::address& addr);
/**
* Convert a VPP byte stinrg into a boost addresss
*/
boost::asio::ip::address from_bytes(uint8_t is_ip6, uint8_t* array);
boost::asio::ip::address from_bytes(uint8_t is_ip6, const uint8_t* array);
};
/*

File diff suppressed because it is too large Load Diff

View File

@ -204,15 +204,44 @@ private:
uint8_t m_preference;
};
class itf_flags_t : public enum_base<itf_flags_t>
{
public:
const static itf_flags_t NONE;
/**
* Path is accepting multicast traffic
*/
const static itf_flags_t ACCEPT;
/**
* A local/for-us/recieve
*/
const static itf_flags_t FORWARD;
static const itf_flags_t& from_vpp(uint32_t val);
private:
/**
* Private constructor taking the value and the string name
*/
itf_flags_t(int v, const std::string& s);
};
/**
* A path-list is a set of paths
*/
typedef std::set<path> path_list_t;
/**
* A mpath-list is a set of paths and interface flags
*/
typedef std::set<std::pair<path, itf_flags_t>> mpath_list_t;
/**
* ostream output for iterator
*/
std::ostream& operator<<(std::ostream& os, const path_list_t& path_list);
std::ostream& operator<<(std::ostream& os, const mpath_list_t& path_list);
/**
* A IP route
@ -392,9 +421,170 @@ private:
static singular_db<key_t, ip_route> m_db;
};
/**
* A IP multicast route
*/
class ip_mroute : public object_base
{
public:
/**
* The key for a route
*/
typedef std::pair<route::table_id_t, mprefix_t> key_t;
/**
* Construct a route in the default table
*/
ip_mroute(const mprefix_t& mprefix);
/**
* Copy Construct
*/
ip_mroute(const ip_mroute& r);
/**
* Construct a route in the given route domain
*/
ip_mroute(const route_domain& rd, const mprefix_t& mprefix);
/**
* Destructor
*/
~ip_mroute();
/**
* Get the route's key
*/
const key_t key() const;
/**
* Comparison operator
*/
bool operator==(const ip_mroute& i) const;
/**
* Return the matching 'singular instance'
*/
std::shared_ptr<ip_mroute> singular() const;
/**
* Find the instnace of the route domain in the OM
*/
static std::shared_ptr<ip_mroute> find(const ip_mroute& temp);
/**
* Dump all route-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 matching 'singular instance'
*/
static std::shared_ptr<ip_mroute> find(const key_t& k);
void add(const path& path, const itf_flags_t& flag);
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;
/**
* Find or add the instnace of the route domain in the OM
*/
static std::shared_ptr<ip_mroute> find_or_add(const ip_mroute& temp);
/*
* It's the OM class that updates the objects in HW
*/
friend class VOM::OM;
/**
* It's the singular_db class that calls replay()
*/
friend class singular_db<key_t, ip_mroute>;
/**
* Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
*/
void update(const ip_mroute& obj);
/**
* Sweep/reap the object if still stale
*/
void sweep(void);
/**
* HW configuration for the result of creating the route
*/
HW::item<bool> m_hw;
/**
* The route domain the route is in.
*/
std::shared_ptr<route_domain> m_rd;
/**
* The mprefix to match
*/
mprefix_t m_mprefix;
/**
* The set of paths
*/
mpath_list_t m_paths;
/**
* A map of all routes
*/
static singular_db<key_t, ip_mroute> m_db;
};
std::ostream& operator<<(std::ostream& os, const ip_route::key_t& key);
};
};
std::ostream& operator<<(std::ostream& os, const ip_mroute::key_t& key);
}; // namespace route
}; // namesapce VPP
/*
* fd.io coding-style-patch-verification: ON

View File

@ -0,0 +1,119 @@
/*
* 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/route.hpp>
#include <vom/route_api_types.hpp>
namespace VOM {
void
to_vpp(const route::path& p, vapi_payload_ip_add_del_route& payload)
{
payload.is_drop = 0;
payload.is_unreach = 0;
payload.is_prohibit = 0;
payload.is_local = 0;
payload.is_classify = 0;
payload.is_multipath = 0;
payload.is_resolve_host = 0;
payload.is_resolve_attached = 0;
if (route::path::flags_t::DVR & p.flags()) {
payload.is_dvr = 1;
}
if (route::path::special_t::STANDARD == p.type()) {
uint8_t path_v6;
to_bytes(p.nh(), &path_v6, payload.next_hop_address);
if (p.rd()) {
payload.next_hop_table_id = p.rd()->table_id();
}
if (p.itf()) {
payload.next_hop_sw_if_index = p.itf()->handle().value();
}
} else if (route::path::special_t::DROP == p.type()) {
payload.is_drop = 1;
} else if (route::path::special_t::UNREACH == p.type()) {
payload.is_unreach = 1;
} else if (route::path::special_t::PROHIBIT == p.type()) {
payload.is_prohibit = 1;
} else if (route::path::special_t::LOCAL == p.type()) {
payload.is_local = 1;
}
payload.next_hop_weight = p.weight();
payload.next_hop_preference = p.preference();
payload.next_hop_via_label = 0;
payload.classify_table_index = 0;
}
void
to_vpp(const route::path& p, vapi_payload_ip_mroute_add_del& payload)
{
if (route::path::special_t::STANDARD == p.type()) {
uint8_t path_v6;
to_bytes(p.nh(), &path_v6, payload.nh_address);
if (p.itf()) {
payload.next_hop_sw_if_index = p.itf()->handle().value();
}
payload.next_hop_afi = p.nh_proto();
}
}
route::path
from_vpp(const vapi_type_fib_path& p, const nh_proto_t& nhp)
{
if (p.is_local) {
return route::path(route::path::special_t::LOCAL);
} else if (p.is_drop) {
return route::path(route::path::special_t::DROP);
} else if (p.is_unreach) {
return route::path(route::path::special_t::UNREACH);
} else if (p.is_prohibit) {
return route::path(route::path::special_t::PROHIBIT);
} else {
boost::asio::ip::address address =
from_bytes(nh_proto_t::IPV6 == nhp, p.next_hop);
std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
if (itf) {
if (p.is_dvr) {
return route::path(*itf, nhp, route::path::flags_t::DVR, p.weight,
p.preference);
} else {
return route::path(address, *itf, p.weight, p.preference);
}
} else {
std::shared_ptr<route_domain> rd = route_domain::find(p.table_id);
if (rd) {
return route::path(*rd, address, p.weight, p.preference);
}
}
}
VOM_LOG(log_level_t::ERROR) << "cannot decode: ";
return route::path(route::path::special_t::DROP);
}
};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -0,0 +1,35 @@
/*
* 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/route.hpp>
#include <vapi/ip.api.vapi.hpp>
namespace VOM {
void to_vpp(const route::path& p, vapi_payload_ip_mroute_add_del& payload);
void to_vpp(const route::path& p, vapi_payload_ip_add_del_route& payload);
route::path from_vpp(const vapi_type_fib_path& p, const nh_proto_t& nh);
}; // namespace VOM
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/

View File

@ -15,53 +15,13 @@
#include <sstream>
#include "vom/route_cmds.hpp"
#include <vom/route_api_types.hpp>
#include <vom/route_cmds.hpp>
namespace VOM {
namespace route {
namespace ip_route_cmds {
static void
to_vpp(const route::path& p, vapi_payload_ip_add_del_route& payload)
{
payload.is_drop = 0;
payload.is_unreach = 0;
payload.is_prohibit = 0;
payload.is_local = 0;
payload.is_classify = 0;
payload.is_multipath = 0;
payload.is_resolve_host = 0;
payload.is_resolve_attached = 0;
if (route::path::flags_t::DVR & p.flags()) {
payload.is_dvr = 1;
}
if (route::path::special_t::STANDARD == p.type()) {
uint8_t path_v6;
to_bytes(p.nh(), &path_v6, payload.next_hop_address);
if (p.rd()) {
payload.next_hop_table_id = p.rd()->table_id();
}
if (p.itf()) {
payload.next_hop_sw_if_index = p.itf()->handle().value();
}
} else if (route::path::special_t::DROP == p.type()) {
payload.is_drop = 1;
} else if (route::path::special_t::UNREACH == p.type()) {
payload.is_unreach = 1;
} else if (route::path::special_t::PROHIBIT == p.type()) {
payload.is_prohibit = 1;
} else if (route::path::special_t::LOCAL == p.type()) {
payload.is_local = 1;
}
payload.next_hop_weight = p.weight();
payload.next_hop_preference = p.preference();
payload.next_hop_via_label = 0;
payload.classify_table_index = 0;
}
update_cmd::update_cmd(HW::item<bool>& item,
table_id_t id,
const prefix_t& prefix,

View File

@ -528,6 +528,10 @@ typedef struct fib_route_path_t_ {
* Exclusive DPO
*/
dpo_id_t dpo;
/**
* MFIB interface flags
*/
u32 frp_mitf_flags;
};
/**
* A path that resolves via a BIER Table.

View File

@ -502,6 +502,12 @@ define ip_mfib_dump
@param count - the number of fib_path in path
@param path - array of of fib_path structures
*/
typedef mfib_path
{
vl_api_fib_path_t path;
u32 itf_flags;
};
manual_endian manual_print define ip_mfib_details
{
u32 context;
@ -513,7 +519,7 @@ manual_endian manual_print define ip_mfib_details
u8 src_address[4];
u32 count;
u32 stats_index;
vl_api_fib_path_t path[count];
vl_api_mfib_path_t path[count];
};
/** \brief Dump IP6 multicast fib table
@ -541,7 +547,7 @@ manual_endian manual_print define ip6_mfib_details
u8 grp_address[16];
u8 src_address[16];
u32 count;
vl_api_fib_path_t path[count];
vl_api_mfib_path_t path[count];
};
define ip_address_details

View File

@ -410,7 +410,7 @@ send_ip_mfib_details (vl_api_registration_t * reg,
vl_api_ip_mfib_details_t *mp;
const mfib_prefix_t *pfx;
mfib_entry_t *mfib_entry;
vl_api_fib_path_t *fp;
vl_api_mfib_path_t *fp;
int path_count;
mfib_entry = mfib_entry_get (mfei);
@ -438,7 +438,8 @@ send_ip_mfib_details (vl_api_registration_t * reg,
fp = mp->path;
vec_foreach (api_rpath, api_rpaths)
{
fib_api_path_encode (api_rpath, fp);
fib_api_path_encode (api_rpath, &fp->path);
fp->itf_flags = ntohl (api_rpath->rpath.frp_mitf_flags);
fp++;
}
vec_free (api_rpaths);
@ -508,7 +509,7 @@ send_ip6_mfib_details (vpe_api_main_t * am,
{
vl_api_ip6_mfib_details_t *mp;
fib_route_path_encode_t *api_rpath;
vl_api_fib_path_t *fp;
vl_api_mfib_path_t *fp;
int path_count;
path_count = vec_len (api_rpaths);
@ -530,7 +531,8 @@ send_ip6_mfib_details (vpe_api_main_t * am,
fp = mp->path;
vec_foreach (api_rpath, api_rpaths)
{
fib_api_path_encode (api_rpath, fp);
fib_api_path_encode (api_rpath, &fp->path);
fp->itf_flags = ntohl (api_rpath->rpath.frp_mitf_flags);
fp++;
}

View File

@ -1325,6 +1325,7 @@ void
mfib_entry_encode (fib_node_index_t mfib_entry_index,
fib_route_path_encode_t **api_rpaths)
{
fib_route_path_encode_t *api_rpath;
mfib_entry_t *mfib_entry;
mfib_entry_src_t *bsrc;
@ -1338,6 +1339,18 @@ mfib_entry_encode (fib_node_index_t mfib_entry_index,
fib_path_encode,
api_rpaths);
}
vec_foreach(api_rpath, *api_rpaths)
{
mfib_itf_t *mfib_itf;
mfib_itf = mfib_entry_itf_find(bsrc->mfes_itfs,
api_rpath->rpath.frp_sw_if_index);
if (mfib_itf)
{
api_rpath->rpath.frp_mitf_flags = mfib_itf->mfi_flags;
}
}
}
const mfib_prefix_t *

View File

@ -38,6 +38,7 @@
#include "vom/prefix.hpp"
#include "vom/route.hpp"
#include "vom/route_cmds.hpp"
#include "vom/mroute_cmds.hpp"
#include "vom/route_domain.hpp"
#include "vom/route_domain_cmds.hpp"
#include "vom/vxlan_tunnel.hpp"
@ -251,6 +252,14 @@ public:
{
rc = handle_derived<route::ip_route_cmds::delete_cmd>(f_exp, f_act);
}
else if (typeid(*f_exp) == typeid(route::ip_mroute_cmds::update_cmd))
{
rc = handle_derived<route::ip_mroute_cmds::update_cmd>(f_exp, f_act);
}
else if (typeid(*f_exp) == typeid(route::ip_mroute_cmds::delete_cmd))
{
rc = handle_derived<route::ip_mroute_cmds::delete_cmd>(f_exp, f_act);
}
else if (typeid(*f_exp) == typeid(neighbour_cmds::create_cmd))
{
rc = handle_derived<neighbour_cmds::create_cmd>(f_exp, f_act);
@ -1762,6 +1771,26 @@ BOOST_AUTO_TEST_CASE(test_routing) {
ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_dvr, 0, pfx_6, {*path_l2}));
TRY_CHECK_RC(OM::write(ian, *route_dvr));
/*
* a multicast route
*/
route::mprefix_t mpfx_4(boost::asio::ip::address::from_string("232.1.1.1"), 32);
route::ip_mroute *mroute_4 = new route::ip_mroute(mpfx_4);
route::path *mp1 = new route::path(itf1, nh_proto_t::IPV4);
route::path *mp2 = new route::path(*itf2, nh_proto_t::IPV4);
mroute_4->add(*mp1, route::itf_flags_t::FORWARD);
mroute_4->add(*mp1, route::itf_flags_t::ACCEPT);
mroute_4->add(*mp2, route::itf_flags_t::FORWARD);
HW::item<bool> hw_mroute_4(true, rc_t::OK);
ADD_EXPECT(route::ip_mroute_cmds::update_cmd(hw_mroute_4, 0, mpfx_4,
*mp1, route::itf_flags_t::FORWARD));
ADD_EXPECT(route::ip_mroute_cmds::update_cmd(hw_mroute_4, 0, mpfx_4,
*mp2, route::itf_flags_t::FORWARD));
ADD_EXPECT(route::ip_mroute_cmds::update_cmd(hw_mroute_4, 0, mpfx_4,
*mp1, route::itf_flags_t::ACCEPT));
TRY_CHECK_RC(OM::write(ian, *mroute_4));
STRICT_ORDER_OFF();
// delete the stack objects that hold references to others
// so the OM::remove is the call that removes the last reference
@ -1775,6 +1804,18 @@ BOOST_AUTO_TEST_CASE(test_routing) {
delete route_dvr;
delete path_l2;
delete ne;
delete mroute_4;
ADD_EXPECT(route::ip_mroute_cmds::delete_cmd(hw_mroute_4, 0, mpfx_4,
*mp1, route::itf_flags_t::FORWARD));
ADD_EXPECT(route::ip_mroute_cmds::delete_cmd(hw_mroute_4, 0, mpfx_4,
*mp2, route::itf_flags_t::FORWARD));
ADD_EXPECT(route::ip_mroute_cmds::delete_cmd(hw_mroute_4, 0, mpfx_4,
*mp1, route::itf_flags_t::ACCEPT));
delete mp1;
delete mp2;
ADD_EXPECT(neighbour_cmds::delete_cmd(hw_neighbour, hw_ifh.data(), mac_n, nh_10));
ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_dvr, 0, pfx_6));
ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5_2, 1, pfx_5));