1#!/usr/local/bin/python3.8
2# This file is part of Ansible
3#
4# Ansible is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# Ansible is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
16#
17from __future__ import (absolute_import, division, print_function)
18__metaclass__ = type
19
20
21DOCUMENTATION = '''
22---
23module: ce_static_route_bfd
24version_added: '0.2.0'
25short_description: Manages static route configuration on HUAWEI CloudEngine switches.
26description:
27    - Manages the static routes on HUAWEI CloudEngine switches.
28author: xuxiaowei0512 (@CloudEngine-Ansible)
29notes:
30  - This module requires the netconf system service be enabled on the remote device being managed.
31  - Recommended connection is C(netconf).
32  - This module also works with C(local) connections for legacy playbooks.
33  - If no vrf is supplied, vrf is set to default.
34  - If I(state=absent), the route configuration will be removed, regardless of the non-required parameters.
35options:
36  prefix:
37    description:
38      - Destination ip address of static route.
39    required: true
40    type: str
41  mask:
42   description:
43     - Destination ip mask of static route.
44   type: str
45  aftype:
46    description:
47      - Destination ip address family type of static route.
48    required: true
49    type: str
50    choices: ['v4','v6']
51  next_hop:
52    description:
53      - Next hop address of static route.
54    type: str
55  nhp_interface:
56    description:
57      - Next hop interface full name of static route.
58    type: str
59  vrf:
60    description:
61      - VPN instance of destination ip address.
62    type: str
63  destvrf:
64    description:
65      - VPN instance of next hop ip address.
66    type: str
67  tag:
68    description:
69      - Route tag value (numeric).
70    type: int
71  description:
72    description:
73      - Name of the route. Used with the name parameter on the CLI.
74    type: str
75  pref:
76    description:
77      - Preference or administrative difference of route (range 1-255).
78    type: int
79  function_flag:
80    description:
81      - Used to distinguish between command line functions.
82    required: true
83    choices: ['globalBFD','singleBFD','dynamicBFD','staticBFD']
84    type: str
85  min_tx_interval:
86    description:
87      - Set the minimum BFD session sending interval (range 50-1000).
88    type: int
89  min_rx_interval:
90    description:
91      - Set the minimum BFD receive interval (range 50-1000).
92    type: int
93  detect_multiplier:
94    description:
95      - Configure the BFD multiplier (range 3-50).
96    type: int
97  bfd_session_name:
98    description:
99      - bfd name (range 1-15).
100    type: str
101  commands:
102    description:
103      - Incoming command line is used to send sys,undo ip route-static default-bfd,commit.
104    type: list
105  state:
106    description:
107      - Specify desired state of the resource.
108    required: false
109    choices: ['present','absent']
110    type: str
111    default: present
112'''
113
114EXAMPLES = '''
115  #ip route-static bfd interface-type interface-number nexthop-address [ local-address address ]
116  #[ min-rx-interval min-rx-interval | min-tx-interval min-tx-interval | detect-multiplier multiplier ]
117  - name: Config an ip route-static bfd 10GE1/0/1 3.3.3.3 min-rx-interval 50 min-tx-interval 50 detect-multiplier 5
118    community.network.ce_static_route_bfd:
119      function_flag: 'singleBFD'
120      nhp_interface: 10GE1/0/1
121      next_hop: 3.3.3.3
122      min_tx_interval: 50
123      min_rx_interval: 50
124      detect_multiplier: 5
125      aftype: v4
126      state: present
127
128  #undo ip route-static bfd [ interface-type interface-number | vpn-instance vpn-instance-name ] nexthop-address
129  - name: Undo ip route-static bfd 10GE1/0/1 3.3.3.4
130    community.network.ce_static_route_bfd:
131      function_flag: 'singleBFD'
132      nhp_interface: 10GE1/0/1
133      next_hop: 3.3.3.4
134      aftype: v4
135      state: absent
136
137  #ip route-static default-bfd { min-rx-interval {min-rx-interval} | min-tx-interval {min-tx-interval} | detect-multiplier {multiplier}}
138  - name: Config an ip route-static default-bfd min-rx-interval 50 min-tx-interval 50 detect-multiplier 6
139    community.network.ce_static_route_bfd:
140      function_flag: 'globalBFD'
141      min_tx_interval: 50
142      min_rx_interval: 50
143      detect_multiplier: 6
144      aftype: v4
145      state: present
146
147  - name: Undo ip route-static default-bfd
148    community.network.ce_static_route_bfd:
149      function_flag: 'globalBFD'
150      aftype: v4
151      state: absent
152      commands: 'sys,undo ip route-static default-bfd,commit'
153
154  - name: Config an ipv4 static route 2.2.2.0/24 2.2.2.1 preference 1 tag 2 description test for staticBFD
155    community.network.ce_static_route_bfd:
156      function_flag: 'staticBFD'
157      prefix: 2.2.2.2
158      mask: 24
159      next_hop: 2.2.2.1
160      tag: 2
161      description: test
162      pref: 1
163      aftype: v4
164      bfd_session_name: btoa
165      state: present
166'''
167RETURN = '''
168proposed:
169    description: k/v pairs of parameters passed into module
170    returned: always
171    type: dict
172    sample: {"function_flag": "staticBFD", "next_hop": "3.3.3.3", "pref": "100",
173            "prefix": "192.168.20.642", "mask": "24", "description": "testing",
174            "vrf": "_public_", "bfd_session_name": "btoa"}
175existing:
176    description: k/v pairs of existing switchport
177    returned: always
178    type: dict
179    sample: {"function_flag": "", "next_hop": "", "pref": "101",
180            "prefix": "192.168.20.0", "mask": "24", "description": "testing",
181            "tag" : "null", "bfd_session_name": "btoa"}
182end_state:
183    description: k/v pairs of switchport after module execution
184    returned: always
185    type: dict
186    sample: {"function_flag": "staticBFD", "next_hop": "3.3.3.3", "pref": "100",
187            "prefix": "192.168.20.0", "mask": "24", "description": "testing",
188            "tag" : "null", "bfd_session_name": "btoa"}
189updates:
190    description: command list sent to the device
191    returned: always
192    type: list
193    sample: ["ip route-static 192.168.20.0 255.255.255.0 3.3.3.3 preference 100 description testing"]
194changed:
195    description: check to see if a change was made on the device
196    returned: always
197    type: bool
198    sample: true
199'''
200
201from xml.etree import ElementTree
202from ansible.module_utils.basic import AnsibleModule
203from ansible.module_utils.six import string_types
204from ansible_collections.community.network.plugins.module_utils.network.cloudengine.ce import get_nc_config, set_nc_config
205
206CE_NC_GET_STATIC_ROUTE_BFD_SESSIONNAME = """
207<filter type="subtree">
208  <staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
209    <staticrtbase>
210      <srRoutes>
211        <srRoute>
212          <vrfName></vrfName>
213          <afType></afType>
214          <topologyName></topologyName>
215          <prefix></prefix>
216          <maskLength></maskLength>
217          <ifName></ifName>
218          <destVrfName></destVrfName>
219          <nexthop></nexthop>
220          <preference></preference>
221          <tag></tag>
222          <sessionName></sessionName>
223          <description></description>
224        </srRoute>
225      </srRoutes>
226    </staticrtbase>
227  </staticrt>
228</filter>
229"""
230# bfd enable
231CE_NC_GET_STATIC_ROUTE_BFD_ENABLE = """
232<filter type="subtree">
233      <staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
234        <staticrtbase>
235          <srRoutes>
236            <srRoute>
237              <vrfName></vrfName>
238              <afType></afType>
239              <topologyName></topologyName>
240              <prefix></prefix>
241              <maskLength></maskLength>
242              <ifName></ifName>
243              <destVrfName></destVrfName>
244              <nexthop></nexthop>
245              <preference></preference>
246              <tag></tag>
247              <bfdEnable></bfdEnable>
248              <description></description>
249            </srRoute>
250          </srRoutes>
251        </staticrtbase>
252      </staticrt>
253    </filter>
254"""
255
256CE_NC_GET_STATIC_ROUTE_BFD_ABSENT = """
257<filter type="subtree">
258  <staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
259    <staticrtbase>
260      <srBfdParas>
261        <srBfdPara>
262          <afType>%s</afType>
263          <ifName>%s</ifName>
264          <destVrfName>%s</destVrfName>
265          <nexthop>%s</nexthop>
266        </srBfdPara>
267      </srBfdParas>
268    </staticrtbase>
269  </staticrt>
270</filter>
271"""
272
273CE_NC_GET_STATIC_ROUTE_BFD = """
274<filter type="subtree">
275  <staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
276    <staticrtbase>
277      <srBfdParas>
278        <srBfdPara>
279          <afType>%s</afType>
280          <ifName>%s</ifName>
281          <destVrfName>%s</destVrfName>
282          <nexthop>%s</nexthop>
283          <localAddress></localAddress>
284          <minTxInterval></minTxInterval>
285          <minRxInterval></minRxInterval>
286          <multiplier></multiplier>
287        </srBfdPara>
288      </srBfdParas>
289    </staticrtbase>
290  </staticrt>
291</filter>
292"""
293CE_NC_GET_STATIC_ROUTE_IPV4_GLOBAL_BFD = """
294<filter type="subtree">
295  <staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
296    <staticrtbase>
297      <srIPv4StaticSite>
298        <minTxInterval></minTxInterval>
299        <minRxInterval></minRxInterval>
300        <multiplier></multiplier>
301      </srIPv4StaticSite>
302    </staticrtbase>
303  </staticrt>
304</filter>
305"""
306CE_NC_GET_STATIC_ROUTE_ABSENT = """
307<filter type="subtree">
308      <staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
309        <staticrtbase>
310          <srRoutes>
311            <srRoute>
312              <vrfName></vrfName>
313              <afType></afType>
314              <topologyName></topologyName>
315              <prefix></prefix>
316              <maskLength></maskLength>
317              <ifName></ifName>
318              <destVrfName></destVrfName>
319              <nexthop></nexthop>
320            </srRoute>
321          </srRoutes>
322        </staticrtbase>
323      </staticrt>
324    </filter>
325"""
326
327CE_NC_DELETE_STATIC_ROUTE_SINGLEBFD = """
328<staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
329        <staticrtbase>
330          <srBfdParas>
331            <srBfdPara operation="delete">
332              <afType>%s</afType>
333              <ifName>%s</ifName>
334              <destVrfName>%s</destVrfName>
335              <nexthop>%s</nexthop>
336            </srBfdPara>
337          </srBfdParas>
338        </staticrtbase>
339      </staticrt>
340"""
341CE_NC_SET_STATIC_ROUTE_SINGLEBFD = """
342<staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
343        <staticrtbase>
344          <srBfdParas>
345            <srBfdPara operation="merge">
346              <afType>%s</afType>
347              <ifName>%s</ifName>
348              <destVrfName>%s</destVrfName>
349              <nexthop>%s</nexthop>%s%s%s%s
350            </srBfdPara>
351          </srBfdParas>
352        </staticrtbase>
353      </staticrt>
354
355"""
356CE_NC_SET_STATIC_ROUTE_SINGLEBFD_LOCALADRESS = """
357<localAddress>%s</localAddress>
358"""
359CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINTX = """
360<minTxInterval>%s</minTxInterval>
361"""
362CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINRX = """
363<minRxInterval>%s</minRxInterval>
364"""
365CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MUL = """
366<multiplier>%s</multiplier>
367"""
368CE_NC_SET_IPV4_STATIC_ROUTE_GLOBALBFD = """
369<staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
370    <staticrtbase>
371      <srIPv4StaticSite operation="merge">
372      %s%s%s
373      </srIPv4StaticSite>
374    </staticrtbase>
375</staticrt>
376"""
377
378CE_NC_SET_STATIC_ROUTE = """
379<staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
380        <staticrtbase>
381          <srRoutes>
382            <srRoute operation="merge">
383              <vrfName>%s</vrfName>
384              <afType>%s</afType>
385              <topologyName>base</topologyName>
386              <prefix>%s</prefix>
387              <maskLength>%s</maskLength>
388              <ifName>%s</ifName>
389              <destVrfName>%s</destVrfName>
390              <nexthop>%s</nexthop>%s%s%s%s
391            </srRoute>
392          </srRoutes>
393        </staticrtbase>
394      </staticrt>
395"""
396CE_NC_SET_DESCRIPTION = """
397<description>%s</description>
398"""
399
400CE_NC_SET_PREFERENCE = """
401<preference>%s</preference>
402"""
403
404CE_NC_SET_TAG = """
405<tag>%s</tag>
406"""
407CE_NC_SET_BFDSESSIONNAME = """
408<sessionName>%s</sessionName>
409"""
410CE_NC_SET_BFDENABLE = """
411<bfdEnable>true</bfdEnable>
412"""
413CE_NC_DELETE_STATIC_ROUTE = """
414<staticrt xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
415        <staticrtbase>
416          <srRoutes>
417            <srRoute operation="delete">
418              <vrfName>%s</vrfName>
419              <afType>%s</afType>
420              <topologyName>base</topologyName>
421              <prefix>%s</prefix>
422              <maskLength>%s</maskLength>
423              <ifName>%s</ifName>
424              <destVrfName>%s</destVrfName>
425              <nexthop>%s</nexthop>
426            </srRoute>
427          </srRoutes>
428        </staticrtbase>
429      </staticrt>
430"""
431
432
433def build_config_xml(xmlstr):
434    """build config xml"""
435
436    return '<config> ' + xmlstr + ' </config>'
437
438
439def is_valid_v4addr(addr):
440    """check if ipv4 addr is valid"""
441    if addr.find('.') != -1:
442        addr_list = addr.split('.')
443        if len(addr_list) != 4:
444            return False
445        for each_num in addr_list:
446
447            if not each_num.isdigit():
448                return False
449            if int(each_num) > 255:
450                return False
451        return True
452    return False
453
454
455def is_valid_v6addr(addr):
456    """check if ipv6 addr is valid"""
457    if addr.find(':') != -1:
458        addr_list = addr.split(':')
459        if len(addr_list) > 6:
460            return False
461        if addr_list[1] == "":
462            return False
463        return True
464    return False
465
466
467def is_valid_tag(tag):
468    """check if the tag is valid"""
469
470    if int(tag) < 1 or int(tag) > 4294967295:
471        return False
472    return True
473
474
475def is_valid_bdf_interval(interval):
476    """check if the min_tx_interva,min-rx-interval is valid"""
477
478    if interval < 50 or interval > 1000:
479        return False
480    return True
481
482
483def is_valid_bdf_multiplier(multiplier):
484    """check if the detect_multiplier is valid"""
485
486    if multiplier < 3 or multiplier > 50:
487        return False
488    return True
489
490
491def is_valid_bdf_session_name(session_name):
492    """check if the bfd_session_name is valid"""
493    if session_name.find(' ') != -1:
494        return False
495    if len(session_name) < 1 or len(session_name) > 15:
496        return False
497    return True
498
499
500def is_valid_preference(pref):
501    """check if the preference is valid"""
502
503    if int(pref) > 0 and int(pref) < 256:
504        return True
505    return False
506
507
508def is_valid_description(description):
509    """check if the description is valid"""
510    if description.find('?') != -1:
511        return False
512    if len(description) < 1 or len(description) > 255:
513        return False
514    return True
515
516
517def compare_command(commands):
518    """check if the commands is valid"""
519    if len(commands) < 3:
520        return True
521    if commands[0] != 'sys' or commands[1] != 'undo ip route-static default-bfd' \
522            or commands[2] != 'commit':
523        return True
524
525
526def get_to_lines(stdout):
527    """data conversion"""
528    lines = list()
529    for item in stdout:
530        if isinstance(item, string_types):
531            item = str(item).split('\n')
532        lines.append(item)
533    return lines
534
535
536def get_change_state(oldvalue, newvalue, change):
537    """get change state"""
538    if newvalue is not None:
539        if oldvalue != str(newvalue):
540            change = True
541    else:
542        if oldvalue != newvalue:
543            change = True
544    return change
545
546
547def get_xml(xml, value):
548    """operate xml"""
549    if value is None:
550        value = ''
551    tempxml = xml % value
552    return tempxml
553
554
555class StaticRouteBFD(object):
556    """static route module"""
557
558    def __init__(self, argument_spec):
559        self.spec = argument_spec
560        self.module = None
561        self._initmodule_()
562
563        # static route info
564        self.function_flag = self.module.params['function_flag']
565        self.aftype = self.module.params['aftype']
566        self.state = self.module.params['state']
567        if self.aftype == "v4":
568            self.version = "ipv4unicast"
569        else:
570            self.version = "ipv6unicast"
571        if self.function_flag != 'globalBFD':
572            self.nhp_interface = self.module.params['nhp_interface']
573            if self.nhp_interface is None:
574                self.nhp_interface = "Invalid0"
575
576            self.destvrf = self.module.params['destvrf']
577            if self.destvrf is None:
578                self.destvrf = "_public_"
579
580            self.next_hop = self.module.params['next_hop']
581            self.prefix = self.module.params['prefix']
582
583        if self.function_flag != 'globalBFD' and self.function_flag != 'singleBFD':
584            self.mask = self.module.params['mask']
585            self.tag = self.module.params['tag']
586            self.description = self.module.params['description']
587            self.pref = self.module.params['pref']
588            if self.pref is None:
589                self.pref = 60
590            # vpn instance info
591            self.vrf = self.module.params['vrf']
592            if self.vrf is None:
593                self.vrf = "_public_"
594            # bfd session name
595            self.bfd_session_name = self.module.params['bfd_session_name']
596
597        if self.function_flag == 'globalBFD' or self.function_flag == 'singleBFD':
598            self.min_tx_interval = self.module.params['min_tx_interval']
599            self.min_rx_interval = self.module.params['min_rx_interval']
600            self.detect_multiplier = self.module.params['detect_multiplier']
601        if self.function_flag == 'globalBFD' and self.state == 'absent':
602            self.commands = self.module.params['commands']
603        # state
604        self.changed = False
605        self.updates_cmd = list()
606        self.results = dict()
607        self.proposed = dict()
608        self.existing = dict()
609        self.end_state = dict()
610
611        self.static_routes_info = dict()
612
613    def _initmodule_(self):
614        """init module"""
615
616        self.module = AnsibleModule(
617            argument_spec=self.spec, supports_check_mode=False)
618
619    def _checkresponse_(self, xml_str, xml_name):
620        """check if response message is already succeed."""
621
622        if "<ok/>" not in xml_str:
623            self.module.fail_json(msg='Error: %s failed.' % xml_name)
624
625    def _convertlentomask_(self, masklen):
626        """convert mask length to ip address mask, i.e. 24 to 255.255.255.0"""
627
628        mask_int = ["0"] * 4
629        length = int(masklen)
630
631        if length > 32:
632            self.module.fail_json(msg='IPv4 ipaddress mask length is invalid')
633        if length < 8:
634            mask_int[0] = str(int((0xFF << (8 - length % 8)) & 0xFF))
635        if length >= 8:
636            mask_int[0] = '255'
637            mask_int[1] = str(int((0xFF << (16 - (length % 16))) & 0xFF))
638        if length >= 16:
639            mask_int[1] = '255'
640            mask_int[2] = str(int((0xFF << (24 - (length % 24))) & 0xFF))
641        if length >= 24:
642            mask_int[2] = '255'
643            mask_int[3] = str(int((0xFF << (32 - (length % 32))) & 0xFF))
644        if length == 32:
645            mask_int[3] = '255'
646
647        return '.'.join(mask_int)
648
649    def _convertipprefix_(self):
650        """convert prefix to real value i.e. 2.2.2.2/24 to 2.2.2.0/24"""
651        if self.function_flag == 'singleBFD':
652            if self.aftype == "v4":
653                if self.prefix.find('.') == -1:
654                    return False
655                addr_list = self.prefix.split('.')
656                length = len(addr_list)
657                if length > 4:
658                    return False
659                for each_num in addr_list:
660                    if not each_num.isdigit():
661                        return False
662                    if int(each_num) > 255:
663                        return False
664                return True
665            else:
666                if self.prefix.find(':') == -1:
667                    return False
668        else:
669            if self.aftype == "v4":
670                if self.prefix.find('.') == -1:
671                    return False
672                if self.mask == '32':
673                    self.prefix = self.prefix
674                    return True
675                if self.mask == '0':
676                    self.prefix = '0.0.0.0'
677                    return True
678                addr_list = self.prefix.split('.')
679                length = len(addr_list)
680                if length > 4:
681                    return False
682                for each_num in addr_list:
683                    if not each_num.isdigit():
684                        return False
685                    if int(each_num) > 255:
686                        return False
687                byte_len = 8
688                ip_len = int(self.mask) // byte_len
689                ip_bit = int(self.mask) % byte_len
690            else:
691                if self.prefix.find(':') == -1:
692                    return False
693                if self.mask == '128':
694                    self.prefix = self.prefix
695                    return True
696                if self.mask == '0':
697                    self.prefix = '::'
698                    return True
699                addr_list = self.prefix.split(':')
700                length = len(addr_list)
701                if length > 6:
702                    return False
703                byte_len = 16
704                ip_len = int(self.mask) // byte_len
705                ip_bit = int(self.mask) % byte_len
706
707            if self.aftype == "v4":
708                for i in range(ip_len + 1, length):
709                    addr_list[i] = 0
710            else:
711                for i in range(length - ip_len, length):
712                    addr_list[i] = 0
713            for j in range(0, byte_len - ip_bit):
714                if self.aftype == "v4":
715                    addr_list[ip_len] = int(addr_list[ip_len]) & (0 << j)
716                else:
717                    if addr_list[length - ip_len - 1] == "":
718                        continue
719                    addr_list[length - ip_len -
720                              1] = '0x%s' % addr_list[length - ip_len - 1]
721                    addr_list[length - ip_len -
722                              1] = int(addr_list[length - ip_len - 1], 16) & (0 << j)
723
724            if self.aftype == "v4":
725                self.prefix = '%s.%s.%s.%s' % (addr_list[0], addr_list[1], addr_list[2], addr_list[3])
726                return True
727            if self.aftype == "v6":
728                ipv6_addr_str = ""
729                for num in range(0, length - ip_len):
730                    ipv6_addr_str += '%s:' % addr_list[num]
731                self.prefix = ipv6_addr_str
732
733                return True
734
735    def set_update_cmd_globalbfd(self):
736        """set globalBFD update command"""
737        if not self.changed:
738            return
739        if self.state == "present":
740            self.updates_cmd.append('ip route-static default-bfd')
741            if self.min_tx_interval:
742                self.updates_cmd.append(' min-rx-interval %s' % (self.min_tx_interval))
743            if self.min_rx_interval:
744                self.updates_cmd.append(' min-tx-interval %s' % (self.min_rx_interval))
745            if self.detect_multiplier:
746                self.updates_cmd.append(' detect-multiplier %s' % (self.detect_multiplier))
747        else:
748            self.updates_cmd.append('undo ip route-static default-bfd')
749
750    def set_update_cmd_singlebfd(self):
751        """set singleBFD update command"""
752        if not self.changed:
753            return
754        if self.next_hop is None:
755            next_hop = ''
756        else:
757            next_hop = self.next_hop
758
759        if self.destvrf == "_public_":
760            destvrf = ''
761        else:
762            destvrf = self.destvrf
763
764        if self.nhp_interface == "Invalid0":
765            nhp_interface = ''
766        else:
767            nhp_interface = self.nhp_interface
768        if self.prefix == "0.0.0.0":
769            prefix = ''
770        else:
771            prefix = self.prefix
772        if self.state == "present":
773            if nhp_interface:
774                self.updates_cmd.append('ip route-static bfd %s %s' % (nhp_interface, next_hop))
775            elif destvrf:
776                self.updates_cmd.append('ip route-static bfd vpn-instance %s %s' % (destvrf, next_hop))
777            else:
778                self.updates_cmd.append('ip route-static bfd %s' % (next_hop))
779            if prefix:
780                self.updates_cmd.append(' local-address %s' % (self.prefix))
781            if self.min_tx_interval:
782                self.updates_cmd.append(' min-rx-interval %s' % (self.min_tx_interval))
783            if self.min_rx_interval:
784                self.updates_cmd.append(' min-tx-interval %s' % (self.min_rx_interval))
785            if self.detect_multiplier:
786                self.updates_cmd.append(' detect-multiplier %s' % (self.detect_multiplier))
787        else:
788            if nhp_interface:
789                self.updates_cmd.append('undo ip route-static bfd %s %s' % (nhp_interface, next_hop))
790            elif destvrf:
791                self.updates_cmd.append('undo ip route-static bfd vpn-instance %s %s' % (destvrf, next_hop))
792            else:
793                self.updates_cmd.append('undo ip route-static bfd %s' % (next_hop))
794
795    def set_update_cmd(self):
796        """set update command"""
797        if not self.changed:
798            return
799
800        if self.aftype == "v4":
801            maskstr = self._convertlentomask_(self.mask)
802        else:
803            maskstr = self.mask
804        static_bfd_flag = True
805        if self.bfd_session_name:
806            static_bfd_flag = False
807        if self.next_hop is None:
808            next_hop = ''
809        else:
810            next_hop = self.next_hop
811        if self.vrf == "_public_":
812            vrf = ''
813        else:
814            vrf = self.vrf
815        if self.destvrf == "_public_":
816            destvrf = ''
817        else:
818            destvrf = self.destvrf
819        if self.nhp_interface == "Invalid0":
820            nhp_interface = ''
821        else:
822            nhp_interface = self.nhp_interface
823        if self.state == "present":
824            if self.vrf != "_public_":
825                if self.destvrf != "_public_":
826                    self.updates_cmd.append('ip route-static vpn-instance %s %s %s vpn-instance %s %s'
827                                            % (vrf, self.prefix, maskstr, destvrf, next_hop))
828                else:
829                    self.updates_cmd.append('ip route-static vpn-instance %s %s %s %s %s'
830                                            % (vrf, self.prefix, maskstr, nhp_interface, next_hop))
831            elif self.destvrf != "_public_":
832                self.updates_cmd.append('ip route-static %s %s vpn-instance %s %s'
833                                        % (self.prefix, maskstr, self.destvrf, next_hop))
834            else:
835                self.updates_cmd.append('ip route-static %s %s %s %s'
836                                        % (self.prefix, maskstr, nhp_interface, next_hop))
837            if self.pref != 60:
838                self.updates_cmd.append(' preference %s' % (self.pref))
839            if self.tag:
840                self.updates_cmd.append(' tag %s' % (self.tag))
841            if not static_bfd_flag:
842                self.updates_cmd.append(' track bfd-session %s' % (self.bfd_session_name))
843            else:
844                self.updates_cmd.append(' bfd enable')
845            if self.description:
846                self.updates_cmd.append(' description %s' % (self.description))
847
848        if self.state == "absent":
849            if self.vrf != "_public_":
850                if self.destvrf != "_public_":
851                    self.updates_cmd.append('undo ip route-static vpn-instance %s %s %s vpn-instance %s %s'
852                                            % (vrf, self.prefix, maskstr, destvrf, next_hop))
853                else:
854                    self.updates_cmd.append('undo ip route-static vpn-instance %s %s %s %s %s'
855                                            % (vrf, self.prefix, maskstr, nhp_interface, next_hop))
856            elif self.destvrf != "_public_":
857                self.updates_cmd.append('undo ip route-static %s %s vpn-instance %s %s'
858                                        % (self.prefix, maskstr, self.destvrf, self.next_hop))
859            else:
860                self.updates_cmd.append('undo ip route-static %s %s %s %s'
861                                        % (self.prefix, maskstr, nhp_interface, next_hop))
862
863    def operate_static_route_globalbfd(self):
864        """set globalbfd update command"""
865        min_tx_interval = self.min_tx_interval
866        min_rx_interval = self.min_rx_interval
867        multiplier = self.detect_multiplier
868        min_tx_interval_xml = """\n"""
869        min_rx_interval_xml = """\n"""
870        multiplier_xml = """\n"""
871        if self.state == "present":
872            if min_tx_interval is not None:
873                min_tx_interval_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINTX % min_tx_interval
874            if min_rx_interval is not None:
875                min_rx_interval_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINRX % min_rx_interval
876            if multiplier is not None:
877                multiplier_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MUL % multiplier
878
879            configxmlstr = CE_NC_SET_IPV4_STATIC_ROUTE_GLOBALBFD % (
880                min_tx_interval_xml, min_rx_interval_xml, multiplier_xml)
881            conf_str = build_config_xml(configxmlstr)
882            recv_xml = set_nc_config(self.module, conf_str)
883            self._checkresponse_(recv_xml, "OPERATE_STATIC_ROUTE_globalBFD")
884
885        if self.state == "absent" and self.commands:
886            min_tx_interval_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINTX % 1000
887            min_rx_interval_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINRX % 1000
888            multiplier_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MUL % 3
889
890            configxmlstr = CE_NC_SET_IPV4_STATIC_ROUTE_GLOBALBFD % (
891                min_tx_interval_xml, min_rx_interval_xml, multiplier_xml)
892            conf_str = build_config_xml(configxmlstr)
893            recv_xml = set_nc_config(self.module, conf_str)
894            self._checkresponse_(recv_xml, "OPERATE_STATIC_ROUTE_globalBFD")
895
896    def operate_static_route_singlebfd(self, version, prefix, nhp_interface, next_hop, destvrf, state):
897        """operate ipv4 static route singleBFD"""
898        min_tx_interval = self.min_tx_interval
899        min_rx_interval = self.min_rx_interval
900        multiplier = self.detect_multiplier
901        min_tx_interval_xml = """\n"""
902        min_rx_interval_xml = """\n"""
903        multiplier_xml = """\n"""
904        local_address_xml = """\n"""
905        if next_hop is None:
906            next_hop = '0.0.0.0'
907
908        if destvrf is None:
909            dest_vpn_instance = "_public_"
910        else:
911            dest_vpn_instance = destvrf
912
913        if nhp_interface is None:
914            nhp_interface = "Invalid0"
915
916        if min_tx_interval is not None:
917            min_tx_interval_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINTX % min_tx_interval
918        if min_rx_interval is not None:
919            min_rx_interval_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MINRX % min_rx_interval
920        if multiplier is not None:
921            multiplier_xml = CE_NC_SET_IPV4_STATIC_ROUTE_BFDCOMMON_MUL % multiplier
922
923        if prefix is not None:
924            local_address_xml = CE_NC_SET_STATIC_ROUTE_SINGLEBFD_LOCALADRESS % prefix
925
926        if state == "present":
927            configxmlstr = CE_NC_SET_STATIC_ROUTE_SINGLEBFD % (
928                version, nhp_interface, dest_vpn_instance,
929                next_hop, local_address_xml, min_tx_interval_xml,
930                min_rx_interval_xml, multiplier_xml)
931
932        else:
933            configxmlstr = CE_NC_DELETE_STATIC_ROUTE_SINGLEBFD % (
934                version, nhp_interface, dest_vpn_instance, next_hop)
935
936        conf_str = build_config_xml(configxmlstr)
937
938        recv_xml = set_nc_config(self.module, conf_str)
939        self._checkresponse_(recv_xml, "OPERATE_STATIC_ROUTE_singleBFD")
940
941    def operate_static_route(self, version, prefix, mask, nhp_interface, next_hop, vrf, destvrf, state):
942        """operate ipv4 static route"""
943        description_xml = """\n"""
944        preference_xml = """\n"""
945        tag_xml = """\n"""
946        bfd_xml = """\n"""
947        if next_hop is None:
948            next_hop = '0.0.0.0'
949        if nhp_interface is None:
950            nhp_interface = "Invalid0"
951
952        if vrf is None:
953            vpn_instance = "_public_"
954        else:
955            vpn_instance = vrf
956
957        if destvrf is None:
958            dest_vpn_instance = "_public_"
959        else:
960            dest_vpn_instance = destvrf
961
962        description_xml = get_xml(CE_NC_SET_DESCRIPTION, self.description)
963
964        preference_xml = get_xml(CE_NC_SET_PREFERENCE, self.pref)
965
966        tag_xml = get_xml(CE_NC_SET_TAG, self.tag)
967
968        if self.function_flag == 'staticBFD':
969            if self.bfd_session_name:
970                bfd_xml = CE_NC_SET_BFDSESSIONNAME % self.bfd_session_name
971        else:
972            bfd_xml = CE_NC_SET_BFDENABLE
973        if state == "present":
974            configxmlstr = CE_NC_SET_STATIC_ROUTE % (
975                vpn_instance, version, prefix, mask, nhp_interface,
976                dest_vpn_instance, next_hop, description_xml, preference_xml, tag_xml, bfd_xml)
977
978        else:
979            configxmlstr = CE_NC_DELETE_STATIC_ROUTE % (
980                vpn_instance, version, prefix, mask, nhp_interface, dest_vpn_instance, next_hop)
981
982        conf_str = build_config_xml(configxmlstr)
983        recv_xml = set_nc_config(self.module, conf_str)
984        self._checkresponse_(recv_xml, "OPERATE_STATIC_ROUTE")
985
986    def get_change_state_global_bfd(self):
987        """get ipv4 global bfd change state"""
988
989        self.get_global_bfd(self.state)
990        change = False
991        if self.state == "present":
992            if self.static_routes_info["sroute_global_bfd"]:
993                for static_route in self.static_routes_info["sroute_global_bfd"]:
994                    if static_route is not None:
995                        if self.min_tx_interval is not None:
996                            if int(static_route["minTxInterval"]) != self.min_tx_interval:
997                                change = True
998                        if self.min_rx_interval is not None:
999                            if int(static_route["minRxInterval"]) != self.min_rx_interval:
1000                                change = True
1001                        if self.detect_multiplier is not None:
1002                            if int(static_route["multiplier"]) != self.detect_multiplier:
1003                                change = True
1004                        return change
1005                    else:
1006                        continue
1007            else:
1008                change = True
1009        else:
1010            if self.commands:
1011                if self.static_routes_info["sroute_global_bfd"]:
1012                    for static_route in self.static_routes_info["sroute_global_bfd"]:
1013                        if static_route is not None:
1014                            if int(static_route["minTxInterval"]) != 1000 or \
1015                               int(static_route["minRxInterval"]) != 1000 or \
1016                               int(static_route["multiplier"]) != 3:
1017                                change = True
1018            return change
1019
1020    def get_global_bfd(self, state):
1021        """get ipv4 global bfd"""
1022
1023        self.static_routes_info["sroute_global_bfd"] = list()
1024
1025        getglobalbfdxmlstr = None
1026        if self.aftype == 'v4':
1027            getglobalbfdxmlstr = CE_NC_GET_STATIC_ROUTE_IPV4_GLOBAL_BFD
1028
1029        if getglobalbfdxmlstr is not None:
1030            xml_global_bfd_str = get_nc_config(self.module, getglobalbfdxmlstr)
1031
1032            if 'data/' in xml_global_bfd_str:
1033                return
1034
1035            xml_global_bfd_str = xml_global_bfd_str.replace('\r', '').replace('\n', ''). \
1036                replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', ""). \
1037                replace('xmlns="http://www.huawei.com/netconf/vrp"', "")
1038            root = ElementTree.fromstring(xml_global_bfd_str)
1039            static_routes_global_bfd = root.findall(
1040                "staticrt/staticrtbase/srIPv4StaticSite")
1041
1042            if static_routes_global_bfd:
1043                for static_route in static_routes_global_bfd:
1044                    static_info = dict()
1045                    for static_ele in static_route:
1046                        if static_ele.tag == "minTxInterval":
1047                            if static_ele.text is not None:
1048                                static_info["minTxInterval"] = static_ele.text
1049                        if static_ele.tag == "minRxInterval":
1050                            if static_ele.text is not None:
1051                                static_info["minRxInterval"] = static_ele.text
1052                        if static_ele.tag == "multiplier":
1053                            if static_ele.text is not None:
1054                                static_info["multiplier"] = static_ele.text
1055
1056                    self.static_routes_info["sroute_global_bfd"].append(static_info)
1057
1058    def get_change_state_single_bfd(self):
1059        """get ipv4 single bfd change state"""
1060
1061        self.get_single_bfd(self.state)
1062        change = False
1063        version = self.version
1064        if self.state == 'present':
1065            if self.static_routes_info["sroute_single_bfd"]:
1066                for static_route in self.static_routes_info["sroute_single_bfd"]:
1067                    if static_route is not None and static_route['afType'] == version:
1068                        if self.nhp_interface:
1069                            if static_route["ifName"].lower() != self.nhp_interface.lower():
1070                                change = True
1071                        if self.destvrf:
1072                            if static_route["destVrfName"].lower() != self.destvrf.lower():
1073                                change = True
1074                        if self.next_hop:
1075                            if static_route["nexthop"].lower() != self.next_hop.lower():
1076                                change = True
1077                        if self.prefix:
1078                            if static_route["localAddress"].lower() != self.prefix.lower():
1079                                change = True
1080                        if self.min_tx_interval:
1081                            if int(static_route["minTxInterval"]) != self.min_tx_interval:
1082                                change = True
1083                        if self.min_rx_interval:
1084                            if int(static_route["minRxInterval"]) != self.min_rx_interval:
1085                                change = True
1086                        if self.detect_multiplier:
1087                            if int(static_route["multiplier"]) != self.detect_multiplier:
1088                                change = True
1089                        return change
1090
1091                    else:
1092                        continue
1093            else:
1094                change = True
1095        else:
1096            for static_route in self.static_routes_info["sroute_single_bfd"]:
1097                # undo ip route-static bfd [ interface-type interface-number |
1098                # vpn-instance vpn-instance-name ] nexthop-address
1099
1100                if static_route["ifName"] and self.nhp_interface:
1101                    if static_route["ifName"].lower() == self.nhp_interface.lower() \
1102                            and static_route["nexthop"].lower() == self.next_hop.lower() \
1103                            and static_route["afType"] == version:
1104                        change = True
1105                        return change
1106
1107                if static_route["destVrfName"] and self.destvrf:
1108                    if static_route["destVrfName"].lower() == self.destvrf.lower() \
1109                            and static_route["nexthop"].lower() == self.next_hop.lower() \
1110                            and static_route["afType"] == version:
1111                        change = True
1112                        return change
1113
1114                if static_route["nexthop"] and self.next_hop:
1115                    if static_route["nexthop"].lower() == self.next_hop.lower() \
1116                            and static_route["afType"] == version:
1117                        change = True
1118                        return change
1119                else:
1120                    continue
1121            change = False
1122        return change
1123
1124    def get_single_bfd(self, state):
1125        """get ipv4 sigle bfd"""
1126        self.static_routes_info["sroute_single_bfd"] = list()
1127        if self.aftype == "v4":
1128            version = "ipv4unicast"
1129        else:
1130            version = "ipv6unicast"
1131        if state == 'absent':
1132            getbfdxmlstr = CE_NC_GET_STATIC_ROUTE_BFD_ABSENT % (
1133                version, self.nhp_interface, self.destvrf, self.next_hop)
1134        else:
1135            getbfdxmlstr = CE_NC_GET_STATIC_ROUTE_BFD % (
1136                version, self.nhp_interface, self.destvrf, self.next_hop)
1137        xml_bfd_str = get_nc_config(self.module, getbfdxmlstr)
1138
1139        if 'data/' in xml_bfd_str:
1140            return
1141        xml_bfd_str = xml_bfd_str.replace('\r', '').replace('\n', ''). \
1142            replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', ""). \
1143            replace('xmlns="http://www.huawei.com/netconf/vrp"', "")
1144        root = ElementTree.fromstring(xml_bfd_str)
1145        static_routes_bfd = root.findall(
1146            "staticrt/staticrtbase/srBfdParas/srBfdPara")
1147        if static_routes_bfd:
1148            for static_route in static_routes_bfd:
1149                static_info = dict()
1150                for static_ele in static_route:
1151                    if static_ele.tag in ["afType", "destVrfName", "nexthop", "ifName"]:
1152                        static_info[static_ele.tag] = static_ele.text
1153                    if static_ele.tag == "localAddress":
1154                        if static_ele.text is not None:
1155                            static_info["localAddress"] = static_ele.text
1156                        else:
1157                            static_info["localAddress"] = "None"
1158                    if static_ele.tag == "minTxInterval":
1159                        if static_ele.text is not None:
1160                            static_info["minTxInterval"] = static_ele.text
1161                    if static_ele.tag == "minRxInterval":
1162                        if static_ele.text is not None:
1163                            static_info["minRxInterval"] = static_ele.text
1164                    if static_ele.tag == "multiplier":
1165                        if static_ele.text is not None:
1166                            static_info["multiplier"] = static_ele.text
1167                self.static_routes_info["sroute_single_bfd"].append(static_info)
1168
1169    def get_static_route(self, state):
1170        """get ipv4 static route about BFD"""
1171        self.static_routes_info["sroute"] = list()
1172        # Increase the parameter used to distinguish whether the incoming bfdSessionName
1173        static_bfd_flag = True
1174        if self.bfd_session_name:
1175            static_bfd_flag = False
1176
1177        if state == 'absent':
1178            getxmlstr = CE_NC_GET_STATIC_ROUTE_ABSENT
1179        else:
1180            # self.static_bfd_flag is true
1181            if static_bfd_flag:
1182                getxmlstr = CE_NC_GET_STATIC_ROUTE_BFD_ENABLE
1183
1184            else:
1185                getxmlstr = CE_NC_GET_STATIC_ROUTE_BFD_SESSIONNAME
1186        xml_str = get_nc_config(self.module, getxmlstr)
1187        if 'data/' in xml_str:
1188            return
1189        xml_str = xml_str.replace('\r', '').replace('\n', ''). \
1190            replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', ""). \
1191            replace('xmlns="http://www.huawei.com/netconf/vrp"', "")
1192        root = ElementTree.fromstring(xml_str)
1193        static_routes = root.findall(
1194            "staticrt/staticrtbase/srRoutes/srRoute")
1195
1196        if static_routes:
1197            for static_route in static_routes:
1198                static_info = dict()
1199                for static_ele in static_route:
1200                    if static_ele.tag in ["vrfName", "afType", "topologyName",
1201                                          "prefix", "maskLength", "destVrfName",
1202                                          "nexthop", "ifName", "preference", "description"]:
1203                        static_info[static_ele.tag] = static_ele.text
1204                    if static_ele.tag == "tag":
1205                        if static_ele.text is not None:
1206                            static_info["tag"] = static_ele.text
1207                        else:
1208                            static_info["tag"] = "None"
1209                    if static_bfd_flag:
1210                        if static_ele.tag == "bfdEnable":
1211                            if static_ele.text is not None:
1212                                static_info["bfdEnable"] = static_ele.text
1213                            else:
1214                                static_info["bfdEnable"] = "None"
1215                    else:
1216                        if static_ele.tag == "sessionName":
1217                            if static_ele.text is not None:
1218                                static_info["sessionName"] = static_ele.text
1219                            else:
1220                                static_info["sessionName"] = "None"
1221                self.static_routes_info["sroute"].append(static_info)
1222
1223    def _checkparams_(self):
1224        """check all input params"""
1225        if self.function_flag == 'singleBFD':
1226            if not self.next_hop:
1227                self.module.fail_json(msg='Error: missing required argument: next_hop.')
1228            if self.state != 'absent':
1229                if self.nhp_interface == "Invalid0" and (not self.prefix or self.prefix == '0.0.0.0'):
1230                    self.module.fail_json(msg='Error: If a nhp_interface is not configured, '
1231                                              'the prefix must be configured.')
1232
1233        if self.function_flag != 'globalBFD':
1234            if self.function_flag == 'dynamicBFD' or self.function_flag == 'staticBFD':
1235                if not self.mask:
1236                    self.module.fail_json(msg='Error: missing required argument: mask.')
1237                # check prefix and mask
1238                if not self.mask.isdigit():
1239                    self.module.fail_json(msg='Error: Mask is invalid.')
1240            if self.function_flag != 'singleBFD' or (self.function_flag == 'singleBFD' and self.destvrf != "_public_"):
1241                if not self.prefix:
1242                    self.module.fail_json(msg='Error: missing required argument: prefix.')
1243                # convert prefix
1244                if not self._convertipprefix_():
1245                    self.module.fail_json(msg='Error: The %s is not a valid address' % self.prefix)
1246
1247            if self.nhp_interface != "Invalid0" and self.destvrf != "_public_":
1248                self.module.fail_json(msg='Error: Destination vrf dose not support next hop is interface.')
1249
1250            if not self.next_hop and self.nhp_interface == "Invalid0":
1251                self.module.fail_json(msg='Error: one of the following is required: next_hop,nhp_interface.')
1252
1253        if self.function_flag == 'dynamicBFD' or self.function_flag == 'staticBFD':
1254            # description check
1255            if self.description:
1256                if not is_valid_description(self.description):
1257                    self.module.fail_json(
1258                        msg='Error: Dsecription length should be 1 - 35, and can not contain "?".')
1259            # tag check
1260            if self.tag is not None:
1261                if not is_valid_tag(self.tag):
1262                    self.module.fail_json(
1263                        msg='Error: Tag should be integer 1 - 4294967295.')
1264            # preference check
1265            if self.pref is not None:
1266                if not is_valid_preference(self.pref):
1267                    self.module.fail_json(
1268                        msg='Error: Preference should be integer 1 - 255.')
1269
1270            if self.function_flag == 'staticBFD':
1271                if self.bfd_session_name:
1272                    if not is_valid_bdf_session_name(self.bfd_session_name):
1273                        self.module.fail_json(
1274                            msg='Error: bfd_session_name length should be 1 - 15, and can not contain Space.')
1275
1276        # ipv4 check
1277        if self.aftype == "v4":
1278            if self.function_flag == 'dynamicBFD' or self.function_flag == 'staticBFD':
1279                if int(self.mask) > 32 or int(self.mask) < 0:
1280                    self.module.fail_json(
1281                        msg='Error: Ipv4 mask must be an integer between 1 and 32.')
1282            # next_hop check
1283            if self.function_flag != 'globalBFD':
1284                if self.next_hop:
1285                    if not is_valid_v4addr(self.next_hop):
1286                        self.module.fail_json(
1287                            msg='Error: The %s is not a valid address.' % self.next_hop)
1288        # ipv6 check
1289        if self.aftype == "v6":
1290            if self.function_flag == 'dynamicBFD' or self.function_flag == 'staticBFD':
1291                if int(self.mask) > 128 or int(self.mask) < 0:
1292                    self.module.fail_json(
1293                        msg='Error: Ipv6 mask must be an integer between 1 and 128.')
1294            if self.function_flag != 'globalBFD':
1295                if self.next_hop:
1296                    if not is_valid_v6addr(self.next_hop):
1297                        self.module.fail_json(
1298                            msg='Error: The %s is not a valid address.' % self.next_hop)
1299
1300        if self.function_flag == 'globalBFD' or self.function_flag == 'singleBFD':
1301            # BFD prarams
1302            if self.min_tx_interval:
1303                if not is_valid_bdf_interval(self.min_tx_interval):
1304                    self.module.fail_json(
1305                        msg='Error: min_tx_interval should be integer 50 - 1000.')
1306            if self.min_rx_interval:
1307                if not is_valid_bdf_interval(self.min_rx_interval):
1308                    self.module.fail_json(
1309                        msg='Error: min_rx_interval should be integer 50 - 1000.')
1310            if self.detect_multiplier:
1311                if not is_valid_bdf_multiplier(self.detect_multiplier):
1312                    self.module.fail_json(
1313                        msg='Error: detect_multiplier should be integer 3 - 50.')
1314
1315            if self.function_flag == 'globalBFD':
1316                if self.state != 'absent':
1317                    if not self.min_tx_interval and not self.min_rx_interval and not self.detect_multiplier:
1318                        self.module.fail_json(
1319                            msg='Error: one of the following is required: min_tx_interval,'
1320                                'detect_multiplier,min_rx_interval.')
1321                else:
1322                    if not self.commands:
1323                        self.module.fail_json(
1324                            msg='Error: missing required argument: command.')
1325                    if compare_command(self.commands):
1326                        self.module.fail_json(
1327                            msg='Error: The command %s line is incorrect.' % (',').join(self.commands))
1328
1329    def set_ip_static_route_globalbfd(self):
1330        """set ip static route globalBFD"""
1331        if not self.changed:
1332            return
1333        if self.aftype == "v4":
1334            self.operate_static_route_globalbfd()
1335
1336    def set_ip_static_route_singlebfd(self):
1337        """set ip static route singleBFD"""
1338        if not self.changed:
1339            return
1340        version = None
1341        if self.aftype == "v4":
1342            version = "ipv4unicast"
1343        else:
1344            version = "ipv6unicast"
1345        self.operate_static_route_singlebfd(version, self.prefix, self.nhp_interface,
1346                                            self.next_hop, self.destvrf, self.state)
1347
1348    def set_ip_static_route(self):
1349        """set ip static route"""
1350        if not self.changed:
1351            return
1352        version = None
1353        if self.aftype == "v4":
1354            version = "ipv4unicast"
1355        else:
1356            version = "ipv6unicast"
1357        self.operate_static_route(version, self.prefix, self.mask, self.nhp_interface,
1358                                  self.next_hop, self.vrf, self.destvrf, self.state)
1359
1360    def is_prefix_exist(self, static_route, version):
1361        """is prefix mask nex_thop exist"""
1362        if static_route is None:
1363            return False
1364        if self.next_hop and self.nhp_interface:
1365            return static_route["prefix"].lower() == self.prefix.lower() \
1366                and static_route["maskLength"] == self.mask \
1367                and static_route["afType"] == version \
1368                and static_route["ifName"].lower() == self.nhp_interface.lower() \
1369                and static_route["nexthop"].lower() == self.next_hop.lower()
1370
1371        if self.next_hop and not self.nhp_interface:
1372            return static_route["prefix"].lower() == self.prefix.lower() \
1373                and static_route["maskLength"] == self.mask \
1374                and static_route["afType"] == version \
1375                and static_route["nexthop"].lower() == self.next_hop.lower()
1376
1377        if not self.next_hop and self.nhp_interface:
1378            return static_route["prefix"].lower() == self.prefix.lower() \
1379                and static_route["maskLength"] == self.mask \
1380                and static_route["afType"] == version \
1381                and static_route["ifName"].lower() == self.nhp_interface.lower()
1382
1383    def get_ip_static_route(self):
1384        """get ip static route"""
1385        change = False
1386        version = self.version
1387        self.get_static_route(self.state)
1388        change_list = list()
1389        if self.state == 'present':
1390            for static_route in self.static_routes_info["sroute"]:
1391                if self.is_prefix_exist(static_route, self.version):
1392                    info_dict = dict()
1393                    exist_dict = dict()
1394                    if self.vrf:
1395                        info_dict["vrfName"] = self.vrf
1396                        exist_dict["vrfName"] = static_route["vrfName"]
1397                    if self.destvrf:
1398                        info_dict["destVrfName"] = self.destvrf
1399                        exist_dict["destVrfName"] = static_route["destVrfName"]
1400                    if self.description:
1401                        info_dict["description"] = self.description
1402                        exist_dict["description"] = static_route["description"]
1403                    if self.tag:
1404                        info_dict["tag"] = self.tag
1405                        exist_dict["tag"] = static_route["tag"]
1406                    if self.pref:
1407                        info_dict["preference"] = str(self.pref)
1408                        exist_dict["preference"] = static_route["preference"]
1409                    if self.nhp_interface:
1410                        if self.nhp_interface.lower() == "invalid0":
1411                            info_dict["ifName"] = "Invalid0"
1412                        else:
1413                            info_dict["ifName"] = "Invalid0"
1414                        exist_dict["ifName"] = static_route["ifName"]
1415                    if self.next_hop:
1416                        info_dict["nexthop"] = self.next_hop
1417                        exist_dict["nexthop"] = static_route["nexthop"]
1418
1419                    if self.bfd_session_name:
1420                        info_dict["bfdEnable"] = 'true'
1421
1422                    else:
1423                        info_dict["bfdEnable"] = 'false'
1424                    exist_dict["bfdEnable"] = static_route["bfdEnable"]
1425
1426                    if exist_dict != info_dict:
1427                        change = True
1428                    else:
1429                        change = False
1430                    change_list.append(change)
1431
1432            if False in change_list:
1433                change = False
1434            else:
1435                change = True
1436            return change
1437
1438        else:
1439            for static_route in self.static_routes_info["sroute"]:
1440                if static_route["nexthop"] and self.next_hop:
1441                    if static_route["prefix"].lower() == self.prefix.lower() \
1442                            and static_route["maskLength"] == self.mask \
1443                            and static_route["nexthop"].lower() == self.next_hop.lower() \
1444                            and static_route["afType"] == version:
1445                        change = True
1446                        return change
1447                if static_route["ifName"] and self.nhp_interface:
1448                    if static_route["prefix"].lower() == self.prefix.lower() \
1449                            and static_route["maskLength"] == self.mask \
1450                            and static_route["ifName"].lower() == self.nhp_interface.lower() \
1451                            and static_route["afType"] == version:
1452                        change = True
1453                        return change
1454                else:
1455                    continue
1456            change = False
1457        return change
1458
1459    def get_proposed(self):
1460        """get proposed information"""
1461        self.proposed['afType'] = self.aftype
1462        self.proposed['state'] = self.state
1463        if self.function_flag != 'globalBFD':
1464            self.proposed['ifName'] = self.nhp_interface
1465            self.proposed['destVrfName'] = self.destvrf
1466            self.proposed['next_hop'] = self.next_hop
1467
1468        if self.function_flag == 'singleBFD':
1469            if self.prefix:
1470                self.proposed['localAddress'] = self.prefix
1471
1472        if self.function_flag == 'globalBFD' or self.function_flag == 'singleBFD':
1473            self.proposed['minTxInterval'] = self.min_tx_interval
1474            self.proposed['minRxInterval'] = self.min_rx_interval
1475            self.proposed['multiplier'] = self.detect_multiplier
1476
1477        if self.function_flag != 'globalBFD' and self.function_flag != 'singleBFD':
1478            self.proposed['prefix'] = self.prefix
1479            self.proposed['mask'] = self.mask
1480            self.proposed['vrfName'] = self.vrf
1481            if self.tag:
1482                self.proposed['tag'] = self.tag
1483            if self.description:
1484                self.proposed['description'] = self.description
1485            if self.pref is None:
1486                self.proposed['preference'] = 60
1487            else:
1488                self.proposed['preference'] = self.pref
1489
1490            static_bfd_flag = True
1491            if self.bfd_session_name:
1492                static_bfd_flag = False
1493            if not static_bfd_flag:
1494                self.proposed['sessionName'] = self.bfd_session_name
1495            else:
1496                self.proposed['bfdEnable'] = 'true'
1497
1498    def get_existing(self):
1499        """get existing information"""
1500        # globalBFD
1501        if self.function_flag == 'globalBFD':
1502            change = self.get_change_state_global_bfd()
1503            self.existing['sroute_global_bfd'] = self.static_routes_info["sroute_global_bfd"]
1504        # singleBFD
1505        elif self.function_flag == 'singleBFD':
1506            change = self.get_change_state_single_bfd()
1507            self.existing['sroute_single_bfd'] = self.static_routes_info["sroute_single_bfd"]
1508        # dynamicBFD / staticBFD
1509        else:
1510            change = self.get_ip_static_route()
1511            self.existing['static_sroute'] = self.static_routes_info["sroute"]
1512        self.changed = bool(change)
1513
1514    def get_end_state(self):
1515        """get end state information"""
1516
1517        # globalBFD
1518        if self.function_flag == 'globalBFD':
1519            self.get_global_bfd(self.state)
1520            self.end_state['sroute_global_bfd'] = self.static_routes_info["sroute_global_bfd"]
1521        # singleBFD
1522        elif self.function_flag == 'singleBFD':
1523            self.static_routes_info["sroute_single_bfd"] = list()
1524            self.get_single_bfd(self.state)
1525            self.end_state['sroute_single_bfd'] = self.static_routes_info["sroute_single_bfd"]
1526        # dynamicBFD / staticBFD
1527        else:
1528            self.get_static_route(self.state)
1529            self.end_state['static_sroute'] = self.static_routes_info["sroute"]
1530
1531    def work(self):
1532        """worker"""
1533        self._checkparams_()
1534        self.get_existing()
1535        self.get_proposed()
1536
1537        if self.function_flag == 'globalBFD':
1538            self.set_ip_static_route_globalbfd()
1539            self.set_update_cmd_globalbfd()
1540        elif self.function_flag == 'singleBFD':
1541            self.set_ip_static_route_singlebfd()
1542            self.set_update_cmd_singlebfd()
1543        else:
1544            self.set_ip_static_route()
1545            self.set_update_cmd()
1546
1547        self.get_end_state()
1548        if self.existing == self.end_state:
1549            self.changed = False
1550        self.results['changed'] = self.changed
1551        self.results['proposed'] = self.proposed
1552        self.results['existing'] = self.existing
1553        self.results['end_state'] = self.end_state
1554        if self.changed:
1555            self.results['updates'] = self.updates_cmd
1556        else:
1557            self.results['updates'] = list()
1558
1559        self.module.exit_json(**self.results)
1560
1561
1562def main():
1563    """main"""
1564
1565    argument_spec = dict(
1566        prefix=dict(type='str'),
1567        mask=dict(type='str'),
1568        aftype=dict(choices=['v4', 'v6'], required=True),
1569        next_hop=dict(type='str'),
1570        nhp_interface=dict(type='str'),
1571        vrf=dict(type='str'),
1572        destvrf=dict(type='str'),
1573        tag=dict(type='int'),
1574        description=dict(type='str'),
1575        pref=dict(type='int'),
1576        # bfd
1577        function_flag=dict(required=True, choices=['globalBFD', 'singleBFD', 'dynamicBFD', 'staticBFD']),
1578        min_tx_interval=dict(type='int'),
1579        min_rx_interval=dict(type='int'),
1580        detect_multiplier=dict(type='int'),
1581        # bfd session name
1582        bfd_session_name=dict(type='str'),
1583        commands=dict(type='list', required=False),
1584        state=dict(choices=['absent', 'present'], default='present', required=False),
1585    )
1586    interface = StaticRouteBFD(argument_spec)
1587    interface.work()
1588
1589
1590if __name__ == '__main__':
1591    main()
1592