?? phyint.c
字號:
/*
* OSPFD routing daemon
* Copyright (C) 1999 by John T. Moy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Routines dealing with physical interfaces.
* There may be one or more OSPF interfaces defined
* over each physical interface; OSPF interfaces
* are operated upon in spfifc.C.
*/
#include "ospfinc.h"
#include "phyint.h"
#include "ifcfsm.h"
#include "system.h"
#include "igmp.h"
/* Constructor for a physical interface.
*/
PhyInt::PhyInt(int phyint)
: AVLitem((uns32 ) phyint, 0), qrytim(this), strqtim(this), oqtim(this)
{
operational = true;
my_addr = 0;
mospf_ifp = 0;
igmp_querier = 0;
igmp_enabled = false;
// Initialize IGMP configurable constants to RFC 2236 defaults
robustness_variable = 2;
query_interval = 125;
query_response_interval = 100;// Tenths of seconds
group_membership_interval = robustness_variable * query_interval;
// Next is more liberal than spec, to survive Querier changes
group_membership_interval += (query_response_interval*3)/20;
other_querier_present_interval = robustness_variable * query_interval;
other_querier_present_interval += query_response_interval/20;
startup_query_interval = query_interval/4;
startup_query_count = robustness_variable;
last_member_query_interval = 10;// Tenths of seconds
last_member_query_count = robustness_variable;
}
/* OSPFD application attaches to a physical interface.
*/
void OSPF::phy_attach(int phyint)
{
PhyInt *phyp;
if (!(phyp = (PhyInt *)phyints.find((uns32) phyint, 0))) {
phyp = new PhyInt((uns32) phyint);
phyints.add(phyp);
sys->phy_open(phyint);
}
phyp->ref();
phyp->verify_igmp_capabilities();
}
/* OSPFD application leaves a group on a physical interface.
*/
void OSPF::phy_detach(int phyint, InAddr if_addr)
{
PhyInt *phyp;
if ((phyp = (PhyInt *)phyints.find((uns32) phyint, 0))) {
phyp->deref();
if (phyp->not_referenced()) {
sys->phy_close(phyint);
phyints.remove(phyp);
delete phyp;
}
else {
if (phyp->igmp_querier == if_addr)
phyp->igmp_querier = 0;
phyp->verify_igmp_capabilities();
}
}
}
/* OSPFD application joins a group on a physical interface.
*/
void OSPF::app_join(int phyint, InAddr group)
{
AVLitem *member;
if (!(member = ospfd_membership.find((uns32) phyint, group))) {
member = new AVLitem((uns32) phyint, group);
ospfd_membership.add(member);
sys->join(group, phyint);
if (spflog(LOG_JOIN, 4)) {
log(&group);
log(" Ifc ");
log(sys->phyname(phyint));
}
}
member->ref();
}
/* OSPFD application leaves a group on a physical interface.
*/
void OSPF::app_leave(int phyint, InAddr group)
{
AVLitem *member;
if ((member = ospfd_membership.find((uns32) phyint, group))) {
member->deref();
if (member->not_referenced()) {
sys->leave(group, phyint);
ospfd_membership.remove(member);
member->chkref();
if (spflog(LOG_LEAVE, 4)) {
log(&group);
log(" Ifc ");
log(sys->phyname(phyint));
}
}
}
}
/***************************************************************
* An implemention of Version 2 of the IGMP
* protocol.
**************************************************************/
/* Go through all the OSPF interfaces associated with an interface
* to determine whether we should run IGMP on the interface and,
* if so, which address we should use in the Group Membership
* Queries.
* At least one of the interfaces must be numbered, with MOSPF
* enabled, for us to send IGMP queries. As for what source address
* to use, we always use the smallest interface address associated
* with the interface (which might not be the interface running
* MOSPF!).
*/
void PhyInt::verify_igmp_capabilities()
{
bool was_querier;
bool multicast_routing;
int phyint = index1();
bool igmp_was_enabled;
multicast_routing = false;
was_querier = IAmQuerier();
my_addr = 0;
mospf_ifp = 0;
igmp_was_enabled = igmp_enabled;
if (operational) {
IfcIterator iter(ospf);
SpfIfc *ip;
InAddr igmp_addr;
while ((ip = iter.get_next())) {
if (ip->if_phyint != phyint)
continue;
// IGMP allowed?
if (!ip->igmp_enabled)
continue;
// mulicast routing enabled?
if (ospf->mospf_enabled() &&
(ip->if_mcfwd == IF_MCFWD_MC))
multicast_routing = true;
// Address to use for IGMP
igmp_addr = (ip->unnumbered() ? ospf->myaddr : ip->if_addr);
// Can do IGMP on the interface
if (my_addr == 0 || igmp_addr < my_addr)
my_addr = igmp_addr;
// Running MOSPF too?
if (ospf->mospf_enabled() &&
(ip->if_mcfwd == IF_MCFWD_MC))
mospf_ifp = ip;
}
}
// Enable/disable multicast routing on interface
sys->set_multicast_routing(phyint, multicast_routing);
igmp_enabled = (my_addr && mospf_ifp);
if (igmp_enabled != igmp_was_enabled) {
if (igmp_enabled)
ospf->app_join(phyint, IGMPAllRouters);
else
ospf->app_leave(phyint, IGMPAllRouters);
}
// Should we be querier?
if (igmp_enabled) {
if (!igmp_querier || my_addr < igmp_querier ||
(was_querier && (my_addr != igmp_querier))) {
igmp_querier = my_addr;
if (ospf->spflog(LOG_QUERIER, 4)) {
ospf->log(&igmp_querier);
ospf->log(" Ifc ");
ospf->log(sys->phyname(phyint));
}
}
}
// Notice IGMP querier state changes
if (IAmQuerier()) {
if (!was_querier)
start_query_duties();
}
else if (was_querier)
stop_query_duties();
}
/* Start the IGMP querier duties by sending out a sequence
* of General Queries at a higher rate.
*/
void PhyInt::start_query_duties()
{
oqtim.stop();
send_query(0);
if (startup_query_count > 1) {
strqtim.startup_queries = startup_query_count - 1;
strqtim.start(startup_query_interval*Timer::SECOND, false);
}
}
/* Stop IGMP query duties by stopping any timers which
* might generate General Queries.
*/
void PhyInt::stop_query_duties()
{
strqtim.stop();
qrytim.stop();
}
/* The Startup Query Timer.
* "startup_queries" will be set right before the timer is started,
* so that it will have the most recently configured value.
*/
StartupQueryTimer::StartupQueryTimer(PhyInt *p)
{
phyp = p;
}
void StartupQueryTimer::action()
{
phyp->send_query(0);
if (--startup_queries <= 0) {
stop();
phyp->qrytim.start(phyp->query_interval*Timer::SECOND, false);
}
}
/* The regular query timer. Goes off continuously, sending
* out Host Membership Queries at a regular interval.
*/
IGMPQueryTimer::IGMPQueryTimer(PhyInt *p)
{
phyp = p;
}
void IGMPQueryTimer::action()
{
phyp->send_query(0);
}
/* The timer measuring whether we should replace the
* current querier, when/if it disappears.
*/
IGMPOtherQuerierTimer::IGMPOtherQuerierTimer(PhyInt *p)
{
phyp = p;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -