Designing Linux Server for CMs Provisioning | docsis.org

You are here

Designing Linux Server for CMs Provisioning

12 posts / 0 new
Last post
perse0
Designing Linux Server for CMs Provisioning

Hello ,

I am interested to build my own system of provisioning services (DHCP,
TFTP, TIME SERVER, etc) for Cable Modems.

I'll use Mysql and PHP; i am new in this and i need the help by you that
has a experience in this marketplace.

The typical dhcp (dhcpd), and tftp servers on Red Hat Based systems
(CentOS) could work for this propose?

thanks in advanced

schirrmeister
Hi, I've never done this

Hi,

I've never done this before, but I don't know why it shouldn't work,
here are some links I found already according this:

ISC-DHCP:
http://www.gossamer-threads.com/lists/cisco/ubr/58023
http://strangejamaican.blogspot.com/2009/03/docsis-on-isc-dhcp.html
http://docsis.org/node/83

Timeserver:
http://argray.com/unixfaq/timesync.shtml#rdate_server

perse0
Thanks

Hi,

Today im found this project:

http://code.google.com/p/docsis-provisioning/

what do you think about it?

...Im working on ISC DHCP, and just following the links that you gave to me!

thansk in advanced!!!

schirrmeister
open source provisioning

Hi perse0,

I also stumbled up on this but have not had a look at it.

At this time I played around with the docsis-server: http://users.accesscomm.ca/docsis_server/
the tftp and time-server works fine. I had only a lab-Installation, so I don't know how it works
in the live network.

Yesterday I found a third project, anounced in "Software,Testing,Provsioning":
http://jhthorsen.github.com/quelea/

regards
Benedikt

perse0
Radius & PPPoE?????

thanks for the info.......

I have just been looking for enough information on the internet, thinking about doing something pretty good and professional.

I've been reading about radius and PPPoE, what do you thing about to integrate these into the platform for provisioning?

possible?

All the info that can you bring me, will be usefull

Thanks in advanced!

sonny
hi perse0 we have think

hi perse0
we have think about pppoe and radius , in layer-2 cmts
and i have test in bigband cmts , that cmts have special function is pppoe relay
can only relay pppoe packet to special ethernet interface .

but when use pppoe need buy bras , need more cost.....

bealsm
I've done this
Yes, it's very possible and not all that complicated. I built a system based on Ubuntu server using standard open source DHCP and tftp servers. The headed that controls the system is php/mysql based as well. Here are some things I learned: 1. Put your provisioning server as close to your subs as possible, or over a very low latency link. Even moderate latency can kill a dhcp session. I am running our network 2 ways. Some CMTS's are on their own WAN link (so there is no local hop from headend to CMTS)...these locations have their own provisioning servers sitting on the same switch as the CMTS. We are migrating to centralized provisioning where one server handles multiple locations and multiple CMTS's. For this, we are connecting to the locations through an MPLS network with DHCP and tftp given real time priority. CMTS's are on site, all other servers are back at the headend. 2. Generate your config files on the headend server and push to the provisioning servers with RSH. Makes updates much easier. 3. Write a small daemon (I used perl) that sits on the provisioning server and handles incoming the snmp requests to the cmts and modems. It's more secure, and more fault tolerant, allowing the local server to perform error handling and pre-processing before reporting back to the headend. If your Sub's are on a network behind a WAN link, it also lets you poll a modem without giving that modem a public IP. 4. For some ideas on the dhcp config, just search this board for my user name. 5. If you can, connect your provisioning server to your CMTS with the serial cable. I find ssh'ing into the provisioning server, then connecting to the CMTS through a terminal emulator works better then a direct telnet session. 6. Look into DRBD and HA (http://www.linux-ha.org/) for your provisioning server if it is handling a lot of subs. Put your tftp and dhcp files (.leases and .conf) on the DRBD partition and run tftp (xinetd really) and dhcpd through heartbeat. This way if one machine dies, the second picks up exactly where the other left off...it even has the same IP, so it's essentially seamless. In testing, my server takes about 4 seconds to fully fail over. 7. Store provisioning info in the centralized mysql server and provision modems via omapi. If you are dealing with multiple CMTS's, you will need to work some database voodoo to associate each sub with provisioning server IP, but it's not really all that difficult. I can give you some schema ideas if you would like. here is a php class I wrote for handling omapi connections. [code] class omapi_Connection{ private $key; private $port; private $path; public $server; function __construct($server = NULL){ if($server){ $this->server = $server; $this->connect(); } } function connect(){ include 'lib/om-constants.php'; $this->key = $omapi_key; $this->port = $omapi_port; $this->path = $omshellPath; $dspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"),); $success = array(); $success[0] = false; $success[1] = ""; $this->process = proc_open($this->path, $dspec, $this->pipes); if(is_resource($this->process)){ $this->readit(); $this->writeit("port {$this->port}"); $this->writeit ("key omapi_key \"{$this->key}\""); $this->writeit("server {$this->server}"); $this->writeit("connect"); } } function add($mac,$group){ $this->init_host($mac); $output = $this->new_host($group); return $this->check_error($output); } function delete($mac){ $this->init_host($mac); $this->open_host(); $output = $this->remove_host(); return $this->check_error($output); } function query($mac){ $this->init_host($mac); $output = $this->open_host(); return $this->check_error($output); } ############################################## function init_host($mac){ if(is_resource($this->process)){ if($this->init) $this->close(); $this->writeit("new host"); $reply = $this->writeit("set hardware-address=$mac"); if(!$this->check_error($reply)) $this->init = 1; } } function new_host($group){ if(is_resource($this->process)){ $this->writeit("set known=1"); $this->writeit("set hardware-type=1"); $this->writeit("set group=\"$group\""); return $this->writeit("create"); } } function open_host(){ if(is_resource($this->process)){ return $this->writeit("open"); } } function remove_host(){ if(is_resource($this->process)){ $error = $this->writeit("remove"); if(!$this->check_error($error)) $this->init = 0; return $error; } } function close(){ if(is_resource($this->process)){ return $this->writeit("close"); } } function check_error($array){ if(!is_array($array)) return false; $glob = implode('',$array); if(preg_match("/can't open object:.*/",$glob,$result)) return $result[0]; } function readit(){ $end = '> '; $length = 1024; stream_set_blocking($this->pipes[1], FALSE); while (!feof($this->pipes[1])) { $buffer = fgets($this->pipes[1], $length); if($buffer && $buffer != $end) $log[] = $buffer; if (substr_count($buffer, $end) > 0) { $pipes[1] = "" ; break; } } $this->logs[] = $log; return $log; } function writeit($str) { $this->logs[] = $str; fwrite($this->pipes[0], "$str\n"); return $this->readit(); } function __destruct(){ fclose($this->pipes[0]); fclose($this->pipes[1]); return proc_close($this->process); } } [/code] If you follow the client-server model, you can actually create a pretty robust system. I'm not on this board as much anymore, so if you have any questions, just email me at bealsm82 AT gmail DOT com
perse0
Thanks....just Thanks

Hi,

thanks, a lot for all...

an other question..... can i reboot/restart/re-provisioning a cable modem from a command on the CMTS??

because, im bluiding the system with the must automatic way.....so when i change a configuration in one specific Costumer i want to make a re-provisioning of the services there...

thanks in advanced

bealsm
You don't need to. Most
You don't need to. Most of what you want to do is easiest to do through the provisioning server. The full action of reprovisioning a customer (which I take to mean changing the config file) involves updating the host declaration in the DHCP server to reflect the new config file then rebooting the modem. Here is the modem class I wrote to handle it. Some of it won't make much sense because it is unique to my database schema, but it should give you an idea of how I handle it. [code] class modem{ private $id; public $customer; public $property; public $mac; public $qos; public $provisioned; public $ip; public $status; private $omconn; function __construct($id=NULL){ if(is_numeric($id)){ $this->setID($id); $this->populate(); } } function assign_customer($id){ $this->customer = $id; } function setID($id){ $this->id = $id; } function setMAC($mac){ $this->mac = $mac; } function populate(){ $query = "Select * from modems, qos where modems.qos = qos.`qosID` AND modems.`id` = '{$this->id}'"; $result = mysql_query($query); $row = mysql_fetch_assoc($result); $this->mac = $row['mac']; $this->customer = $row['custID']; $this->qos = $row['qosID']; $this->qosName = $row['name']; $this->provisioned = $row['provisioned']; $this->qosGroup = $row['dhcpdGroup']; $this->up = $row[up]; $this->down = $row[down]; } function status(){ $query = "Select * from Walkdata where mac = '{$this->mac}'"; $result = mysql_query($query) or die(mysql_error()); if(mysql_num_rows($result)) $row = mysql_fetch_assoc($result); $this->ip = $row['ip']; $this->status = $row['status']; $this->prov_status(); } ################################### function set_qos($qos){ $this->qos = $qos; $query = "update modems set qos = '$qos' where id = '{$this->id}'"; mysql_query($query); $this->populate(); $this->log('QOS profile changed to {$this->qosName}'); } function mute(){ $success = $this->deregister(); if($success){ $query = "update modems set provisioned = '0' where id = '{$this->id}'"; mysql_query($query); $this->log('Modem muted'); return 1; } return 0; } function unmute(){ $success = $this->register(); if($success){ $query = "update modems set provisioned = '1' where id = '{$this->id}'"; mysql_query($query); $this->log('Modem unmuted'); return 1; } return 0; } function toggle(){ if($this->provisioned == 1) return $this->mute(); else return $this->unmute(); } function add(){ if(!$this->qos) $this->qos = 1; $this->populate_qos(); $this->register(); $query = "Insert into `modems` (`custID`,`mac`,`qos`,`provisioned`) VALUES ('{$this->customer}','{$this->mac}','{$this->qos}','{$this->provisioned}')"; mysql_query($query) or die(mysql_error()); $this->id = mysql_insert_id(); $this->log('Modem Registered'); return 1; } function delete(){ $this->deregister(); $query = "Delete from `modems` where id = '{$this->id}'"; mysql_query($query) or die(mysql_error()); $this->log('Modem Removed'); return 1; } ################################## function populate_qos(){ $query = "Select * from qos where qosID = '{$this->qos}'"; $result = mysql_query($query); $this->qosGroup = mysql_result($result,0,'dhcpdGroup'); $this->qosName = mysql_result($result,0,'name'); } function log($action){ $query = "Insert into `modem-Transactions` (`modem`,`mac`,`customerID`,`comments`) VALUES ('{$this->id}','{$this->mac}','{$this->customer}','$action')"; mysql_query($query); } function omapi_connect(){ $this->omconn = new omapi_Connection($this->dhcp_Server); } function register(){ if(!$this->omconn) $this->omapi_connect(); $this->omconn->add($this->mac,$this->qosGroup); return $this->prov_status(); } function deregister(){ if(!$this->omconn) $this->omapi_connect(); $this->omconn->delete($this->mac); $this->prov_status(); $this->reboot(); if(!$this->provisioned) return 1; return 0; } function prov_status(){ if(!$this->omconn) $this->omapi_connect(); $status = $this->omconn->query($this->mac); $this->provisioned = isset($status) ? 0 : 1; return $this->provisioned; } function apply_qos($qos = NULL){ if($qos) $this->set_qos($qos); $sucess = $this->deregister(); if(!$success && $this->provisioned) die('Could not unregister modem'); $sucess = $this->register(); if(!$success && !$this->provisioned) die('Could not reregister modem'); $this->reboot(); return 1; } function log_dump(){ if($this->omconn) return $this->omconn->logs; } function reboot(){ if(!$this->ip) $this->status(); exec("/usr/local/bin/modemClient reset {$this->ip} {$this->dhcp_Server}"); $this->log('reboot'); } function query(){ if(!$this->ip) $this->status(); exec("/usr/local/bin/modemClient info {$this->ip} {$this->dhcp_Server}", $live_info); print_r($live_info); } } [/code] If you look at the bottom functions, you can see how I deal with provisioning, unprovisioning and updating modems. muting and unmuting is how I handle nonpay. I change the registration status in the dhcp server, but don't delete it from my master database. To change the modem's provisioning, you use this function: [code] function apply_qos($qos = NULL){ if($qos) $this->set_qos($qos); //if a new qos is defined, update database $success = $this->deregister(); //delete modem declaration from dhcp server if(!$success && $this->provisioned) die('Could not unregister modem'); // if errors were returned and the host declaration is still active, die $success = $this->register(); // register the modem using the new qos. if(!$success && !$this->provisioned) die('Could not reregister modem'); // if errors and the new host declaration does not exist, die $this->reboot(); //reboot the modem so that it can take the new config. return 1; // return success } [/code] To reboot the modem, I call: exec("/usr/local/bin/modemClient reset {$this->ip} {$this->dhcp_Server}"); modemClient is a perl script I wrote that connects to a perl dameon running on the provisioning server. The modemClient script sends the reset command and the modem's ip to the ip specified in $this->dhcp_Server. When the server receives this command, it resets the modem by setting the reset SNMP MIB. I did it this way because most of my sites were behind a WAN interface, so I connect to the system through a public IP. I didn't want to give every modem a public IP, so I just give the provisioning server a public and connect via this daemon.
perse0
thanks!!

Thank you ,, so much!!!

very cool way for reprovisioning!!

the part when sent to reboot a CM ....i was thinking to do this part with PHP and make a telnet or rlogin (what ever) and then reboot !!!!

at this time im working in the core of the server.. after this i'll proceed to work with the GUI!!

thanks!!

bajojoba
Reset of the CM via SNMP

Hi,

I would say that the best and easiest way to reset the CM is via SNMP. You'll need to know your CMTS RW community.

On CISCO (and Arris C3):

you'll need to change the CM MAC to decimal value (example: 00:18:23:34:ff:aa = 0.24.35.52.255.170) and add it to the oid .1.3.6.1.4.1.9.9.116.1.3.1.1.8. like this:

snmpwalk -v 2c -c community CMTS_IP .1.3.6.1.4.1.9.9.116.1.3.1.1.8.0.24.35.52.255.170

what you get is a PTR number of the CM. With this number you can reset the CM:
snmpset -v 2c -c rwcommunity CMTS_IP .1.3.6.1.4.1.4491.2.1.10.1.2.1.5.PTR i 1

ON CASA (tested on 3200 and 2200):
it is much easier that on cisco.
snmpset -v 2c -c rwcommunity CMTS_IP 1.3.6.1.4.1.20858.10.12.1.5.2.0 x "00 11 22 33 44 55"

Hope this helps.

bealsm
I actually did a lot of

I actually did a lot of experimenting with rebooting modems and as well as with scripting telnet sessions and even rlogin. I found php to have horrible support for such tasks. Perl is better, but you still are attempting to script a serial interface which was designed for human interaction. You could probably modify the omapi code to work for telnet, as it is basicaly doing the same thing. (Sending a request then waiting for a response)

I wound up using snmp because it was simple and universal. I don't have to worry about the code breaking if we install a different cmts. Even with the extra work it took me to write the dameon (which was easy using easy::tcp), it was less of a headache then scripting a telnet session, and let me access a lot of data from the modems that the cmts doesn't pull in (such as modem brand, firmware version, T-errors, boot logs, ect).

Anyway, good luck with your project. Mine took me about a year to bring to a point that I consider it stable and operational. Let me know if you have any questions or would like to see some more code. I don't check here super often, so a direct email is faster. I listed my address in a previous post.

Log in or register to post comments