CPlatform.py revision 6e425446
1#!/router/bin/python
2
3from interfaces_e import IFType
4from platform_cmd_link import *
5import CustomLogger
6import misc_methods
7import re
8import time
9import CProgressDisp
10from CShowParser import CShowParser
11
12class CPlatform(object):
13    def __init__(self, silent_mode):
14        self.if_mngr            = CIfManager()
15        self.cmd_link           = CCommandLink(silent_mode)
16        self.nat_config         = None
17        self.stat_route_config  = None
18        self.running_image      = None
19        self.needed_image_path  = None
20        self.tftp_cfg           = None
21        self.config_history     = { 'basic_if_config' : False, 'tftp_server_config' : False }
22
23    def configure_basic_interfaces(self, mtu = 4000):
24
25        cache = CCommandCache()
26        for dual_if in self.if_mngr.get_dual_if_list():
27            client_if_command_set   = []
28            server_if_command_set   = []
29
30            client_if_command_set.append ('mac-address {mac}'.format( mac = dual_if.client_if.get_src_mac_addr()) )
31            client_if_command_set.append ('mtu %s' % mtu)
32            client_if_command_set.append ('ip address {ip} 255.255.255.0'.format( ip = dual_if.client_if.get_ipv4_addr() ))
33            client_if_command_set.append ('ipv6 address {ip}/64'.format( ip = dual_if.client_if.get_ipv6_addr() ))
34
35            cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
36
37            server_if_command_set.append ('mac-address {mac}'.format( mac = dual_if.server_if.get_src_mac_addr()) )
38            server_if_command_set.append ('mtu %s' % mtu)
39            server_if_command_set.append ('ip address {ip} 255.255.255.0'.format( ip = dual_if.server_if.get_ipv4_addr() ))
40            server_if_command_set.append ('ipv6 address {ip}/64'.format( ip = dual_if.server_if.get_ipv6_addr() ))
41
42            cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
43
44        self.cmd_link.run_single_command(cache)
45        self.config_history['basic_if_config'] = True
46
47
48
49    def configure_basic_filtered_interfaces(self, intf_list, mtu = 4000):
50
51        cache = CCommandCache()
52        for intf in intf_list:
53            if_command_set   = []
54
55            if_command_set.append ('mac-address {mac}'.format( mac = intf.get_src_mac_addr()) )
56            if_command_set.append ('mtu %s' % mtu)
57            if_command_set.append ('ip address {ip} 255.255.255.0'.format( ip = intf.get_ipv4_addr() ))
58            if_command_set.append ('ipv6 address {ip}/64'.format( ip = intf.get_ipv6_addr() ))
59
60            cache.add('IF', if_command_set, intf.get_name())
61
62        self.cmd_link.run_single_command(cache)
63
64
65    def load_clean_config (self, config_filename = "clean_config.cfg", cfg_drive = "bootflash"):
66        self.clear_nat_translations()
67
68        cache = CCommandCache()
69        cache.add('EXEC', "configure replace {drive}:{file} force".format(drive = cfg_drive, file = config_filename))
70        self.cmd_link.run_single_command(cache)
71
72    def config_pbr (self, mode = 'config'):
73        idx = 1
74        unconfig_str = '' if mode=='config' else 'no '
75
76        cache = CCommandCache()
77        pre_commit_cache = CCommandCache()
78        pre_commit_set = set([])
79
80        for dual_if in self.if_mngr.get_dual_if_list():
81            client_if_command_set   = []
82            server_if_command_set   = []
83            conf_t_command_set      = []
84            client_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.server_if.get_ipv4_addr() )
85            server_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.client_if.get_ipv4_addr() )
86
87            if dual_if.is_duplicated():
88                # define the relevant VRF name
89                pre_commit_set.add('{mode}ip vrf {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
90
91                # assign VRF to interfaces, config interfaces with relevant route-map
92                client_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
93                client_if_command_set.append ('{mode}ip policy route-map {dup}_{p1}_to_{p2}'.format(
94                    mode = unconfig_str,
95                    dup = dual_if.get_vrf_name(),
96                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
97                server_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
98                server_if_command_set.append ('{mode}ip policy route-map {dup}_{p2}_to_{p1}'.format(
99                    mode = unconfig_str,
100                    dup = dual_if.get_vrf_name(),
101                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
102
103                # config route-map routing
104                conf_t_command_set.append('{mode}route-map {dup}_{p1}_to_{p2} permit 10'.format(
105                    mode = unconfig_str,
106                    dup = dual_if.get_vrf_name(),
107                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
108                if mode == 'config':
109                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
110                         next_hop = client_net_next_hop) )
111                conf_t_command_set.append('{mode}route-map {dup}_{p2}_to_{p1} permit 10'.format(
112                    mode = unconfig_str,
113                    dup = dual_if.get_vrf_name(),
114                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
115                if mode == 'config':
116                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
117                         next_hop = server_net_next_hop) )
118
119                # config global arp to interfaces net address and vrf
120                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
121                    mode = unconfig_str,
122                    dup = dual_if.get_vrf_name(),
123                    next_hop = server_net_next_hop,
124                    dest_mac = dual_if.client_if.get_dest_mac()))
125                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
126                    mode = unconfig_str,
127                    dup = dual_if.get_vrf_name(),
128                    next_hop = client_net_next_hop,
129                    dest_mac = dual_if.server_if.get_dest_mac()))
130            else:
131                # config interfaces with relevant route-map
132                client_if_command_set.append ('{mode}ip policy route-map {p1}_to_{p2}'.format(
133                    mode = unconfig_str,
134                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
135                server_if_command_set.append ('{mode}ip policy route-map {p2}_to_{p1}'.format(
136                    mode = unconfig_str,
137                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
138
139                # config route-map routing
140                conf_t_command_set.append('{mode}route-map {p1}_to_{p2} permit 10'.format(
141                    mode = unconfig_str,
142                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
143                if mode == 'config':
144                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
145                         next_hop = client_net_next_hop) )
146                conf_t_command_set.append('{mode}route-map {p2}_to_{p1} permit 10'.format(
147                    mode = unconfig_str,
148                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
149                if mode == 'config':
150                    conf_t_command_set.append('set ip next-hop {next_hop}'.format(
151                         next_hop = server_net_next_hop) )
152
153                # config global arp to interfaces net address
154                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
155                    mode = unconfig_str,
156                    next_hop = server_net_next_hop,
157                    dest_mac = dual_if.client_if.get_dest_mac()))
158                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
159                    mode = unconfig_str,
160                    next_hop = client_net_next_hop,
161                    dest_mac = dual_if.server_if.get_dest_mac()))
162
163            # assign generated config list to cache
164            cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
165            cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
166            cache.add('CONF', conf_t_command_set)
167            idx += 2
168
169        # finish handling pre-config cache
170        pre_commit_set = list(pre_commit_set)
171#       pre_commit_set.append('exit')
172        pre_commit_cache.add('CONF', pre_commit_set )
173        # deploy the configs (order is important!)
174        self.cmd_link.run_command( [pre_commit_cache, cache] )
175        if self.config_history['basic_if_config']:
176            # in this case, duplicated interfaces will lose its ip address.
177            # re-config IPv4 addresses
178            self.configure_basic_filtered_interfaces(self.if_mngr.get_duplicated_if() )
179
180    def config_no_pbr (self):
181        self.config_pbr(mode = 'unconfig')
182
183    def config_static_routing (self, stat_route_obj, mode = 'config'):
184
185        if mode == 'config':
186            self.stat_route_config = stat_route_obj   # save the latest static route config for future removal purposes
187
188        unconfig_str = '' if mode=='config' else 'no '
189        cache              = CCommandCache()
190        pre_commit_cache   = CCommandCache()
191        pre_commit_set     = set([])
192        current_dup_intf   = None
193        # client_net       = None
194        # server_net       = None
195        client_net         = stat_route_obj.client_net_start
196        server_net         = stat_route_obj.server_net_start
197        conf_t_command_set = []
198
199        for dual_if in self.if_mngr.get_dual_if_list():
200
201            # handle duplicated addressing generation
202            if dual_if.is_duplicated():
203                if dual_if.get_vrf_name() != current_dup_intf:
204                    # if this is a dual interfaces, and it is different from the one we proccessed so far, reset static route addressing
205                    current_dup_intf = dual_if.get_vrf_name()
206                    client_net       = stat_route_obj.client_net_start
207                    server_net       = stat_route_obj.server_net_start
208            else:
209                if current_dup_intf is not None:
210                    current_dup_intf = None
211                    client_net       = stat_route_obj.client_net_start
212                    server_net       = stat_route_obj.server_net_start
213
214            client_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.server_if.get_ipv4_addr() )
215            server_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.client_if.get_ipv4_addr() )
216
217            # handle static route configuration for the interfaces
218            if dual_if.is_duplicated():
219                client_if_command_set   = []
220                server_if_command_set   = []
221
222                # define the relevant VRF name
223                pre_commit_set.add('{mode}ip vrf {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
224
225                # assign VRF to interfaces, config interfaces with relevant route-map
226                client_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
227                server_if_command_set.append ('{mode}ip vrf forwarding {dup}'.format( mode = unconfig_str, dup = dual_if.get_vrf_name()) )
228
229                conf_t_command_set.append( "{mode}ip route vrf {dup} {next_net} {dest_mask} {next_hop}".format(
230                    mode = unconfig_str,
231                    dup = dual_if.get_vrf_name(),
232                    next_net = client_net,
233                    dest_mask = stat_route_obj.client_mask,
234                    next_hop = client_net_next_hop))
235                conf_t_command_set.append( "{mode}ip route vrf {dup} {next_net} {dest_mask} {next_hop}".format(
236                    mode = unconfig_str,
237                    dup = dual_if.get_vrf_name(),
238                    next_net = server_net,
239                    dest_mask = stat_route_obj.server_mask,
240                    next_hop = server_net_next_hop))
241
242                # config global arp to interfaces net address and vrf
243                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
244                    mode = unconfig_str,
245                    dup = dual_if.get_vrf_name(),
246                    next_hop = server_net_next_hop,
247                    dest_mac = dual_if.client_if.get_dest_mac()))
248                conf_t_command_set.append('{mode}arp vrf {dup} {next_hop} {dest_mac} arpa'.format(
249                    mode = unconfig_str,
250                    dup = dual_if.get_vrf_name(),
251                    next_hop = client_net_next_hop,
252                    dest_mac = dual_if.server_if.get_dest_mac()))
253
254                # assign generated interfaces config list to cache
255                cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
256                cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
257
258            else:
259                conf_t_command_set.append( "{mode}ip route {next_net} {dest_mask} {next_hop}".format(
260                    mode = unconfig_str,
261                    next_net = client_net,
262                    dest_mask = stat_route_obj.client_mask,
263                    next_hop = server_net_next_hop))
264                conf_t_command_set.append( "{mode}ip route {next_net} {dest_mask} {next_hop}".format(
265                    mode = unconfig_str,
266                    next_net = server_net,
267                    dest_mask = stat_route_obj.server_mask,
268                    next_hop = client_net_next_hop))
269
270                # config global arp to interfaces net address
271                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
272                    mode = unconfig_str,
273                    next_hop = server_net_next_hop,
274                    dest_mac = dual_if.client_if.get_dest_mac()))
275                conf_t_command_set.append('{mode}arp {next_hop} {dest_mac} arpa'.format(
276                    mode = unconfig_str,
277                    next_hop = client_net_next_hop,
278                    dest_mac = dual_if.server_if.get_dest_mac()))
279
280            # bump up to the next client network address
281            client_net = misc_methods.get_single_net_client_addr(client_net, stat_route_obj.net_increment)
282            server_net = misc_methods.get_single_net_client_addr(server_net, stat_route_obj.net_increment)
283
284
285        # finish handling pre-config cache
286        pre_commit_set = list(pre_commit_set)
287#       pre_commit_set.append('exit')
288        pre_commit_cache.add('CONF', pre_commit_set )
289        # assign generated config list to cache
290        cache.add('CONF', conf_t_command_set)
291        # deploy the configs (order is important!)
292        self.cmd_link.run_command( [pre_commit_cache, cache] )
293        if self.config_history['basic_if_config']:
294            # in this case, duplicated interfaces will lose its ip address.
295            # re-config IPv4 addresses
296            self.configure_basic_filtered_interfaces(self.if_mngr.get_duplicated_if() )
297
298
299    def config_no_static_routing (self, stat_route_obj = None):
300
301        if stat_route_obj is None and self.stat_route_config is not None:
302            self.config_static_routing(self.stat_route_config, mode = 'unconfig')
303            self.stat_route_config = None  # reverse current static route config back to None (no nat config is known to run).
304        elif stat_route_obj is not None:
305            self.config_static_routing(stat_route_obj, mode = 'unconfig')
306        else:
307            raise UserWarning('No static route configuration is available for removal.')
308
309    def config_nbar_pd (self, mode = 'config'):
310        unconfig_str = '' if mode=='config' else 'no '
311        cache = CCommandCache()
312
313        for intf in self.if_mngr.get_if_list(if_type = IFType.Client):
314            cache.add('IF', "{mode}ip nbar protocol-discovery".format( mode = unconfig_str ), intf.get_name())
315
316        self.cmd_link.run_single_command( cache )
317
318    def config_no_nbar_pd (self):
319        self.config_nbar_pd (mode = 'unconfig')
320
321
322    def config_nat_verify (self, mode = 'config'):
323
324        # toggle all duplicate interfaces
325        # dup_ifs = self.if_mngr.get_duplicated_if()
326        if mode=='config':
327            self.toggle_duplicated_intf(action = 'down')
328            # self.__toggle_interfaces(dup_ifs, action = 'down' )
329        else:
330            # if we're in 'unconfig', toggle duplicated interfaces back up
331            self.toggle_duplicated_intf(action = 'up')
332            # self.__toggle_interfaces(dup_ifs)
333
334    def config_no_nat_verify (self):
335        self.config_nat_verify(mode = 'unconfig')
336
337    def config_nat (self, nat_obj, mode = 'config'):
338
339        if mode == 'config':
340            self.nat_config = nat_obj   # save the latest nat config for future removal purposes
341
342        cache               = CCommandCache()
343        conf_t_command_set  = []
344        client_net          = nat_obj.clients_net_start
345        pool_net            = nat_obj.nat_pool_start
346        unconfig_str        = '' if mode=='config' else 'no '
347
348        # toggle all duplicate interfaces
349        # dup_ifs = self.if_mngr.get_duplicated_if()
350        if mode=='config':
351            self.toggle_duplicated_intf(action = 'down')
352            # self.__toggle_interfaces(dup_ifs, action = 'down' )
353        else:
354            # if we're in 'unconfig', toggle duplicated interfaces back up
355            self.toggle_duplicated_intf(action = 'up')
356            # self.__toggle_interfaces(dup_ifs)
357
358        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
359            cache.add('IF', "{mode}ip nat inside".format( mode = unconfig_str ), dual_if.client_if.get_name())
360            cache.add('IF', "{mode}ip nat outside".format( mode = unconfig_str ), dual_if.server_if.get_name())
361            pool_id = dual_if.get_id() + 1
362
363            conf_t_command_set.append("{mode}ip nat pool pool{pool_num} {start_addr} {end_addr} netmask {mask}".format(
364                mode = unconfig_str,
365                pool_num = pool_id,
366                start_addr = pool_net,
367                end_addr = CNatConfig.calc_pool_end(pool_net, nat_obj.nat_netmask),
368                mask = nat_obj.nat_netmask))
369
370            conf_t_command_set.append("{mode}ip nat inside source list {num} pool pool{pool_num} overload".format(
371                mode = unconfig_str,
372                num = pool_id,
373                pool_num = pool_id ))
374            conf_t_command_set.append("{mode}access-list {num} permit {net_addr} {net_wildcard}".format(
375                mode = unconfig_str,
376                num = pool_id,
377                net_addr = client_net,
378                net_wildcard = nat_obj.client_acl_wildcard))
379
380            # bump up to the next client address
381            client_net = misc_methods.get_single_net_client_addr(client_net, nat_obj.net_increment)
382            pool_net   = misc_methods.get_single_net_client_addr(pool_net, nat_obj.net_increment)
383
384
385        # assign generated config list to cache
386        cache.add('CONF', conf_t_command_set)
387
388        # deploy the configs (order is important!)
389        self.cmd_link.run_single_command( cache )
390
391
392    def config_no_nat (self, nat_obj = None):
393        # first, clear all nat translations
394        self.clear_nat_translations()
395
396        # then, decompose the known config
397        if nat_obj is None and self.nat_config is not None:
398            self.config_nat(self.nat_config, mode = 'unconfig')
399            self.nat_config = None  # reverse current NAT config back to None (no nat config is known to run).
400        elif nat_obj is not None:
401            self.config_nat(nat_obj, mode = 'unconfig')
402        else:
403            raise UserWarning('No NAT configuration is available for removal.')
404
405
406    def config_zbf (self, mode = 'config'):
407        cache               = CCommandCache()
408        pre_commit_cache    = CCommandCache()
409        conf_t_command_set  = []
410
411        # toggle all duplicate interfaces down
412        self.toggle_duplicated_intf(action = 'down')
413        # dup_ifs = self.if_mngr.get_duplicated_if()
414        # self.__toggle_interfaces(dup_ifs, action = 'down' )
415
416        # define security zones and security service policy to be applied on the interfaces
417        conf_t_command_set.append('class-map type inspect match-any c1')
418        conf_t_command_set.append('match protocol tcp')
419        conf_t_command_set.append('match protocol udp')
420        conf_t_command_set.append('policy-map type inspect p1')
421        conf_t_command_set.append('class type inspect c1')
422        conf_t_command_set.append('inspect')
423        conf_t_command_set.append('class class-default')
424        conf_t_command_set.append('pass')
425
426        conf_t_command_set.append('zone security z_in')
427        conf_t_command_set.append('zone security z_out')
428
429        conf_t_command_set.append('zone-pair security in2out source z_in destination z_out')
430        conf_t_command_set.append('service-policy type inspect p1')
431        conf_t_command_set.append('zone-pair security out2in source z_out destination z_in')
432        conf_t_command_set.append('service-policy type inspect p1')
433        conf_t_command_set.append('exit')
434
435        pre_commit_cache.add('CONF', conf_t_command_set)
436
437        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
438            cache.add('IF', "zone-member security z_in", dual_if.client_if.get_name() )
439            cache.add('IF', "zone-member security z_out", dual_if.server_if.get_name() )
440
441        self.cmd_link.run_command( [pre_commit_cache, cache] )
442
443    def config_no_zbf (self):
444        cache               = CCommandCache()
445        conf_t_command_set  = []
446
447        # define security zones and security service policy to be applied on the interfaces
448        conf_t_command_set.append('no zone-pair security in2out source z_in destination z_out')
449        conf_t_command_set.append('no zone-pair security out2in source z_out destination z_in')
450
451        conf_t_command_set.append('no policy-map type inspect p1')
452        conf_t_command_set.append('no class-map type inspect match-any c1')
453
454        conf_t_command_set.append('no zone security z_in')
455        conf_t_command_set.append('no zone security z_out')
456
457        cache.add('CONF', conf_t_command_set)
458
459        for dual_if in self.if_mngr.get_dual_if_list(is_duplicated = False):
460            cache.add('IF', "no zone-member security z_in", dual_if.client_if.get_name() )
461            cache.add('IF', "no zone-member security z_out", dual_if.server_if.get_name() )
462
463        self.cmd_link.run_command( [cache] )
464        # toggle all duplicate interfaces back up
465        self.toggle_duplicated_intf(action = 'up')
466        # dup_ifs = self.if_mngr.get_duplicated_if()
467        # self.__toggle_interfaces(dup_ifs)
468
469
470    def config_ipv6_pbr (self, mode = 'config'):
471        idx = 1
472        unconfig_str = '' if mode=='config' else 'no '
473        cache               = CCommandCache()
474        conf_t_command_set  = []
475
476        conf_t_command_set.append('{mode}ipv6 unicast-routing'.format(mode = unconfig_str) )
477
478        for dual_if in self.if_mngr.get_dual_if_list():
479            client_if_command_set   = []
480            server_if_command_set   = []
481
482            client_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.server_if.get_ipv6_addr(), {'7':1}, ip_type = 'ipv6' )
483            server_net_next_hop = misc_methods.get_single_net_client_addr(dual_if.client_if.get_ipv6_addr(), {'7':1}, ip_type = 'ipv6' )
484
485
486            client_if_command_set.append ('{mode}ipv6 enable'.format(mode = unconfig_str))
487            server_if_command_set.append ('{mode}ipv6 enable'.format(mode = unconfig_str))
488
489            if dual_if.is_duplicated():
490                prefix = 'ipv6_' + dual_if.get_vrf_name()
491            else:
492                prefix = 'ipv6'
493
494            # config interfaces with relevant route-map
495            client_if_command_set.append ('{mode}ipv6 policy route-map {pre}_{p1}_to_{p2}'.format(
496                mode = unconfig_str,
497                pre = prefix,
498                p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
499            server_if_command_set.append ('{mode}ipv6 policy route-map {pre}_{p2}_to_{p1}'.format(
500                mode = unconfig_str,
501                pre = prefix,
502                p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
503
504            # config global arp to interfaces net address and vrf
505            conf_t_command_set.append('{mode}ipv6 neighbor {next_hop} {intf} {dest_mac}'.format(
506                    mode = unconfig_str,
507                    next_hop = server_net_next_hop,
508                    intf = dual_if.client_if.get_name(),
509                    dest_mac = dual_if.client_if.get_dest_mac()))
510            conf_t_command_set.append('{mode}ipv6 neighbor {next_hop} {intf} {dest_mac}'.format(
511                    mode = unconfig_str,
512                    next_hop = client_net_next_hop,
513                    intf = dual_if.server_if.get_name(),
514                    dest_mac = dual_if.server_if.get_dest_mac()))
515
516            conf_t_command_set.append('{mode}route-map {pre}_{p1}_to_{p2} permit 10'.format(
517                    mode = unconfig_str,
518                    pre = prefix,
519                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
520            if (mode == 'config'):
521                conf_t_command_set.append('set ipv6 next-hop {next_hop}'.format(next_hop = client_net_next_hop ) )
522            conf_t_command_set.append('{mode}route-map {pre}_{p2}_to_{p1} permit 10'.format(
523                    mode = unconfig_str,
524                    pre = prefix,
525                    p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) )
526            if (mode == 'config'):
527                conf_t_command_set.append('set ipv6 next-hop {next_hop}'.format(next_hop = server_net_next_hop ) )
528                conf_t_command_set.append('exit')
529
530            # assign generated config list to cache
531            cache.add('IF', server_if_command_set, dual_if.server_if.get_name())
532            cache.add('IF', client_if_command_set, dual_if.client_if.get_name())
533            idx += 2
534
535        cache.add('CONF', conf_t_command_set)
536
537        # deploy the configs (order is important!)
538        self.cmd_link.run_command( [cache] )
539
540    def config_no_ipv6_pbr (self):
541        self.config_ipv6_pbr(mode = 'unconfig')
542
543    # show methods
544    def get_cpu_util (self):
545        response    = self.cmd_link.run_single_command('show platform hardware qfp active datapath utilization | inc Load')
546        return CShowParser.parse_cpu_util_stats(response)
547
548    def get_cft_stats (self):
549        response    = self.cmd_link.run_single_command('test platform hardware qfp active infrastructure cft datapath function cft-cpp-show-all-instances')
550        return CShowParser.parse_cft_stats(response)
551
552    def get_nbar_stats (self):
553        per_intf_stats = {}
554        for intf in self.if_mngr.get_if_list(if_type = IFType.Client):
555            response = self.cmd_link.run_single_command("show ip nbar protocol-discovery interface {interface} stats packet-count protocol".format( interface = intf.get_name() ), flush_first = True)
556            per_intf_stats[intf.get_name()] = CShowParser.parse_nbar_stats(response)
557        return per_intf_stats
558
559    def get_nbar_profiling_stats (self):
560        response = self.cmd_link.run_single_command("show platform hardware qfp active feature nbar profiling")
561        return CShowParser.parse_nbar_profiling_stats(response)
562
563    def get_drop_stats (self):
564
565        response    = self.cmd_link.run_single_command('show platform hardware qfp active interface all statistics', flush_first = True)
566        # print response
567        # response    = self.cmd_link.run_single_command('show platform hardware qfp active interface all statistics')
568        # print response
569        if_list_by_name = map( lambda x: x.get_name(), self.if_mngr.get_if_list() )
570        return CShowParser.parse_drop_stats(response, if_list_by_name )
571
572    def get_nat_stats (self):
573        response    = self.cmd_link.run_single_command('show ip nat statistics')
574        return CShowParser.parse_nat_stats(response)
575
576    def get_cvla_memory_usage(self):
577        response    = self.cmd_link.run_single_command('show platform hardware qfp active infrastructure cvla client handles')
578        # (res, res2) = CShowParser.parse_cvla_memory_usage(response)
579        return CShowParser.parse_cvla_memory_usage(response)
580
581
582    # clear methods
583    def clear_nat_translations(self):
584        pre_commit_cache = CCommandCache()
585        pre_commit_cache.add('EXEC', 'clear ip nat translation *')
586        self.cmd_link.run_single_command( pre_commit_cache )
587
588    def clear_cft_counters (self):
589        """ clear_cft_counters(self) -> None
590
591        Clears the CFT counters on the platform
592        """
593        self.cmd_link.run_single_command('test platform hardware qfp active infrastructure cft datapath function cft-cpp-clear-instance-stats')
594
595    def clear_counters(self):
596        """ clear_counters(self) -> None
597
598        Clears the platform counters
599        """
600
601        pre_commit_cache = CCommandCache()
602        pre_commit_cache.add('EXEC', ['clear counters','\r'] )
603        self.cmd_link.run_single_command( pre_commit_cache )
604
605    def clear_nbar_stats(self):
606        """ clear_nbar_stats(self) -> None
607
608        Clears the NBAR-PD classification stats
609        """
610        pre_commit_cache = CCommandCache()
611        pre_commit_cache.add('EXEC', ['clear ip nbar protocol-discovery','\r'] )
612        self.cmd_link.run_single_command( pre_commit_cache )
613
614    def clear_packet_drop_stats(self):
615        """ clear_packet_drop_stats(self) -> None
616
617        Clears packet-drop stats
618        """
619#       command = "show platform hardware qfp active statistics drop clear"
620        self.cmd_link.run_single_command('show platform hardware qfp active interface all statistics clear_drop')
621
622    ###########################################
623    # file transfer and image loading methods #
624    ###########################################
625    def get_running_image_details (self):
626        """ get_running_image_details() -> dict
627
628        Check for the currently running image file on the platform.
629        Returns a dictionary, where 'drive' key is the drive in which the image is installed,
630        and 'image' key is the actual image file used.
631        """
632        response = self.cmd_link.run_single_command('show version | include System image')
633        parsed_info = CShowParser.parse_show_image_version(response)
634        self.running_image = parsed_info
635        return parsed_info
636
637
638    def check_image_existence (self, img_name):
639        """ check_image_existence(self, img_name) -> boolean
640
641        Parameters
642        ----------
643        img_name : str
644            a string represents the image name.
645
646        Check if the image file defined in the platform_config already loaded into the platform.
647        """
648        search_drives = ['bootflash', 'harddisk', self.running_image['drive']]
649        for search_drive in search_drives:
650            command = "dir {drive}: | include {image}".format(drive = search_drive, image = img_name)
651            response = self.cmd_link.run_single_command(command, timeout = 10)
652            if CShowParser.parse_image_existence(response, img_name):
653                self.needed_image_path = '%s:%s' % (search_drive, img_name)
654                print 'Found image in platform:', self.needed_image_path
655                return True
656        return False
657
658    def config_tftp_server(self, device_cfg_obj, external_tftp_config = None, applyToPlatform = False):
659        """ configure_tftp_server(self, external_tftp_config, applyToPlatform) -> str
660
661        Parameters
662        ----------
663        external_tftp_config : dict (Not is use)
664            A path to external tftp config file other than using the one defined in the instance.
665        applyToPlatform : boolean
666            set to True in order to apply the config into the platform
667
668        Configures the tftp server on an interface of the platform.
669        """
670#       tmp_tftp_config = external_tftp_config if external_tftp_config is not None else self.tftp_server_config
671        self.tftp_cfg   = device_cfg_obj.get_tftp_info()
672        cache           = CCommandCache()
673
674        command = "ip tftp source-interface {intf}".format( intf = device_cfg_obj.get_mgmt_interface() )
675        cache.add('CONF', command )
676        self.cmd_link.run_single_command(cache)
677        self.config_history['tftp_server_config'] = True
678
679    def load_platform_image(self, img_filename, external_tftp_config = None):
680        """ load_platform_image(self, img_filename, external_tftp_config) -> None
681
682        Parameters
683        ----------
684        external_tftp_config : dict
685            A path to external tftp config file other than using the one defined in the instance.
686        img_filename : str
687            image name to be saved into the platforms drive.
688
689        This method loads the configured image into the platform's harddisk (unless it is already loaded),
690        and sets that image to be the boot_image of the platform.
691        """
692        if not self.check_image_existence(img_filename): # check if this image isn't already saved in platform
693            #tmp_tftp_config = external_tftp_config if external_tftp_config is not None else self.tftp_cfg
694
695            if self.config_history['tftp_server_config']:  # make sure a TFTP configuration has been loaded
696                cache = CCommandCache()
697                if self.running_image is None:
698                    self.get_running_image_details()
699
700                command = "copy tftp://{tftp_ip}/{img_path}/{image} harddisk:".format(
701                    tftp_ip  = self.tftp_cfg['ip_address'],
702                    img_path = self.tftp_cfg['images_path'],
703                    image    = img_filename)
704                cache.add('EXEC', [command, '\r', '\r'])
705
706                progress_thread = CProgressDisp.ProgressThread(notifyMessage = "Copying image via tftp, this may take a while...\n")
707                progress_thread.start()
708
709                response = self.cmd_link.run_single_command(cache, timeout = 900, read_until = ['\?', '\#'])
710                print "RESPONSE:"
711                print response
712                progress_thread.join()
713                copy_ok = CShowParser.parse_file_copy(response)
714
715                if not copy_ok:
716                    raise UserWarning('Image file loading failed. Please make sure the accessed image exists and has read privileges')
717            else:
718                raise UserWarning('TFTP configuration is not available. Please make sure a valid TFTP configuration has been provided')
719
720    def set_boot_image(self, boot_image):
721        """ set_boot_image(self, boot_image) -> None
722
723        Parameters
724        ----------
725        boot_image : str
726            An image file to be set as boot_image
727
728        Configures boot_image as the boot image of the platform into the running-config + config-register
729        """
730        cache = CCommandCache()
731        if self.needed_image_path is None:
732            if not self.check_image_existence(boot_image):
733                raise Exception("Trying to set boot image that's not found in router, please copy it first.")
734
735        boot_img_cmd = "boot system flash %s" % self.needed_image_path
736        config_register_cmd = "config-register 0x2021"
737        cache.add('CONF', ["no boot system", boot_img_cmd, config_register_cmd])
738        self.cmd_link.run_single_command( cache )
739        self.save_config_to_startup_config()
740
741    def is_image_matches(self, needed_image):
742        """ set_boot_image(self, needed_image) -> boolean
743
744        Parameters
745        ----------
746        needed_image : str
747            An image file to compare router running image
748
749        Compares image name to router running image, returns match result.
750
751        """
752        if self.running_image is None:
753            self.get_running_image_details()
754        needed_image = needed_image.lower()
755        current_image = self.running_image['image'].lower()
756        if needed_image.find(current_image) != -1:
757            return True
758        if current_image.find(needed_image) != -1:
759            return True
760        return False
761
762    # misc class related methods
763
764    def load_platform_data_from_file (self, device_cfg_obj):
765        self.if_mngr.load_config(device_cfg_obj)
766
767    def launch_connection (self, device_cfg_obj):
768        self.running_image = None # clear the image name "cache"
769        self.cmd_link.launch_platform_connectivity(device_cfg_obj)
770
771    def reload_connection (self, device_cfg_obj):
772        self.cmd_link.close_platform_connection()
773        self.launch_connection(device_cfg_obj)
774
775    def save_config_to_startup_config (self):
776        """ save_config_to_startup_config(self) -> None
777
778        Copies running-config into startup-config.
779        """
780        self.cmd_link.run_single_command('wr')
781
782    def reload_platform(self, device_cfg_obj):
783        """ reload_platform(self) -> None
784
785        Reloads the platform.
786        """
787        from subprocess import call
788        import os
789        i = 0
790        sleep_time = 30 # seconds
791
792        try:
793            cache = CCommandCache()
794
795            cache.add('EXEC', ['reload','n\r','\r'] )
796            self.cmd_link.run_single_command( cache )
797
798            progress_thread = CProgressDisp.ProgressThread(notifyMessage = "Reloading the platform, this may take a while...\n")
799            progress_thread.start()
800            time.sleep(60) # need delay for device to shut down before polling it
801            # poll the platform until ping response is received.
802            while True:
803                time.sleep(sleep_time)
804                try:
805                    x = call(["ping", "-c 1", device_cfg_obj.get_ip_address()], stdout = open(os.devnull, 'wb'))
806                except:
807                    x = 1
808                if x == 0:
809                    break
810                elif i > 20:
811                    raise TimeoutError('Platform failed to reload after reboot for over {minutes} minutes!'.format(minutes = round(1 + i * sleep_time / 60)))
812                else:
813                    i += 1
814
815            time.sleep(30)
816            self.reload_connection(device_cfg_obj)
817        finally:
818            progress_thread.join()
819
820    def get_if_manager(self):
821        return self.if_mngr
822
823    def dump_obj_config (self, object_name):
824        if object_name=='nat' and self.nat_config is not None:
825            self.nat_config.dump_config()
826        elif object_name=='static_route' and self.stat_route_config is not None:
827            self.stat_route_config.dump_config()
828        else:
829            raise UserWarning('No known configuration exists.')
830
831    def toggle_duplicated_intf(self, action = 'down'):
832
833        dup_ifs = self.if_mngr.get_duplicated_if()
834        self.__toggle_interfaces( dup_ifs, action = action )
835
836
837    def __toggle_interfaces (self, intf_list, action = 'up'):
838        cache = CCommandCache()
839        mode_str = 'no ' if action == 'up' else ''
840
841        for intf_obj in intf_list:
842            cache.add('IF', '{mode}shutdown'.format(mode = mode_str), intf_obj.get_name())
843
844        self.cmd_link.run_single_command( cache )
845
846
847class CStaticRouteConfig(object):
848
849    def __init__(self, static_route_dict):
850        self.clients_start  = static_route_dict['clients_start']
851        self.servers_start  = static_route_dict['servers_start']
852        self.net_increment  = misc_methods.gen_increment_dict(static_route_dict['dual_port_mask'])
853        self.client_mask    = static_route_dict['client_destination_mask']
854        self.server_mask    = static_route_dict['server_destination_mask']
855        self.client_net_start = self.extract_net_addr(self.clients_start, self.client_mask)
856        self.server_net_start = self.extract_net_addr(self.servers_start, self.server_mask)
857        self.static_route_dict = static_route_dict
858
859    def extract_net_addr (self, ip_addr, ip_mask):
860        addr_lst = ip_addr.split('.')
861        mask_lst = ip_mask.split('.')
862        mask_lst = map(lambda x,y: int(x) & int(y), addr_lst, mask_lst )
863        masked_str = map(lambda x: str(x), mask_lst )
864        return '.'.join(masked_str)
865
866    def dump_config (self):
867        import yaml
868        print yaml.dump( self.static_route_dict , default_flow_style=False)
869
870
871class CNatConfig(object):
872    def __init__(self, nat_dict):
873        self.clients_net_start  = nat_dict['clients_net_start']
874        self.client_acl_wildcard= nat_dict['client_acl_wildcard_mask']
875        self.net_increment      = misc_methods.gen_increment_dict(nat_dict['dual_port_mask'])
876        self.nat_pool_start     = nat_dict['pool_start']
877        self.nat_netmask        = nat_dict['pool_netmask']
878        self.nat_dict           = nat_dict
879
880    @staticmethod
881    def calc_pool_end (nat_pool_start, netmask):
882        pool_start_lst  = map(lambda x: int(x), nat_pool_start.split('.') )
883        pool_end_lst    = list( pool_start_lst )   # create new list object, don't point to the original one
884        mask_lst        = map(lambda x: int(x), netmask.split('.'))
885        curr_octet      = 3 # start with the LSB octet
886        inc_val         = 1
887
888        while True:
889            tmp_masked = inc_val & mask_lst[curr_octet]
890            if tmp_masked == 0:
891                if (inc_val << 1) > 255:
892                    inc_val = 1
893                    pool_end_lst[curr_octet] = 255
894                    curr_octet -= 1
895                else:
896                    inc_val <<= 1
897            else:
898                pool_end_lst[curr_octet] += (inc_val - 1)
899                break
900        return '.'.join(map(lambda x: str(x), pool_end_lst))
901
902    def dump_config (self):
903        import yaml
904        print yaml.dump( self.nat_dict , default_flow_style=False)
905
906
907if __name__ == "__main__":
908    pass
909