pfatt/src/Service/NgCtl.php
2022-03-10 20:47:28 -06:00

176 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Pfatt\Service;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
class NgCtl implements LoggerAwareInterface
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* Use ngctl to check connection.
*/
public function ngIsConnected(): bool
{
return $this->exec(['show', 'laneapfilter:eapout']);
}
/**
* Remove the eapout connection between laneapfilter and waneapfilter.
*/
public function ngRmHook(): void
{
$this->logger->info('Disconnecting netgraph node ...');
$this->exec(['rmhook', 'laneapfilter:', 'eapout']) ?
$this->logger->info('OK!') :
$this->logger->error('ERROR!');
}
/**
* Connect laneapfilter and waneapfilter with eapout.
*/
public function ngConnect(): void
{
$this->logger->info('Connecting netgraph node ...');
$this->exec(['connect', 'waneapfilter:', 'laneapfilter:', 'eapout', 'eapout']) ?
$this->logger->info('OK!') :
$this->logger->error('ERROR!');
}
/**
* Use ngctl to setup virtual connection.
*
* @param string $ont
* ONT network connection interface.
* @param string $rg
* Residential Gateway network connection interface.
* @param string $rgMac
* Residential Gateway MAC address.
* @return void
*/
public function createNodes(string $ont, string $rg, string $rgMac): void
{
$this->logger->info('Building netgraph nodes.');
$this->logger->info(' creating ng_one2many...');
$this->exec(['mkpeer', $ont . ':', 'one2many', 'lower', 'one']);
$this->exec(['name', $ont . ':lower', 'o2m']);
$this->logger->info('OK!');
$this->logger->info(' creating vlan node and interface...');
$this->exec(['mkpeer', 'o2m:', 'vlan', 'many0', ' downstream']);
$this->exec(['name', 'o2m:many0', 'vlan0']);
$this->exec(['mkpeer', 'vlan0:', 'eiface', 'vlan0', 'ether']);
$this->exec([
'msg',
'vlan0:',
'\'addfilter { vlan=0 hook="vlan0" }\''
]);
$this->exec(['msg', 'ngeth0:', 'set', $rgMac]);
$this->logger->info('OK!');
$this->logger->info(" defining etf for $ont (ONT)...");
$this->exec(['mkpeer', 'o2m:', 'etf', 'many1', 'downstream']);
$this->exec(['name', 'o2m:many1', 'waneapfilter']);
$this->exec([
'connect',
'waneapfilter:',
$ont . ':',
'nomatch',
'upper'
]);
$this->logger->info('OK!');
$this->logger->info(" defining etf for $rg (RG)...");
$this->exec(['mkpeer', $rg . ':', 'etf', 'lower', 'downstream']);
$this->exec(['name', $rg . ':', 'lower', 'laneapfilter']);
$this->exec([
'connect',
'laneapfilter:',
$rg . ':',
'nomatch',
'upper'
]);
$this->logger->info('OK!');
$this->logger->info(" bridging etf for $ont <-> $rg...");
$this->exec([
'connect',
'waneapfilter:',
'laneapfilter:',
'eapout',
'eapout'
]);
$this->logger->info('OK!');
$this->logger->info(" defining filters for EAP traffic...");
$this->exec([
'msg',
'waneapfilter:',
'\'setfilter { matchhook="eapout" ethertype=0x888e }\''
]);
$this->exec([
'msg',
'laneapfilter:',
'\'setfilter { matchhook="eapout" ethertype=0x888e }\''
]);
$this->logger->info('OK!');
$this->logger->info(" enabling one2many links...");
$this->exec([
'msg',
'o2m:',
'setconfig',
'"{ xmitAlg=2 failAlg=1 enabledLinks=[ 1 1 ] }"'
]);
$this->logger->info('OK!');
$this->logger->info(" removing waneapfilter:nomatch hook...");
$this->exec(['rmhook', 'waneapfilter:', 'nomatch']);
$this->logger->info('OK!');
}
public function removeNodes(string $ont, string $rg): void
{
$this->exec(['shutdown', 'waneapfilter:']);
$this->exec(['shutdown', 'laneapfilter:']);
$this->exec(['shutdown', $ont . ':']);
$this->exec(['shutdown', $rg . ':']);
$this->exec(['shutdown', 'o2m:']);
$this->exec(['shutdown', 'vlan0:']);
$this->exec(['shutdown', 'ngeth0:']);
}
/**
* Run a ngctl command.
*
* @param array<int, string> $args
* Additional arguments to pass to ngctl.
*
* @return bool
* True on success, false on failure.
*/
private function exec(array $args): bool
{
$process = new Process(['/usr/sbin/ngctl', ...$args], '/tmp');
return !$process->run();
}
/**
* {@inheritDoc}
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
}