From: Leandro Lucarella Date: Wed, 19 Dec 2007 17:41:39 +0000 (-0300) Subject: Merge branch 'master' of git.llucax.com.ar:/var/lib/git/software/pymin X-Git-Url: https://git.llucax.com/software/pymin.git/commitdiff_plain/91cc87ccd8910e4bbeecf2981d6c07b8578b28c0?hp=eb9820e75fe3861fd56e0635171f3bcc171ccbaa Merge branch 'master' of git.llucax.com.ar:/var/lib/git/software/pymin --- diff --git a/config.py b/config.py index 3ff98c6..a0b5498 100644 --- a/config.py +++ b/config.py @@ -11,6 +11,12 @@ config_path = join(base_path, 'config') class Root(Handler): + def __init__(self): + f = file("/proc/sys/net/ipv4/ip_forward","w") + f.write("1") + f.close() + #self.ip.device_up_hook(self.dns) + firewall = FirewallHandler( pickle_dir = join(pickle_path, 'firewall'), config_dir = join(config_path, 'firewall')) diff --git a/doc/protocol_specification.txt b/doc/protocol_specification.txt new file mode 100644 index 0000000..5abe9e9 --- /dev/null +++ b/doc/protocol_specification.txt @@ -0,0 +1,339 @@ +#ESPECIFICACION DEL PROTOCOLO DEL PYMIN + +[PARAMETROS OPCIONALES] + + +---------------------------------- + +MODULO : DHCP + +para inciar/parar el servicio : +dhcp start +dhcp stop + +para setear parametros: +dhcp set +PARAMETER puede tomar los siguientes valores : +domain_name : nombre de dominio +dns_1 : dominio del dns primario +dns_2 : dominio del dns secundario +net_address : direccion de red +net_mask : mascara de la direccion de red +net_start : direccion de inicio del rango +net_end : direccion de fin del rango +net_gateway : direccion del gateway + +para crear un host: +dhcp host add +para eliminar un host: +dhcp host delete + + +NAME : es el nombre del host +IP : la direccion ip del host +MAC : la direccion mac del host + +----------------------------------- + +MODULO : DNS + +para inciar/parar el servicio : +dns start +dns stop + +para setear parametros: +dns set +PARAMETER puede tomar los siguientes valores : +isp_dns1 : dns primario del isp +isp_dns2 : dns secundario del isp +bind_addr1 : direccion primaria a la cual bindear +bind_addr2 : direccion secundaria a la cual bindear + +para crear una zona: +dns zone add + +para eliminar una zona: +dns zone delete + +para agregar un host a una zona: +dns host add + +para eliminar un host de una zona: +dns host delete + +para agregar un mail exchanger: +dns mx add + +para eliminar un mail exchanger: +dns mx delete + +para agregar un name server: +dns ns add + +para eliminar un name server: +dns ns delete + +ZONE : es el nombre de la zona a crear (ej : mizona.com) +HOSTNAME : nombre del host +IP_HOST : ip del host +MAILEXCHANGER : es un mail exchanger (ej: mx1.mizona.com) +PRIO : es la prioridad sobre el mail exchanger +NAMESERVER : es un name server (ej: ns1.mizona.com) + +----------------------------------- + +MODULO : IP + +para levantar un device : +ip dev up + +para bajar un device : +ip dev down + +para agregar una direccion ip : +ip addr add [BROADCAST] + +para eliminar una direccion ip : +ip addr add + +para ver las direcciones ip asignadas a un device: +ip addr show + +para agregar una ruta : +ip route add [DEVICE] + +para eliminar una ruta: +ip route delete [DEVICE] + +para ver las rutas asignadas: +ip route show [DEVICE] +ACLARACION : si una ruta fue dada de alta sin especificar un device, +la misma podra verse con "ip route show", caso contrario hay +que especificar el device + +para agregar un hop: +ip hop add + +para eliminar un hop: +ip hop delete + +para ver los hops : +ip hop show + + +DEVICE : el device (ej: eth0) +IP : direccion ip +PREFIX : prefijo de la direccion ip +BROADCAST : direccion de broadcast (ocpional) +NETADDR : direccion de red +GATEWAY : direccion del gateway +ROUTEINDEX : es el indice de la lista que muestra el comando show + +--------------------------------- + +MODULO : PPP + +para inciar/parar el servicio : +ppp start +ppp stop + +para agregar un coneccion : +ppp conn add [device=] [server=] + +para eliminar una coneccion : +ppp conn delete + +para mostrar las conecciones: +ppp show + +NAME : npmbre de la coneccion +USERNAME : nombre de usuario +PASSWORD : contraseña +TYPE : tipo de coneccion punto a punto, la misma puede ser : + OE : para pppoe , en este caso debera especificarse un device + TUNNEL : para ppptp , en este caso debera especificarse un server + PPP : para ppp , en este caso debera especificarse un device + +--------------------------------- + +MODULO : PROXY + +para inciar/parar el servicio : +proxy start +proxy stop + +para setear parametros: +proxy set +PARAMETER puede tomar los siguientes valores : +ip : direccion ip +port : puerto en donde se esucucha + +para agregar un host: +proxy host add + +para eliminar un host: +proxy host delete + +para ver los hosts: +proxy host show + +para agregar un user: +proxy user add + +para eliminar un user: +proxy user add + +para ver los usuarios: +proxy user show + +IP: la direccion ip del host +USERNAME : nombre de usuario +PASSWORD : contraseña + +--------------------------------- + +MODULO : VRRP + +para inciar/parar el servicio : +vrrp start +vrrp stop + +para setear parametros: +vrrp set +PARAMETER puede tomar los siguientes valores : +ipaddress : direccion ip +id : id dentro del grupo +prio : prioridad router +dev : device + +--------------------------------- + +MODULO : FIREWALL + +para iniciar/parar el servicio: +firewall start +firewall stop +(el stop elimina todas las reglas y deja todo abierto) + +Para agregar una regla: +firewall rule add [ ] + puede ser: INPUT, OUTPUT o FORWARD + puede ser: ACCEPT, REJECT o DROP + es la subred fuente (de la forma IP/máscara) + es la subred destino (de la forma IP/máscara) + es: ICMP, UDP, TCP o ALL + es el puerto fuente (solo válido si es UDP o TCP) + es el puerto destino (solo válido si es UDP o TCP) + +Para modificar una regla: +firewall rule update [ ] + es la posición de la regla (puede verse con 'firewall rule show') +El resto de los parámetros son iguales que para agregar una regla. + +Para borrar una regla: +firewall rule delete + es la posición de la regla (puede verse con 'firewall rule show') + +Para borrar todas las reglas: +firewall rule clear + +Para obtener información sobre una regla: +firewall rule get + es la posición de la regla (puede verse con 'firewall rule show') + +Para listar (obtener sobre todas) las reglas: +firewall rule show + +--------------------------------- + +MODULO : NAT + +para iniciar/parar el servicio: +nat start +nat stop +(el stop elimina todas las reglas) + +Para agregar una redirección de un puerto: +nat forward add [ ] + es el dispositivo de red a usar (por ej eth1) + es TCP o UDP + es el puerto entrante a redireccionar + es la IP de destino a donde redireccionar el puerto + es el puerto destino (si no se especifica, es el mismo que ) + es la subred fuente para la cual aplicar le redireccionamiento (IP/máscara) + es la subred destino para la cual aplicar le redireccionamiento (IP/máscara) +(si no se especifican subredes, se redirecciona todo el tráfico para el puerto) + +Para modificar una redirección de un puerto: +nat forward update [ ] + es la posición de la redirección (puede verse con 'nat forward show') +El resto de los parámetros son iguales que para agregar una redirección. + +Para borrar una redirección: +nat forward delete + es la posición de la redirección (puede verse con 'nat forward show') + +Para borrar todas las redirecciones: +nat forward clear + +Para obtener información sobre una redirección: +nat forward get + es la posición de la redirección (puede verse con 'nat forward show') + +Para listar (obtener información sobre todas) las redirecciones: +nat forward show + + +Para agregar un source nat: +nat snat add [] + es el dispositivo de red a usar (por ej eth1) + dirección IP fuente a NATear + es la subred fuente para la cual aplicar el source nat (IP/máscara) +(si no se especifica subred, se redirecciona todo el tráfico de la IP fuente) + +Para modificar un snat: +nat snat update [ ] + es la posición del snat (puede verse con 'nat snat show') +El resto de los parámetros son iguales que para agregar un snat. + +Para borrar un snat: +nat snat delete + es la posición del snat (puede verse con 'nat snat show') + +Para borrar todos los snat: +nat snat clear + +Para obtener información sobre un snat: +nat snat get + es la posición del snat (puede verse con 'nat snat show') + +Para listar (obtener información sobre todos) los snat: +nat snat show + + +Para agregar un enmascaramiento (masquerade): +nat masq add + es el dispositivo de red a usar (por ej eth1) + es la subred fuente para la cual aplicar el masq (IP/máscara) + +Para modificar un masq: +nat masq update [ ] + es la posición del snat (puede verse con 'nat masq show') +El resto de los parámetros son iguales que para agregar un masq. + +Para borrar un masq: +nat masq delete + es la posición del masq (puede verse con 'nat masq show') + +Para borrar todos los masq: +nat masq clear + +Para obtener información sobre un masq: +nat masq get + es la posición del masq (puede verse con 'nat masq show') + +Para listar (obtener información sobre todos) los masq: +nat masq show + + + diff --git a/pymin/services/ip/__init__.py b/pymin/services/ip/__init__.py index 0c0ea5f..b1d50b2 100644 --- a/pymin/services/ip/__init__.py +++ b/pymin/services/ip/__init__.py @@ -92,19 +92,51 @@ class Route(Sequence): self.net_addr = net_addr self.prefix = prefix self.gateway = gateway + def update(self, net_addr=None, prefix=None, gateway=None): if net_addr is not None: self.net_addr = net_addr if prefix is not None: self.prefix = prefix if gateway is not None: self.gateway = gateway + def as_tuple(self): return(self.net_addr, self.prefix, self.gateway) + def __cmp__(self, other): + if self.net_addr == other.net_addr \ + and self.prefix == other.prefix \ + and self.gateway == other.gateway: + return 0 + return cmp(id(self), id(other)) + class RouteHandler(ListComposedSubHandler): handler_help = u"Manage IP routes" _comp_subhandler_cont = 'devices' _comp_subhandler_attr = 'routes' _comp_subhandler_class = Route + @handler(u'Adds a route to : ip route add [device]') + def add(self, net_addr, prefix, gateway, dev=None): + if dev is not None: + ListComposedSubHandler.add(self, dev, net_addr, prefix, gateway) + else: + r = Route(net_addr, prefix, gateway) + if not r in self.parent.no_device_routes: + self.parent.no_device_routes.append(r) + + @handler("Deletes a route : ip route delete [dev]") + def delete(self, index, dev=None): + if dev is not None: + ListComposedSubHandler.delete(self, dev, index) + else: + i = int(index) + del self.parent.no_device_routes[i] + + @handler("Shows routes : ip route show [dev]") + def show(self, dev=None): + if dev is not None: + return ListComposedSubHandler.show(self, dev) + else: + return self.parent.no_device_routes class AddressHandler(DictComposedSubHandler): handler_help = u"Manage IP addresses" @@ -129,6 +161,20 @@ class DeviceHandler(SubHandler): def up(self, name): if name in self.parent.devices: call(self.device_template.render(dev=name, action='up'), shell=True) + #bring up all the route asocitaed to the device + for route in self.parent.devices[name].routes: + try: + call(self.parent._render_config('route_add', dict( + dev = name, + net_addr = route.net_addr, + prefix = route.prefix, + gateway = route.gateway, + ) + ), shell=True) + except ExecutionError, e: + print e + self.parent._bring_up_no_dev_routes() + self.parent._restart_services() else: raise DeviceNotFoundError(name) @@ -136,6 +182,8 @@ class DeviceHandler(SubHandler): def down(self, name): if name in self.parent.devices: call(self.device_template.render(dev=name, action='down'), shell=True) + self.parent._bring_up_no_dev_routes() + self.parent._restart_services() else: raise DeviceNotFoundError(name) @@ -151,11 +199,12 @@ class IpHandler(Restorable, ConfigWriter, TransactionalHandler): handler_help = u"Manage IP devices, addresses, routes and hops" - _persistent_attrs = ('devices','hops') + _persistent_attrs = ('devices','hops','no_device_routes') _restorable_defaults = dict( devices=get_network_devices(), - hops = list() + hops = list(), + no_device_routes = list(), ) _config_writer_files = ('device', 'ip_add', 'ip_del', 'ip_flush', @@ -173,57 +222,87 @@ class IpHandler(Restorable, ConfigWriter, TransactionalHandler): self.route = RouteHandler(self) self.dev = DeviceHandler(self) self.hop = HopHandler(self) + self.no_device_routes = list() + self.services = list() def _write_config(self): r"_write_config() -> None :: Execute all commands." for device in self.devices.values(): + if device.active: + self._write_config_for_device(device) + self._bring_up_no_dev_routes() + self._write_hops() + + def _bring_up_no_dev_routes(self): + for route in self.no_device_routes: try: - call(self._render_config('route_flush', dict(dev=device.name)), shell=True) - except ExecutionError, e: - print e - try: - call(self._render_config('ip_flush', dict(dev=device.name)), shell=True) + call(self._render_config('route_add', dict( + dev = None, + net_addr = route.net_addr, + prefix = route.prefix, + gateway = route.gateway, + ) + ), shell=True) except ExecutionError, e: print e - for address in device.addrs.values(): - broadcast = address.broadcast - if broadcast is None: - broadcast = '+' - try: - call(self._render_config('ip_add', dict( - dev = device.name, - addr = address.ip, - netmask = address.netmask, - peer = address.peer, - broadcast = broadcast, - ) - ), shell=True) - except ExecutionError, e: - print e - for route in device.routes: - try: - call(self._render_config('route_add', dict( - dev = device.name, - net_addr = route.net_addr, - prefix = route.prefix, - gateway = route.gateway, - ) - ), shell=True) - except ExecutionError, e: - print e + + def _write_hops(self): + r"_write_hops() -> None :: Execute all hops." if self.hops: try: call('ip route del default', shell=True) except ExecutionError, e: print e try: + #get hops for active devices + active_hops = dict() + for h in self.hops: + if h.device in self.devices: + if self.devices[h.device].active: + active_hops.append(h) call(self._render_config('hop', dict( - hops = self.hops, + hops = active_hops, ) ), shell=True) except ExecutionError, e: print e + def _write_config_for_device(self, device): + r"_write_config_for_device(self, device) -> None :: Execute all commands for a device." + try: + call(self._render_config('route_flush', dict(dev=device.name)), shell=True) + except ExecutionError, e: + print e + try: + call(self._render_config('ip_flush', dict(dev=device.name)), shell=True) + except ExecutionError, e: + print e + for address in device.addrs.values(): + broadcast = address.broadcast + if broadcast is None: + broadcast = '+' + try: + call(self._render_config('ip_add', dict( + dev = device.name, + addr = address.ip, + netmask = address.netmask, + peer = address.peer, + broadcast = broadcast, + ) + ), shell=True) + except ExecutionError, e: + print e + for route in device.routes: + try: + call(self._render_config('route_add', dict( + dev = device.name, + net_addr = route.net_addr, + prefix = route.prefix, + gateway = route.gateway, + ) + ), shell=True) + except ExecutionError, e: + print e def handle_timer(self): self.refresh_devices() @@ -231,14 +310,49 @@ class IpHandler(Restorable, ConfigWriter, TransactionalHandler): def refresh_devices(self): devices = get_network_devices() - #add not registered devices + #add not registered and active devices + go_active = False for k,v in devices.items(): if k not in self.devices: self.devices[k] = v - #delete dead devices + elif not self.devices[k].active: + self.active = True + go_active = True + self._write_config_for_device(self.devices[k]) + if go_active: + self._write_hops() + self._bring_up_no_dev_routes() + self._restart_services() + + #mark inactive devices for k in self.devices.keys(): + go_down = False if k not in devices: - del self.devices[k] + self.devices[k].active = False + go_down = True + if go_down: + self._bring_up_no_dev_routes() + + def _restart_services(self): + for s in self.services: + if s._service_running: + try: + s.stop() + except ExecutionError: + pass + try: + s.start() + except ExecutionError: + pass + + #hooks a service to the ip handler, so when + #a device is brought up one can restart the service + #that need to refresh their device list + def device_up_hook(self, serv): + if hasattr(serv, 'stop') and hasattr(serv, 'start'): + self.services.append(serv) + + diff --git a/pymin/services/ip/templates/route_add b/pymin/services/ip/templates/route_add index 4b92915..fdaf1a4 100644 --- a/pymin/services/ip/templates/route_add +++ b/pymin/services/ip/templates/route_add @@ -1 +1,5 @@ -ip route add dev ${dev} ${net_addr}/${prefix} via ${gateway} \ No newline at end of file +%if dev is not None: +ip route add dev ${dev} ${net_addr}/${prefix} via ${gateway} +%else: +ip route add ${net_addr}/${prefix} via ${gateway} +%endif \ No newline at end of file diff --git a/pymin/services/qos/__init__.py b/pymin/services/qos/__init__.py index ca09d9d..905e4ca 100644 --- a/pymin/services/qos/__init__.py +++ b/pymin/services/qos/__init__.py @@ -8,26 +8,56 @@ from pymin.dispatcher import handler, HandlerError, Handler from pymin.services.util import Restorable, ConfigWriter, InitdHandler, \ TransactionalHandler, SubHandler, call, \ get_network_devices, ListComposedSubHandler, \ - DictComposedSubHandler + DictComposedSubHandler, ExecutionError __ALL__ = ('QoSHandler',) +class DeviceError(HandlerError): + + def __init__(self, dev): + self.message = u'Devive error : "%s"' % dev + + +class DeviceNotFoundError(DeviceError): + + def __init__(self, dev): + self.message = u'Device not found : "%s"' % dev + + class ClassError(HandlerError): - def __init__(self, qosclass): - self.message = u'Class error : "%s"' % qosclass + def __init__(self, cls): + self.message = u'Class error : "%s"' % cls class ClassNotFoundError(ClassError): - def __init__(self, qosclass): - self.message = u'Class not found : "%s"' % qosclass + def __init__(self, cls): + self.message = u'Class not found : "%s"' % cls class ClassAlreadyExistsError(ClassError): - def __init__(self, qosclass): - self.message = u'Class already exists : "%s"' % qosclass + def __init__(self, cls): + self.message = u'Class already exists : "%s"' % cls + + +class HostError(HandlerError): + + def __init__(self, host): + self.message = u'Host error : "%s"' % host + + +class HostNotFoundError(HostError): + + def __init__(self, ip): + self.message = u'Host not found : "%s"' % host + + +class HostAlreadyExistsError(HostError): + + def __init__(self, ip): + self.message = u'Host already exists : "%s"' % host class Class(Sequence): @@ -35,7 +65,7 @@ class Class(Sequence): def __init__(self, cid, rate=None): self.cid = cid self.rate = rate - self.hosts = list() + self.hosts = dict() def as_tuple(self): return (self.cid, self.rate) @@ -52,40 +82,31 @@ class ClassHandler(Handler): self.parent = parent @handler('Adds a class : add ') - def add(self, cid, dev, rate): + def add(self, dev, cid, rate): if not dev in self.parent.devices: - raise DeviceNotFoundError(device) - c = Class(cid, dev, rate) + raise DeviceNotFoundError(dev) + try: - self.parent.classes.index(c) - raise ClassAlreadyExistsError(cid + '->' + dev) + self.parent.devices[dev].classes[cid] = Class(cid, rate) except ValueError: - self.parent.classes.append(c) + raise ClassAlreadyExistsError(cid + ' -> ' + dev) @handler(u'Deletes a class : delete ') - def delete(self, cid, dev): + def delete(self, dev, cid): if not dev in self.parent.devices: - raise DeviceNotFoundError(device) - c = Class(cid, dev) + raise DeviceNotFoundError(dev) + try: - self.parent.classes.remove(c) - except ValueError: - raise ClassNotFoundError(cid + '->' + dev) + del self.parent.devices[dev].classes[cid] + except KeyError: + raise ClassNotFoundError(cid + ' -> ' + dev) @handler(u'Lists classes : list ') - def list(self, device): + def list(self, dev): try: - k = self.parent.classes.keys() - except ValueError: - k = list() - return k - - @handler(u'Get information about all classes: show ') - def show(self, device): - try: - k = self.parent.classes.values() - except ValueError: - k = list() + k = self.parent.devices[dev].classes.items() + except KeyError: + k = dict() return k @@ -97,12 +118,37 @@ class Host(Sequence): def as_tuple(self): return (self.ip) + def __cmp__(self, other): + if self.ip == other.ip: + return 0 + return cmp(id(self), id(other)) + + +class HostHandler(SubHandler): -class HostHandler(DictComposedSubHandler): - handler_help = u"Manage Hosts" - _comp_subhandler_cont = 'classes' - _comp_subhandler_attr = 'hosts' - _comp_subhandler_class = Host + def __init__(self, parent): + self.parent = parent + + @handler('Adds a host to a class : add ') + def add(self, dev, cid, ip): + if not dev in self.parent.devices: + raise DeviceNotFoundError(dev) + + if not cid in self.parent.devices[dev].classes: + raise ClassNotFoundError(cid) + + try: + self.parent.devices[dev].classes[cid].hosts[ip] = Host(ip) + except ValueError: + raise HostAlreadyExistsError(h + ' -> ' + dev) + + @handler(u'Lists hosts : list ') + def list(self, dev, cid): + try: + k = self.parent.devices[dev].classes[cid].hosts.keys() + except KeyError: + k = dict() + return k class Device(Sequence): @@ -110,7 +156,7 @@ class Device(Sequence): def __init__(self, name, mac): self.name = name self.mac = mac - self.classes = list() + self.classes = dict() def as_tuple(self): return (self.name, self.mac) @@ -131,14 +177,20 @@ class DeviceHandler(SubHandler): @handler(u'Bring the device up') def up(self, name): if name in self.parent.devices: - call(self.device_template.render(dev=name, action='add'), shell=True) + try: + call(self.device_template.render(dev=name, action='add'), shell=True) + except ExecutionError: + pass else: raise DeviceNotFoundError(name) @handler(u'Bring the device down') def down(self, name): if name in self.parent.devices: - call(self.device_template.render(dev=name, action='del'), shell=True) + try: + call(self.device_template.render(dev=name, action='del'), shell=True) + except ExecutionError: + pass else: raise DeviceNotFoundError(name) @@ -155,13 +207,11 @@ class QoSHandler(Restorable, ConfigWriter, TransactionalHandler): handler_help = u"Manage QoS devices, classes and hosts" - _persistent_attrs = ('devices','classes','hosts') + _persistent_attrs = ('devices') _restorable_defaults = dict( devices=dict((dev, Device(dev, mac)) - for (dev, mac) in get_network_devices().items()), - classes = list(), - hosts = list() + for (dev, mac) in get_network_devices().items()) ) _config_writer_files = ('device', 'class_add', 'class_del', 'host_add') @@ -176,28 +226,43 @@ class QoSHandler(Restorable, ConfigWriter, TransactionalHandler): self._restore() self._write_config() self.dev = DeviceHandler(self) - self.classes = ClassHandler(self) - self.hosts = HostHandler(self) + self.cls = ClassHandler(self) + self.host = HostHandler(self) def _write_config(self): r"_write_config() -> None :: Execute all commands." for device in self.devices.values(): - call(self._render_config('device', dict(dev=device.name, action='del')), shell=True) - call(self._render_config('device', dict(dev=device.name, action='add')), shell=True) - for qosclass in device.classes: - call(self._render_config('class_add', dict( + try: + call(self._render_config('device', dict(dev=device.name, action='del')), shell=True) + except ExecutionError: + pass + + try: + call(self._render_config('device', dict(dev=device.name, action='add')), shell=True) + except ExecutionError: + pass + + for cls in device.classes.values(): + try: + call(self._render_config('class_add', dict( dev = device.name, - cid = qosclass.cid, - rate = qosclass.rate - ) - ), shell=True) - for host in qosclass.hosts: - call(self._render_config('host_add', dict( - dev = device.name, - ip = host.ip, - cid = qosclass.cid + cid = cls.cid, + rate = cls.rate ) ), shell=True) + except ExecutionError: + pass + + for host in cls.hosts.values(): + try: + call(self._render_config('host_add', dict( + dev = device.name, + ip = host.ip, + cid = cls.cid + ) + ), shell=True) + except ExecutionError: + pass def handle_timer(self): self.refresh_devices() diff --git a/pymin/services/qos/templates/class_add b/pymin/services/qos/templates/class_add index 5570e46..7f62e35 100644 --- a/pymin/services/qos/templates/class_add +++ b/pymin/services/qos/templates/class_add @@ -1 +1 @@ -tc class add dev ${dev} classid 1:${id} htb rate ${rate} +tc class add dev ${dev} classid 1:${cid} htb rate ${rate}kbps diff --git a/pymin/services/qos/templates/host_add b/pymin/services/qos/templates/host_add index 096dca9..d14de00 100644 --- a/pymin/services/qos/templates/host_add +++ b/pymin/services/qos/templates/host_add @@ -1 +1 @@ -tc filter add dev ${dev} protocol ip u32 match ip src ${ip} flowid 1:{id} +tc filter add dev ${dev} protocol ip u32 match ip src ${ip} flowid 1:${cid} diff --git a/pymin/services/util.py b/pymin/services/util.py index a7ec0e4..cb97815 100644 --- a/pymin/services/util.py +++ b/pymin/services/util.py @@ -155,10 +155,11 @@ class Device(Sequence): self.name = name self.mac = mac self.ppp = ppp + self.active = True self.addrs = dict() self.routes = list() def as_tuple(self): - return (self.name, self.mac, self.addrs) + return (self.name, self.mac, self.active, self.addrs)