Skip to content

Commit

Permalink
static/mcast: Support multiple mcast routes of different distances.
Browse files Browse the repository at this point in the history
This allows static routes to over-ride ones created by PIM.
Route distance is currently fixed:  static == 0, pim == 1.
Lower distance wins.

Signed-off-by: Ben Greear <greearb@candelatech.com>
  • Loading branch information
greearb committed Jun 20, 2012
1 parent 521eab5 commit 6566779
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 89 deletions.
212 changes: 184 additions & 28 deletions xorp/fea/mfea_node.cc
Expand Up @@ -42,6 +42,29 @@
#include "mfea_vif.hh"


MfeaRouteStorage::MfeaRouteStorage(uint32_t d, const string module_name, const IPvX& _source,
const IPvX& _group, const string& _iif_name, const string& _oif_names) :
distance(d), is_binary(false), module_instance_name(module_name), source(_source),
group(_group), iif_name(_iif_name), oif_names(_oif_names) { }

MfeaRouteStorage::MfeaRouteStorage(uint32_t d, const string module_name, const IPvX& _source,
const IPvX& _group, uint32_t iif_vif_idx,
const Mifset& _oiflist, const Mifset& _oif_disable_wrongvif,
uint32_t max_vifs, const IPvX& _rp_addr) :
distance(d), is_binary(true), module_instance_name(module_name), source(_source),
group(_group), iif_vif_index(iif_vif_idx), oiflist(_oiflist),
oiflist_disable_wrongvif(_oif_disable_wrongvif), max_vifs_oiflist(max_vifs),
rp_addr(_rp_addr) { }

MfeaRouteStorage::MfeaRouteStorage(const MfeaRouteStorage& o) :
distance(o.distance), is_binary(true), module_instance_name(o.module_instance_name),
source(o.source), group(o.group), iif_name(o.iif_name),
oif_names(o.oif_names), iif_vif_index(o.iif_vif_index),
oiflist(o.oiflist), oiflist_disable_wrongvif(o.oiflist_disable_wrongvif),
max_vifs_oiflist(o.max_vifs_oiflist), rp_addr(o.rp_addr) { }

MfeaRouteStorage::MfeaRouteStorage() : distance(0), is_binary(false), max_vifs_oiflist(0) { }

/**
* MfeaNode::MfeaNode:
* @fea_node: The corresponding FeaNode.
Expand Down Expand Up @@ -1821,10 +1844,45 @@ int MfeaNode::add_mfc_str(const string& module_instance_name,
const IPvX& group,
const string& iif_name,
const string& oif_names,
string& error_msg) {
string& error_msg, bool check_stored_routes) {
int rv;
uint32_t iif_vif_index;

XLOG_INFO("MFEA add_mfc_str, module: %s source: %s group: %s check-stored-routes: %i",
module_instance_name.c_str(), source.str().c_str(),
group.str().c_str(), (int)(check_stored_routes));

if (check_stored_routes) {
MfeaRouteStorage mrs(0, module_instance_name, source,
group, iif_name, oif_names);
routes[mrs.distance][mrs.getHash()] = mrs;

// If any lower distance routes are already in place, do nothing and
// return.
if (mrs.distance > 0) {
for (unsigned int i = mrs.distance - 1; i > 0; i--) {
map<string, MfeaRouteStorage>::const_iterator iter = routes[i].find(mrs.getHash());
if (iter != routes[i].end()) {
XLOG_INFO("Lower-distance mfea route exists, distance: %i source: %s group: %s",
i, source.str().c_str(), group.str().c_str());
return XORP_OK;
}
}
}

// If any higher distance routes are already in place, remove them from kernel.
for (unsigned int i = mrs.distance + 1; i<MAX_MFEA_DISTANCE; i++) {
map<string, MfeaRouteStorage>::const_iterator iter = routes[i].find(mrs.getHash());
if (iter != routes[i].end()) {
XLOG_INFO("Removing higher-distance mfea route, distance: %i source: %s group: %s",
i, source.str().c_str(), group.str().c_str());
delete_mfc(iter->second.module_instance_name, iter->second.source,
iter->second.group, error_msg, false);
break;
}
}
}

// Convert strings to mfc binary stuff and pass to
// add_mfc()
MfeaVif *mfea_vif = vif_find_by_name(iif_name);
Expand Down Expand Up @@ -1863,7 +1921,7 @@ int MfeaNode::add_mfc_str(const string& module_instance_name,
rv = add_mfc(module_instance_name, source, group,
iif_vif_index, oiflist,
oiflist_disable_wrongvif,
MAX_VIFS, rp_addr);
MAX_VIFS, rp_addr, error_msg, false);
if (rv != XORP_OK) {
error_msg = "call to add_mfc failed";
}
Expand Down Expand Up @@ -1894,25 +1952,66 @@ MfeaNode::add_mfc(const string& module_instance_name,
uint32_t iif_vif_index, const Mifset& oiflist,
const Mifset& oiflist_disable_wrongvif,
uint32_t max_vifs_oiflist,
const IPvX& rp_addr)
const IPvX& rp_addr, string& error_msg,
bool check_stored_routes)
{
UNUSED(module_instance_name);

uint8_t oifs_ttl[MAX_VIFS];
uint8_t oifs_flags[MAX_VIFS];

XLOG_INFO("MFEA add_mfc, module: %s source: %s group: %s",
XLOG_INFO("MFEA add_mfc, module: %s source: %s group: %s check-stored-routes: %i",
module_instance_name.c_str(), source.str().c_str(),
group.str().c_str());

if (max_vifs_oiflist > MAX_VIFS)
return (XORP_ERROR);
group.str().c_str(), (int)(check_stored_routes));

if (max_vifs_oiflist > MAX_VIFS) {
error_msg += c_format("max-vifs-oiflist: %u > MAX_VIFS: %u\n",
max_vifs_oiflist, MAX_VIFS);
return XORP_ERROR;
}

// Check the iif
if (iif_vif_index == Vif::VIF_INDEX_INVALID)
return (XORP_ERROR);
if (iif_vif_index >= max_vifs_oiflist)
return (XORP_ERROR);
if (iif_vif_index == Vif::VIF_INDEX_INVALID) {
error_msg += "iif_vif_index is VIF_INDEX_INVALID\n";
return XORP_ERROR;
}

if (iif_vif_index >= max_vifs_oiflist) {
error_msg += c_format("iif_vif_index: %u >= max-vifs-oiflist: %u\n",
iif_vif_index, max_vifs_oiflist);
return XORP_ERROR;
}

if (check_stored_routes) {
MfeaRouteStorage mrs(1, module_instance_name, source,
group, iif_vif_index, oiflist,
oiflist_disable_wrongvif, max_vifs_oiflist,
rp_addr);
routes[mrs.distance][mrs.getHash()] = mrs;

// If any lower distance routes are already in place, do nothing and
// return.
if (mrs.distance > 0) {
for (unsigned int i = mrs.distance - 1; i > 0; i--) {
map<string, MfeaRouteStorage>::const_iterator iter = routes[i].find(mrs.getHash());
if (iter != routes[i].end()) {
XLOG_INFO("Lower-distance mfea route exists, distance: %i source: %s group: %s",
i, source.str().c_str(), group.str().c_str());
return XORP_OK;
}
}
}

// If any higher distance routes are already in place, remove them from kernel.
for (unsigned int i = mrs.distance + 1; i<MAX_MFEA_DISTANCE; i++) {
map<string, MfeaRouteStorage>::const_iterator iter = routes[i].find(mrs.getHash());
if (iter != routes[i].end()) {
XLOG_INFO("Removing higher-distance mfea route, distance: %i source: %s group: %s",
i, source.str().c_str(), group.str().c_str());
delete_mfc(iter->second.module_instance_name, iter->second.source,
iter->second.group, error_msg, false);
break;
}
}
}

//
// Reset the initial values
Expand Down Expand Up @@ -1949,9 +2048,10 @@ MfeaNode::add_mfc(const string& module_instance_name,
case AF_INET6:
{
#ifndef HAVE_IPV6_MULTICAST_ROUTING
XLOG_ERROR("add_mfc() failed: "
"IPv6 multicast routing not supported");
return (XORP_ERROR);
string em = "add_mfc() failed: IPv6 multicast routing not supported\n";
error_msg += em;
XLOG_ERROR(em);
return XORP_ERROR;
#else
#if defined(MRT6_MFC_FLAGS_DISABLE_WRONGVIF) && defined(ENABLE_ADVANCED_MULTICAST_API)
oifs_flags[i] |= MRT6_MFC_FLAGS_DISABLE_WRONGVIF;
Expand All @@ -1971,10 +2071,11 @@ MfeaNode::add_mfc(const string& module_instance_name,
if (_mfea_mrouter.add_mfc(source, group, iif_vif_index, oifs_ttl,
oifs_flags, rp_addr)
!= XORP_OK) {
return (XORP_ERROR);
error_msg += "mfea_mrouter add_mfc failed.\n";
return XORP_ERROR;
}

return (XORP_OK);
return XORP_OK;
}

/**
Expand All @@ -1990,19 +2091,74 @@ MfeaNode::add_mfc(const string& module_instance_name,
* Return value: %XORP_OK on success, otherwise %XORP_ERROR.
**/
int
MfeaNode::delete_mfc(const string& , // module_instance_name,
const IPvX& source, const IPvX& group)
MfeaNode::delete_mfc(const string& module_instance_name,
const IPvX& source, const IPvX& group,
string& error_msg, bool check_stored_routes)
{
if (_mfea_mrouter.delete_mfc(source, group) != XORP_OK) {
return (XORP_ERROR);
bool do_rem_route = true;
int rv;
string hash = source.str() + ":" + group.str();

XLOG_INFO("delete-mfc, module: %s source: %s group: %s check-stored-routes: %i\n",
module_instance_name.c_str(), source.str().c_str(),
group.str().c_str(), (int)(check_stored_routes));

if (check_stored_routes) {
// find existing route by instance-name.
for (unsigned int i = 0; i<MAX_MFEA_DISTANCE; i++) {
map<string, MfeaRouteStorage>::iterator iter = routes[i].find(hash);
if (iter != routes[i].end()) {
// Found something to delete..see if it belongs to us?
if (iter->second.module_instance_name == module_instance_name) {
// Yep, that's us.
routes[i].erase(hash);
goto check_remove_route;
}
else {
// was some other protocol's route. Don't mess with this,
// and don't remove anything from the kernel.
do_rem_route = false;
}
}
}
}

check_remove_route:

if (! do_rem_route) {
return XORP_OK;
}

rv = _mfea_mrouter.delete_mfc(source, group);

//
// XXX: Remove all corresponding dataflow entries
//
// Remove all corresponding dataflow entries
mfea_dft().delete_entry(source, group);

return (XORP_OK);

if (check_stored_routes) {
// Now, see if we have any higher-distance routes to add.
for (unsigned int i = 0; i<MAX_MFEA_DISTANCE; i++) {
map<string, MfeaRouteStorage>::iterator iter = routes[i].find(hash);
if (iter != routes[i].end()) {
if (iter->second.isBinary()) {
rv = add_mfc(iter->second.module_instance_name,
iter->second.source, iter->second.group,
iter->second.iif_vif_index,
iter->second.oiflist, iter->second.oiflist_disable_wrongvif,
iter->second.max_vifs_oiflist, iter->second.rp_addr,
error_msg, false);
}
else {
rv = add_mfc_str(iter->second.module_instance_name,
iter->second.source, iter->second.group,
iter->second.iif_name, iter->second.oif_names,
error_msg, false);
}
break;
}
}
}

return rv;
}

/**
Expand Down
77 changes: 62 additions & 15 deletions xorp/fea/mfea_node.hh
Expand Up @@ -46,6 +46,44 @@ class MfeaVif;
class SgCount;
class VifCount;


class MfeaRouteStorage {
public:
uint32_t distance; // lower is higer priority.
bool is_binary;

string module_instance_name;
IPvX source;
IPvX group;

// String based route
string iif_name;
string oif_names;

// Binary based route
uint32_t iif_vif_index;
Mifset oiflist;
Mifset oiflist_disable_wrongvif;
uint32_t max_vifs_oiflist;
IPvX rp_addr;

MfeaRouteStorage(uint32_t d, const string module_name, const IPvX& _source,
const IPvX& _group, const string& _iif_name, const string& _oif_names);

MfeaRouteStorage(uint32_t d, const string module_name, const IPvX& _source,
const IPvX& _group, uint32_t iif_vif_idx,
const Mifset& _oiflist, const Mifset& _oif_disable_wrongvif,
uint32_t max_vifs, const IPvX& _rp_addr);

MfeaRouteStorage(const MfeaRouteStorage& o);
MfeaRouteStorage();

bool isBinary() const { return is_binary; }

string getHash() { return source.str() + ":" + group.str(); }
};


/**
* @short The MFEA node class.
*
Expand Down Expand Up @@ -578,19 +616,20 @@ public:
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int add_mfc(const string& module_instance_name,
const IPvX& source, const IPvX& group,
uint32_t iif_vif_index, const Mifset& oiflist,
const Mifset& oiflist_disable_wrongvif,
uint32_t max_vifs_oiflist,
const IPvX& rp_addr);

int add_mfc_str(const string& module_instance_name,
const IPvX& source,
const IPvX& group,
const string& iif_name,
const string& oif_names,
string& error_msg);
int add_mfc(const string& module_instance_name,
const IPvX& source, const IPvX& group,
uint32_t iif_vif_index, const Mifset& oiflist,
const Mifset& oiflist_disable_wrongvif,
uint32_t max_vifs_oiflist,
const IPvX& rp_addr, string& error_msg,
bool check_stored_routes);

int add_mfc_str(const string& module_instance_name,
const IPvX& source,
const IPvX& group,
const string& iif_name,
const string& oif_names,
string& error_msg, bool check_stored_routes);

/**
* Delete Multicast Forwarding Cache (MFC) from the kernel.
Expand All @@ -606,8 +645,9 @@ public:
*
* @return XORP_OK on success, otherwise XORP_ERROR.
*/
int delete_mfc(const string& module_instance_name,
const IPvX& source, const IPvX& group);
int delete_mfc(const string& module_instance_name,
const IPvX& source, const IPvX& group,
string& error_msg, bool check_stored_routes);

/**
* Add a dataflow monitor entry.
Expand Down Expand Up @@ -859,6 +899,13 @@ private:
IfTree _mfea_iftree;
IfConfigUpdateReplicator _mfea_iftree_update_replicator;

// Store desired routes. This is a cheap way of doing some of the
// RIB logic, but for mcast routes.
// Lower distance means higher priority.
// key is: source:group, ie: 192.168.1.1:226.0.0.1
#define MAX_MFEA_DISTANCE 8
map<string, MfeaRouteStorage> routes[MAX_MFEA_DISTANCE];

//
// Debug and test-related state
//
Expand Down

0 comments on commit 6566779

Please sign in to comment.