// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
#ident "$XORP: xorp/fea/pa_transaction.cc,v 1.12 2007/02/16 22:45:49 pavlin Exp $"
#include "fea_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/debug.h"
#include "pa_entry.hh"
#include "pa_table.hh"
#include "pa_transaction.hh"
#include "pa_backend.hh"
#include "pa_backend_dummy.hh"
#include "pa_backend_ipfw2.hh"
/* ------------------------------------------------------------------------- */
void
PaTransactionManager::pre_commit(uint32_t tid)
{
unset_error();
const PaSnapshot4* ps4 = _ptm.create_snapshot4();
const PaBackend::Snapshot4Base* bps4 = _pbp->create_snapshot4();
#ifdef notyet
const PaSnapshot6* ps6 = _ptm.create_snapshot6();
const PaBackend::Snapshot6Base* bps6 = _pbp->create_snapshot6();
_pa_transactions.insert(PaTransactionDB::value_type(
tid, PaTransaction(ps4, ps6, bps4, bps6)));
#else
_pa_transactions.insert(PaTransactionDB::value_type(
tid, PaTransaction(ps4, bps4)));
#endif
}
void
PaTransactionManager::post_commit(uint32_t tid)
{
PaTransactionDB::iterator i = _pa_transactions.find(tid);
if (i == _pa_transactions.end()) {
XLOG_ERROR("PaTransaction ID %u is missing snapshots: %s",
XORP_UINT_CAST(tid), "not found in PaTransactionDB");
return;
}
PaTransaction& pat = i->second;
//
// Check if the transaction succeeded. Back out changes using
// snapshots of the affected subsystems, if necessary.
//
if (!error().empty()) {
if (pat.snap4() != NULL)
pat.snap4()->restore(_ptm);
if (pat.bsnap4() != NULL)
_pbp->restore_snapshot4(pat.bsnap4());
#ifdef notyet
if (pat.snap6() != NULL)
pat.snap6()->restore(_ptm);
if (pat.bsnap6() != NULL)
_pbp->restore_snapshot6(pat.bsnap6());
#endif
}
// XXX: The destructor for PaTransaction should delete the snapshots.
_pa_transactions.erase(i);
}
void
PaTransactionManager::operation_result(bool success,
const TransactionOperation& op)
{
if (success)
return;
const PaTransactionOperation* fto =
dynamic_cast<const PaTransactionOperation*>(&op);
if (fto == 0) {
//
// Getting here is programmer error.
//
XLOG_ERROR("PaTransaction commit error, \"%s\" is not a "
"PaTransactionOperation",
op.str().c_str());
return;
}
//
// Only print the error message for the first failed operation.
// Flush the transaction if an error occurred, thus halting it.
//
if (set_unset_error(fto->str())) {
#ifdef notyet
flush(fto->tid);
#endif
XLOG_ERROR("PaTransaction commit failed on %s",
fto->str().c_str());
}
}
/* ------------------------------------------------------------------------- */
//
// Attempt to instantiate a back-end ACL provider by name.
//
// Must not be called during a commit; we are implicitly
// serialized by way of the FEA being single-threaded and
// event driven. In any other parallelism scheme,
// a lock must be held.
//
bool
PaTransactionManager::set_backend(const char* name)
{
if (name == NULL)
return false;
PaBackend* nbp = NULL;
// Attempt to construct the new backend.
try {
if (strcmp(name, "dummy") == 0) {
nbp = new PaDummyBackend();
#ifdef notyet
#ifdef HAVE_PACKETFILTER_IPF
} else if (strcmp(name, "ipf") == 0) {
nbp = new PaIpfBackend();
#endif
#endif
#ifdef HAVE_PACKETFILTER_IPFW2
} else if (strcmp(name, "ipfw2") == 0) {
nbp = new PaIpfw2Backend();
#endif
#ifdef notyet
#ifdef HAVE_PACKETFILTER_NF
// Linux Netfilter, also known as 'iptables'.
} else if ((strcmp(name, "netfilter") == 0) ||
(strcmp(name, "iptables") == 0)) {
nbp = new PaNfBackend();
#endif
#endif
#ifdef notyet
#ifdef HAVE_PACKETFILTER_PF
} else if (strcmp(name, "pf") == 0) {
nbp = new PaPfBackend();
#endif
#endif
} else {
return false;
}
} catch (PaInvalidBackendException) {
return false;
}
XLOG_ASSERT(nbp != NULL);
// Free the old backend if we had one.
if (_pbp != NULL)
delete _pbp;
_pbp = nbp;
// Push XORP's picture of the ACLs down to the new backend.
const PaSnapshot4* ps4 = _ptm.create_snapshot4();
_pbp->push_entries4(ps4);
delete ps4;
#ifdef notyet
const PaSnapshot6* ps6 = _ptm.create_snapshot6();
_pbp->push_entries6(ps6);
delete ps6;
#endif
return true;
}
/* ------------------------------------------------------------------------- */
PaTransactionManager::PaTransaction::PaTransaction(
const PaSnapshot4* sn4, const PaBackend::Snapshot4Base* bsn4)
: _snap4(sn4), _bsnap4(bsn4)
{
}
PaTransactionManager::PaTransaction::~PaTransaction()
{
if (_snap4 != NULL)
delete _snap4;
if (_bsnap4 != NULL)
delete _bsnap4;
#ifdef notyet
if (_snap6 != NULL)
delete _snap6;
if (_bsnap4 != NULL)
delete _bsnap6;
#endif
}
/* ------------------------------------------------------------------------- */
syntax highlighted by Code2HTML, v. 0.9.1