diff --git a/src/iface.cc b/src/iface.cc index 99617be..6c09f60 100644 --- a/src/iface.cc +++ b/src/iface.cc @@ -599,6 +599,7 @@ int iface::poll_all() continue; } + bool found = false; for (std::list >::iterator s_it = ifa->_sessions.begin(); s_it != ifa->_sessions.end(); s_it++) { assert(!s_it->is_null()); @@ -607,9 +608,18 @@ int iface::poll_all() if ((sess->taddr() == taddr) && (sess->status() == session::WAITING || sess->status() == session::RENEWING)) { sess->handle_advert(ifa); + found = true; break; } } + + if (found == false) { + if (ifa->owner()) { + ifa->owner()->handle_advert(saddr, taddr, ifa); + } else { + logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name(); + } + } } } @@ -709,4 +719,14 @@ const ptr& iface::pr() const return _pr; } +void iface::owner(const ptr& pr) +{ + _owner = pr; +} + +const ptr& iface::owner() const +{ + return _owner; +} + NDPPD_NS_END diff --git a/src/iface.h b/src/iface.h index 48d49e2..573b613 100644 --- a/src/iface.h +++ b/src/iface.h @@ -67,8 +67,12 @@ public: void remove_session(const ptr& se); void pr(const ptr& pr); - + const ptr& pr() const; + + void owner(const ptr& pr); + + const ptr& owner() const; private: static std::map > _map; @@ -108,6 +112,8 @@ private: std::list > _sessions; weak_ptr _pr; + + weak_ptr _owner; // The link-layer address of this interface. struct ether_addr hwaddr; diff --git a/src/ndppd.cc b/src/ndppd.cc index 813b931..51cb852 100644 --- a/src/ndppd.cc +++ b/src/ndppd.cc @@ -204,6 +204,7 @@ static bool configure(ptr& cf) if (!ifa || ifa.is_null() == true) { return false; } + ifa->owner(pr); pr->add_rule(addr, ifa); } else if (ru_cf->find("auto")) { diff --git a/src/proxy.cc b/src/proxy.cc index c878ac6..5e32b2f 100644 --- a/src/proxy.cc +++ b/src/proxy.cc @@ -26,7 +26,9 @@ #include "session.h" NDPPD_NS_BEGIN - + +static address all_nodes = address("ff02::1"); + std::list > proxy::_list; proxy::proxy() : @@ -61,14 +63,8 @@ ptr proxy::open(const std::string& ifname, bool promiscuous) return create(ifa, promiscuous); } -void proxy::handle_solicit(const address& saddr, const address& daddr, - const address& taddr) +ptr proxy::find_or_create_session(const address& saddr, const address& daddr, const address& taddr, const ptr& receiver) { - logger::debug() - << "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null") - << ", saddr=" << saddr.to_string() - << ", taddr=" << taddr.to_string(); - // Let's check this proxy's list of sessions to see if we can // find one with the same target address. @@ -76,43 +72,32 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, sit != _sessions.end(); sit++) { if ((*sit)->taddr() == taddr) - { - (*sit)->touch(); - - switch ((*sit)->status()) { - case session::WAITING: - case session::INVALID: - break; - - case session::VALID: - case session::RENEWING: - (*sit)->send_advert(); - } - - return; - } + return (*sit); } - + // Since we couldn't find a session that matched, we'll try to find // a matching rule instead, and then set up a new session. - + ptr se; - + for (std::list >::iterator it = _rules.begin(); it != _rules.end(); it++) { ptr ru = *it; logger::debug() << "checking " << ru->addr() << " against " << taddr; - if (!daddr.is_multicast() && ru->addr() != daddr) { + if (!daddr.is_multicast() && ru->addr() != daddr && daddr != taddr) { continue; } + + if (receiver && ru->ifa() && receiver->name() != ru->ifa()->name()) + continue; if (ru->addr() == taddr) { if (!se) { se = session::create(_ptr, saddr, daddr, taddr, _autowire); } - + if (ru->is_auto()) { ptr rt = route::find(taddr); @@ -129,23 +114,60 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, // This rule doesn't have an interface, and thus we'll consider // it "static" and immediately send the response. se->handle_advert(); - return; + return se; } else { se->add_iface((*it)->ifa()); #ifdef WITH_ND_NETLINK if (if_addr_find((*it)->ifa()->name(), &taddr.const_addr())) { logger::debug() << "Sending NA out " << (*it)->ifa()->name(); se->add_iface(_ifa); - se->handle_advert(_ifa); + se->handle_advert(); } #endif } } } - + if (se) { _sessions.push_back(se); - se->send_solicit(); + } + + return se; +} + +void proxy::handle_advert(const address& saddr, const address& taddr, const ptr& receiver) +{ + logger::debug() + << "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null") + << ", saddr=" << saddr.to_string() + << ", taddr=" << taddr.to_string(); + + ptr se = find_or_create_session(saddr, all_nodes, taddr, receiver); + if (!se) return; + + se->handle_advert(receiver); +} + +void proxy::handle_solicit(const address& saddr, const address& daddr, const address& taddr) +{ + logger::debug() + << "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null") + << ", saddr=" << saddr.to_string() + << ", taddr=" << taddr.to_string(); + + ptr se = find_or_create_session(saddr, daddr, taddr, ptr()); + if (!se) return; + + se->touch(); + + switch (se->status()) { + case session::WAITING: + case session::INVALID: + return; + + case session::VALID: + case session::RENEWING: + se->send_advert(); } } diff --git a/src/proxy.h b/src/proxy.h index c19ea60..c09212d 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -33,9 +33,12 @@ public: static ptr create(const ptr& ifa, bool promiscuous); static ptr open(const std::string& ifn, bool promiscuous); + + ptr find_or_create_session(const address& saddr, const address& daddr, const address& taddr, const ptr& receiver); + + void handle_advert(const address& saddr, const address& taddr, const ptr& receiver); - void handle_solicit(const address& saddr, const address& daddr, - const address& taddr); + void handle_solicit(const address& saddr, const address& daddr, const address& taddr); void remove_session(const ptr& se); diff --git a/src/session.cc b/src/session.cc index ba000d0..10e7130 100644 --- a/src/session.cc +++ b/src/session.cc @@ -104,14 +104,14 @@ ptr session::create(const ptr& pr, const address& saddr, se->_taddr = taddr; se->_daddr = daddr; se->_autowire = auto_wire; - se->_wired = false; + se->_wired = false; se->_ttl = pr->timeout(); - se->_touched = true; + se->_touched = false; _sessions.push_back(se); logger::debug() - << "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", slave=" << ((pr->ifa()) ? pr->ifa()->name() : "null") << ", saddr=" << saddr + << "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null") << ", saddr=" << saddr << ", daddr=" << daddr << ", taddr=" << taddr << ", autowire=" << (auto_wire == true ? "yes" : "no") << " =" << logger::format("%x", (session* )se); return se; @@ -139,7 +139,13 @@ void session::send_solicit() void session::touch() { - _touched = true; + if (_touched == false) + { + _touched = true; + + if (status() == session::WAITING || status() == session::INVALID) + send_solicit(); + } } void session::send_advert() @@ -193,13 +199,14 @@ void session::handle_auto_unwire(const ptr& ifa) void session::handle_advert(const ptr& ifa) { - if (_autowire == true) { + if (_autowire == true && _status == WAITING) { handle_auto_wire(ifa); } handle_advert(); } + void session::handle_advert() { logger::debug() diff --git a/src/session.h b/src/session.h index eacead3..6b6a6cc 100644 --- a/src/session.h +++ b/src/session.h @@ -84,9 +84,9 @@ public: int status() const; void status(int val); - - void handle_advert(); + void handle_advert(); + void handle_advert(const ptr& ifa); void handle_auto_wire(const ptr& ifa);