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 $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; } }