From 47f5736043b1b89198f41fe3e9eb1aaf219c0ac4 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Mon, 10 Aug 2020 15:28:33 -0700 Subject: [PATCH 01/24] Initial commit for adding non-template bgpcfgd script --- dockers/docker-fpm-frr/docker_init.sh | 6 + dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 | 91 + .../frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 | 78 + .../frr/bgpd/bgpd.conf.db.addr_family.j2 | 143 + .../frr/bgpd/bgpd.conf.db.comm_list.j2 | 54 + .../docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 | 200 + .../frr/bgpd/bgpd.conf.db.nbr_af.j2 | 150 + .../frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 | 103 + .../frr/bgpd/bgpd.conf.db.pref_list.j2 | 30 + .../frr/bgpd/bgpd.conf.db.route_map.j2 | 150 + dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 | 4 + .../docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 | 38 + .../frr/ospfd/ospfd.conf.db.area.j2 | 37 + .../frr/ospfd/ospfd.conf.db.comm_list.j2 | 129 + .../ospfd/ospfd.conf.db.distributeroute.j2 | 52 + .../frr/ospfd/ospfd.conf.db.interface.j2 | 76 + .../frr/ospfd/ospfd.conf.db.policyrange.j2 | 16 + .../frr/ospfd/ospfd.conf.db.vlink.j2 | 29 + .../frr/staticd/staticd.conf.j2 | 2 + .../frr/staticd/staticd.db.conf.j2 | 149 + .../frr/supervisord/supervisord.conf.j2 | 40 + src/sonic-bgpcfgd/bgpcfgd_no_template | 3770 +++++++++++++++++ 22 files changed, 5347 insertions(+) create mode 100644 dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 create mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 create mode 100644 dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 create mode 100755 src/sonic-bgpcfgd/bgpcfgd_no_template diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index c0cc341ce795..640eecd884ac 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -6,6 +6,7 @@ mkdir -p /etc/supervisor/conf.d sonic-cfggen -d -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2 > /etc/supervisor/conf.d/supervisord.conf CONFIG_TYPE=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["docker_routing_config_mode"]'` +TEMPL_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["bgp_template_config"]'` if [[ ! -z "$NAMESPACE_ID" ]]; then # FRR is not running in host namespace so we need to delete @@ -34,12 +35,17 @@ if [ -z "$CONFIG_TYPE" ] || [ "$CONFIG_TYPE" == "separated" ]; then sonic-cfggen -d -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2 -y /etc/sonic/constants.yml > /etc/frr/bgpd.conf sonic-cfggen -d -t /usr/share/sonic/templates/zebra/zebra.conf.j2 > /etc/frr/zebra.conf sonic-cfggen -d -t /usr/share/sonic/templates/staticd/staticd.conf.j2 > /etc/frr/staticd.conf + if [ -n "$TEMPL_CONFIG" ] && [ "$TEMPL_CONFIG" == "false" ]; then + sonic-cfggen -d -t /usr/share/sonic/templates/bgdd/bfdd.conf.j2 > /etc/frr/bfdd.conf + sonic-cfggen -d -t /usr/share/sonic/templates/ospfd/ospfd.conf.j2 > /etc/frr/ospfd.conf + fi echo "no service integrated-vtysh-config" > /etc/frr/vtysh.conf rm -f /etc/frr/frr.conf elif [ "$CONFIG_TYPE" == "unified" ]; then sonic-cfggen -d -y /etc/sonic/constants.yml -t /usr/share/sonic/templates/frr.conf.j2 >/etc/frr/frr.conf echo "service integrated-vtysh-config" > /etc/frr/vtysh.conf rm -f /etc/frr/bgpd.conf /etc/frr/zebra.conf /etc/frr/staticd.conf + rm -f /etc/frr/bfdd.conf /etc/frr/ospfd.conf /etc/frr/pimd.conf fi chown -R frr:frr /etc/frr/ diff --git a/dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 b/dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 new file mode 100644 index 000000000000..fc3b4f177f32 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 @@ -0,0 +1,91 @@ +! +{% block banner %} +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/frr/bfd.conf.j2 with config DB data +! file: bfd.conf +! +{% endblock banner %} +! +{% block bfd_shop_peers %} +{% if BFD_PEER_SINGLE_HOP %} +bfd +{% for (peer_key, peer_info) in BFD_PEER_SINGLE_HOP.iteritems() %} +{% set peer_args = '' %} +{% if peer_key[0] != 'null' %} +{% set peer_args = peer_args~' '~'peer'~' '~peer_key[0] %} +{% endif %} +{% if peer_key[1] != 'null' %} +{% set peer_args = peer_args~' '~'interface'~' '~peer_key[1] %} +{% endif %} +{% if peer_key[2] != 'null' %} +{% set peer_args = peer_args~' '~'vrf'~' '~peer_key[2] %} +{% endif %} +{% if peer_key[3] != 'null' %} +{% set peer_args = peer_args~' '~'local-address'~' '~peer_key[3] %} +{% endif %} +{{ peer_args }} +{# set the bfd peer timers #} +{% if (peer_info['desired-minimum-tx-interval'] is defined and peer_info['desired-minimum-tx-interval'] | int != 300) %} + transmit-interval {{ peer_info['desired-minimum-tx-interval'] }} +{% endif %} +{% if (peer_info['required-minimum-receive'] is defined and peer_info['required-minimum-receive'] | int != 300) %} + receive-interval {{ peer_info['required-minimum-receive'] }} +{% endif %} +{% if (peer_info['detection-multiplier'] is defined and peer_info['detection-multiplier'] | int != 3) %} + detect-multiplier {{ peer_info['detection-multiplier'] }} +{% endif %} +{% if (peer_info['echo-active'] is defined and peer_info['echo-active'] != 'false') %} + echo-mode +{% endif %} +{% if (peer_info['desired-minimum-echo-receive'] is defined and peer_info['desired-minimum-echo-receive'] | int != 50) %} + echo-interval {{ peer_info['desired-minimum-echo-receive'] }} +{% endif %} +{% if (peer_info['enabled'] is defined and peer_info['enabled'] == 'true') %} + no shutdown +{% else %} + shutdown +{% endif %} + ! +{% endfor %} +! +{% endif %} +{% endblock bfd_shop_peers%} +{% block bfd_mhop_peers %} +{% if BFD_PEER_MULTI_HOP %} +bfd +{% for (peer_key, peer_info) in BFD_PEER_MULTI_HOP.iteritems() %} +{% set peer_args = '' %} +{% if peer_key[0] != 'null' %} +{% set peer_args = peer_args~' '~'peer'~' '~peer_key[0] %} +{% endif %} +{% if peer_key[1] != 'null' %} +{% set peer_args = peer_args~' '~'interface'~' '~peer_key[1] %} +{% endif %} +{% if peer_key[2] != 'null' %} +{% set peer_args = peer_args~' '~'vrf'~' '~peer_key[2] %} +{% endif %} +{% if peer_key[3] != 'null' %} +{% set peer_args = peer_args~' '~'local-address'~' '~peer_key[3] %} +{% endif %} +{% set peer_args = peer_args~' '~'multihop' %} +{{ peer_args }} +{# set the bfd peer timers #} +{% if (peer_info['desired-minimum-tx-interval'] is defined and peer_info['desired-minimum-tx-interval'] | int != 300) %} + transmit-interval {{ peer_info['desired-minimum-tx-interval'] }} +{% endif %} +{% if (peer_info['required-minimum-receive'] is defined and peer_info['required-minimum-receive'] | int != 300) %} + receive-interval {{ peer_info['required-minimum-receive'] }} +{% endif %} +{% if (peer_info['detection-multiplier'] is defined and peer_info['detection-multiplier'] | int != 3) %} + detect-multiplier {{ peer_info['detection-multiplier'] }} +{% endif %} +{% if (peer_info['enabled'] is defined and peer_info['enabled'] == 'true') %} + no shutdown +{% else %} + shutdown +{% endif %} + ! +{% endfor %} +! +{% endif %} +{% endblock bfd_mhop_peers%} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 new file mode 100644 index 000000000000..c130ac3cc616 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 @@ -0,0 +1,78 @@ +{% if af_val.has_key('advertise-all-vni') and af_val['advertise-all-vni'] == 'true' %} + advertise-all-vni +{% endif %} +{% if af_val.has_key('autort') %} + autort {{af_val['autort']}} +{% endif %} +{% if af_val.has_key('advertise-default-gw') and af_val['advertise-default-gw'] == 'true' %} + advertise-default-gw +{% endif %} +{% if af_val.has_key('dad-enabled') and af_val.has_key('dad-max-moves') and af_val.has_key('dad-time') %} + dup-addr-detection max-moves {{af_val['dad-max-moves']}} time {{af_val['dad-time']}} +{% endif %} +{% if af_val.has_key('dad-freeze') %} + dup-addr-detection freeze {{af_val['dad-freeze']}} +{% endif %} +{% if af_val.has_key('advertise-ipv4-unicast') and af_val['advertise-ipv4-unicast'] == 'true' %} + advertise ipv4 unicast +{% endif %} +{% if af_val.has_key('advertise-ipv6-unicast') and af_val['advertise-ipv6-unicast'] == 'true' %} + advertise ipv6 unicast +{% endif %} +{% if af_val.has_key('default-originate-ipv4') and af_val['default-originate-ipv4'] == 'true' %} + default-originate ipv4 +{% endif %} +{% if af_val.has_key('default-originate-ipv6') and af_val['default-originate-ipv6'] == 'true' %} + default-originate ipv6 +{% endif %} +{% if af_val.has_key('route-distinguisher') %} + rd {{af_val['route-distinguisher']}} +{% endif %} +{% if af_val.has_key('import-rts') %} +{% for irt in af_val['import-rts'] %} + route-target import {{irt}} +{% endfor %} +{% endif %} +{% if af_val.has_key('export-rts') %} +{% for irt in af_val['export-rts'] %} + route-target export {{irt}} +{% endfor %} +{% endif %} +{% if BGP_GLOBALS_EVPN_RT is defined and BGP_GLOBALS_EVPN_RT|length > 0 %} +{% for evpn_rt_key, evpn_rt_val in BGP_GLOBALS_EVPN_RT.iteritems() %} +{% if vrf == evpn_rt_key[0] %} + route-target {{evpn_rt_val['route-target-type']}} {{evpn_rt_key[2]}} +{% endif %} +{% endfor %} +{% endif %} +{% if BGP_GLOBALS_EVPN_VNI is defined and BGP_GLOBALS_EVPN_VNI|length > 0 %} +{% for vni_key, vni_val in BGP_GLOBALS_EVPN_VNI.iteritems() %} +{% if vrf == vni_key[0] %} + vni {{vni_key[2]}} +{% if vni_val.has_key('route-distinguisher') %} + rd {{vni_val['route-distinguisher']}} +{% endif %} +{% if vni_val.has_key('import-rts') %} +{% for irt in vni_val['import-rts'] %} + route-target import {{irt}} +{% endfor %} +{% endif %} +{% if vni_val.has_key('export-rts') %} +{% for irt in vni_val['export-rts'] %} + route-target export {{irt}} +{% endfor %} +{% endif %} +{% if BGP_GLOBALS_EVPN_VNI_RT is defined and BGP_GLOBALS_EVPN_VNI_RT|length > 0 %} +{% for vni_rt_key, vni_rt_val in BGP_GLOBALS_EVPN_VNI_RT.iteritems() %} +{% if vrf == vni_rt_key[0] and vni_key[2] == vni_rt_key[2] %} + route-target {{vni_rt_val['route-target-type']}} {{vni_rt_key[3]}} +{% endif %} +{% endfor %} +{% endif %} +{% if vni_val.has_key('advertise-default-gw') and vni_val['advertise-default-gw'] == 'true' %} + advertise-default-gw +{% endif %} + exit-vni +{% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 new file mode 100644 index 000000000000..220db779ac91 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 @@ -0,0 +1,143 @@ +{# -----------------------------------------------------------------------------------------#} +{# this is invoked with the "vrf" variable set #} +{# -----------------------------------------------------------------------------------------#} +{# -------address-family --------------------------- #} +{% if (BGP_GLOBALS_AF is defined and BGP_GLOBALS_AF|length > 0) or + (BGP_GLOBALS_AF_NETWORK is defined and BGP_GLOBALS_AF_NETWORK|length > 0) or + (BGP_GLOBALS_AF_AGGREGATE_ADDR is defined and BGP_GLOBALS_AF_AGGREGATE_ADDR|length > 0) or + (ROUTE_REDISTRIBUTE is defined and ROUTE_REDISTRIBUTE|length > 0) or + (BGP_PEER_GROUP_AF is defined and BGP_PEER_GROUP_AF|length > 0) or + (BGP_NEIGHBOR_AF is defined and BGP_NEIGHBOR_AF|length > 0) %} +{% set af_str_map = { 'ipv4_unicast': 'ipv4', 'ipv6_unicast':'ipv6', 'l2vpn_evpn':'l2vpn'} %} +{% set safi_str_map = { 'ipv4_unicast': 'unicast', 'ipv6_unicast':'unicast', 'l2vpn_evpn':'evpn'} %} +{% for af, af_str in af_str_map|dictsort %} + ! + address-family {{af_str}} {{safi_str_map[af]}} +{% if BGP_GLOBALS_AF is defined and BGP_GLOBALS_AF|length > 0 %} +{% for af_key, af_val in BGP_GLOBALS_AF.iteritems() %} +{% if vrf == af_key[0] and af == af_key[1] %} +{% if af_val.has_key('ebgp_route_distance') and af_val.has_key('ibgp_route_distance') and af_val.has_key('local_route_distance') %} + distance bgp {{af_val['ebgp_route_distance']}} {{af_val['ibgp_route_distance']}} {{af_val['local_route_distance']}} +{% endif %} +{% if af_val.has_key('import_vrf') %} + import vrf {{af_val['import_vrf']}} +{% endif %} +{% if af_val.has_key('import_vrf_route_map') %} + import vrf route-map {{af_val['import_vrf_route_map']}} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# ------- network-prefix --------------------------- #} +{% if BGP_GLOBALS_AF_NETWORK is defined and BGP_GLOBALS_AF_NETWORK|length > 0 %} +{% for af_nw_key, af_nw_val in BGP_GLOBALS_AF_NETWORK.iteritems() %} +{% if vrf == af_nw_key[0] and af == af_nw_key[1] %} +{% set af_nw_ns = namespace(nw_end = '') %} +{% if af_nw_val.has_key('backdoor') and af_nw_val['backdoor'] == 'true' %} +{% set af_nw_ns.nw_end = 'backdoor ' %} +{% endif %} +{% if af_nw_val.has_key('policy') %} +{% set af_nw_ns.nw_end = af_nw_ns.nw_end + 'route-map ' + af_nw_val['policy'] %} +{% endif %} + network {{af_nw_key[2]}} {{af_nw_ns.nw_end}} +{% endif %} +{% endfor %} +{% endif %} +{# ------- network-prefix end --------------------------- #} +{# ------- aggregate-prefix -Start--------------------------- #} +{% if BGP_GLOBALS_AF_AGGREGATE_ADDR is defined and BGP_GLOBALS_AF_AGGREGATE_ADDR|length > 0 %} +{% for af_ag_key, af_ag_val in BGP_GLOBALS_AF_AGGREGATE_ADDR.iteritems() %} +{% set af_ag_ns = namespace(ag_end = '') %} +{% if vrf == af_ag_key[0] and af == af_ag_key[1] %} +{% if af_ag_val.has_key('as_set') and af_ag_val['as_set'] == 'true' %} +{% set af_ag_ns.ag_end = 'as-set ' %} +{% endif %} +{% if af_ag_val.has_key('summary_only') and af_ag_val['summary_only'] == 'true' %} +{% set af_ag_ns.ag_end = af_ag_ns.ag_end + 'summary-only' %} +{% endif %} + aggregate-address {{af_ag_key[2]}} {{af_ag_ns.ag_end}} +{% endif %} +{% endfor %} +{% endif %} +{# ------- aggregate-prefix - End --------------------------- #} +{# ------- redistribute - Start --------------------------- #} +{% if ROUTE_REDISTRIBUTE is defined and ROUTE_REDISTRIBUTE|length > 0 %} +{% for rr_key, rr_val in ROUTE_REDISTRIBUTE.items() %} +{% if vrf == rr_key[0] and af_str == rr_key[3] %} +{% if rr_val.has_key('route_map') %} +{% for rmap in rr_val['route_map'] %} + redistribute {{rr_key[1]}} route-map {{rmap}} +{% endfor %} +{% else %} + redistribute {{rr_key[1]}} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# ------- redistribute - End ----------------------------- #} +{# ------- peer-group af--------------------------- #} +{% if BGP_PEER_GROUP_AF is defined and BGP_PEER_GROUP_AF|length > 0 %} +{% for n_af_key, n_af_val in BGP_PEER_GROUP_AF.items() %} +{% if vrf == n_af_key[0] and af == n_af_key[2] %} +{% set nbr_name = n_af_key[1] %} +{% include "bgpd.conf.db.nbr_af.j2" %} +{% endif %} +{% endfor %} +{% endif %} +{# ------- peer-group af end --------------------------- #} +{# ------- neighbor af--------------------------- #} +{% if BGP_NEIGHBOR_AF is defined and BGP_NEIGHBOR_AF|length > 0 %} +{% for n_af_key, n_af_val in BGP_NEIGHBOR_AF.items() %} +{% if vrf == n_af_key[0] and af == n_af_key[2] %} +{% set nbr_name = n_af_key[1] %} +{% include "bgpd.conf.db.nbr_af.j2" %} +{% endif %} +{% endfor %} +{% endif %} +{# ------- neighbor af end --------------------------- #} +{% if BGP_GLOBALS_AF is defined and BGP_GLOBALS_AF|length > 0 %} +{% for af_key, af_val in BGP_GLOBALS_AF.items() %} +{% if vrf == af_key[0] and af == af_key[1] %} +{# -------bgp dampen - start--------------------------- #} +{% if af_val.has_key('route_flap_dampen') and af_val['route_flap_dampen'] == 'true' %} +{% set ns = namespace(route_dampen = '') %} +{% if af_val.has_key('route_flap_dampen_half_life') %} +{% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_half_life'] + ' ' %} +{% if af_val.has_key('route_flap_dampen_reuse_threshold') %} +{% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_reuse_threshold'] + ' ' %} +{% if af_val.has_key('route_flap_dampen_suppress_threshold') %} +{% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_suppress_threshold'] + ' ' %} +{% if af_val.has_key('route_flap_dampen_max_suppress') %} +{% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_max_suppress'] + ' ' %} +{% endif %} +{% endif %} +{% endif %} +{% endif %} + bgp dampening {{ns.route_dampen}} +{% endif %} +{# -------bgp dampen - end --------------------------- #} +{% if af_val.has_key('max_ebgp_paths') %} + maximum-paths {{af_val['max_ebgp_paths']}} +{% endif %} +{% if af_val.has_key('max_ibgp_paths') %} +{% set ns = namespace(max_ibgp = af_val['max_ibgp_paths']) %} +{% if af_val.has_key('ibgp_equal_cluster_length') and af_val['ibgp_equal_cluster_length'] == 'true' %} +{% set ns.max_ibgp = ns.max_ibgp + ' equal-cluster-length' %} +{% endif %} + maximum-paths ibgp {{ns.max_ibgp}} +{% endif %} +{% if af_val.has_key('route_download_filter') %} + table-map {{af_val['route_download_filter']}} +{% endif %} +{# -------bgp evpn - start --------------------------- #} +{% if af == 'l2vpn_evpn' %} +{% include "bgpd.conf.db.addr_family.evpn.j2" %} +{% endif %} +{# -------bgp evpn - end --------------------------- #} +{% endif %} +{% endfor %} +{% endif %} + exit-address-family +{% endfor %} +{% endif %} +{# -------address-family end --------------------------- #} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 new file mode 100644 index 000000000000..e61b98c164b7 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 @@ -0,0 +1,54 @@ +{# ------------------------------------------------------------------------------------ #} +{% if (COMMUNITY_SET is defined and COMMUNITY_SET|length > 0) or + (EXTENDED_COMMUNITY_SET is defined and EXTENDED_COMMUNITY_SET|length >0) %} +! +{% endif %} +{# ------------------------------------------------------------------------------------ #} +{% if COMMUNITY_SET is defined and COMMUNITY_SET|length > 0 %} +{% for cm_key, cm_val in COMMUNITY_SET.items() %} +{% if cm_val.has_key('set_type') and cm_val.has_key('match_action') and cm_val.has_key('community_member') %} +{% if cm_val['match_action']|lower == 'all' %} +{% set ns = namespace(cm_list = '') %} +{% for cm in cm_val['community_member'] %} +{% set ns.cm_list = ns.cm_list + cm + ' ' %} +{% endfor %} +bgp community-list {{cm_val['set_type']|lower}} {{cm_key}} permit {{ns.cm_list}} +{% elif cm_val['match_action']|lower == 'any' %} +{% for cm in cm_val['community_member'] %} +bgp community-list {{cm_val['set_type']|lower}} {{cm_key}} permit {{cm}} +{% endfor %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# ------------------------------------------------------------------------------------ #} +{% if EXTENDED_COMMUNITY_SET is defined and EXTENDED_COMMUNITY_SET|length > 0 %} +{% for cm_key, cm_val in EXTENDED_COMMUNITY_SET.items() %} +{% if cm_val.has_key('set_type') and cm_val.has_key('match_action') and cm_val.has_key('community_member') %} +{% if cm_val['match_action']|lower == 'all' %} +{% set ns = namespace(cm_list = '') %} +{% for cm in cm_val['community_member'] %} +{% if 'route-target' in cm %} +{% set ns.cm_list = ns.cm_list + 'rt ' + cm[13:] + ' ' %} +{% elif 'route-origin' in cm %} +{% set ns.cm_list = ns.cm_list + 'soo ' + cm[13:] + ' ' %} +{% else %} +{% set ns.cm_list = ns.cm_list + cm + ' ' %} +{% endif %} +{% endfor %} +bgp extcommunity-list {{cm_val['set_type']|lower}} {{cm_key}} permit {{ns.cm_list}} +{% elif cm_val['match_action']|lower == 'any' %} +{% for cm in cm_val['community_member'] %} +{% if 'route-target' in cm %} +bgp extcommunity-list {{cm_val['set_type']|lower}} {{cm_key}} permit rt {{cm[13:]}} +{% elif 'route-origin' in cm %} +bgp extcommunity-list {{cm_val['set_type']|lower}} {{cm_key}} permit soo {{cm[13:]}} +{% else %} +bgp extcommunity-list {{cm_val['set_type']|lower}} {{cm_key}} permit {{cm}} +{% endif %} +{% endfor %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# ------------------------------------------------------------------------------------ #} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 new file mode 100644 index 000000000000..e081e9de6f3c --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 @@ -0,0 +1,200 @@ +{# ------------------------------------------------------------------------------------ #} +{% include "bgpd.conf.db.pref_list.j2" %} +{# ------------------------------------------------------------------------------------ #} +{# ------------------------------------------------------------------------------------ #} +{% include "bgpd.conf.db.route_map.j2" %} +{# ------------------------------------------------------------------------------------ #} +{% if AS_PATH_SET is defined and AS_PATH_SET|length > 0 %} +! +{% for key, val in AS_PATH_SET.items() %} +{% if val.has_key('as_path_set_member') %} +{% for path in val['as_path_set_member'] %} +bgp as-path access-list {{key}} permit {{path}} +{% endfor %} +{% endif %} +{% endfor %} +{% endif %} +{# ------------------------------------------------------------------------------------ #} +{% include "bgpd.conf.db.comm_list.j2" %} +{# ------------------------------------------------------------------------------------ #} +{% if BGP_GLOBALS is defined and BGP_GLOBALS|length > 0 %} +{% for vrf, bgp_sess in BGP_GLOBALS.items() %} +{% if bgp_sess.has_key('local_asn') %} +! +{% if vrf == 'default' %} +router bgp {{ bgp_sess['local_asn']}} +{% else %} +router bgp {{ bgp_sess['local_asn']}} vrf {{ vrf }} +{% endif %} +{% if bgp_sess.has_key('fast_external_failover') and bgp_sess['fast_external_failover'] == 'false' %} + no bgp fast-external-failover +{% endif %} +{% if bgp_sess.has_key('router_id') %} + bgp router-id {{bgp_sess['router_id']}} +{% endif %} +{% if bgp_sess.has_key('log_nbr_state_changes') and bgp_sess['log_nbr_state_changes'] == 'true' %} + bgp log-neighbor-changes +{% endif %} +{% if bgp_sess.has_key('always_compare_med') and bgp_sess['always_compare_med'] == 'true' %} + bgp always-compare-med +{% endif %} +{# --------------------------bgp default - start -------------------------------------- #} +{% if bgp_sess.has_key('default_ipv4_unicast') and bgp_sess['default_ipv4_unicast'] == 'true' %} + bgp default ipv4-unicast +{% else %} + no bgp default ipv4-unicast +{% endif %} +{% if bgp_sess.has_key('default_local_preference') %} + bgp default local-preference {{bgp_sess['default_local_preference']}} +{% endif %} +{% if bgp_sess.has_key('default_show_hostname') and bgp_sess['default_show_hostname'] == 'true' %} + bgp default show-hostname +{% endif %} +{% if bgp_sess.has_key('default_shutdown') and bgp_sess['default_shutdown'] == 'true' %} + bgp default shutdown +{% endif %} +{% if bgp_sess.has_key('default_subgroup_pkt_queue_max') %} + bgp default subgroup-pkt-queue-max {{bgp_sess['default_subgroup_pkt_queue_max']}} +{% endif %} +{# --------------------------bgp default - end ---------------------------------------- #} +{% if bgp_sess.has_key('rr_clnt_to_clnt_reflection') and bgp_sess['rr_clnt_to_clnt_reflection'] == 'false' %} + no bgp client-to-client reflection +{% endif %} +{% if bgp_sess.has_key('rr_cluster_id') %} + bgp cluster-id {{bgp_sess['rr_cluster_id']}} +{% endif %} +{% if bgp_sess.has_key('disable_ebgp_connected_rt_check') and bgp_sess['disable_ebgp_connected_rt_check'] == 'true' %} + bgp disable-ebgp-connected-route-check +{% endif %} +{% if bgp_sess.has_key('deterministic_med') and bgp_sess['deterministic_med'] == 'true' %} + bgp deterministic-med +{% endif %} +{% if bgp_sess.has_key('max_delay') %} +{% set ns = namespace(max_delay = '') %} +{% set ns.max_delay = ns.max_delay + bgp_sess['max_delay'] %} +{% if bgp_sess.has_key('establish_wait') %} +{% set ns.max_delay = ns.max_delay + ' ' + bgp_sess['establish_wait'] %} +{% endif %} + update-delay {{ns.max_delay}} +{% endif %} +{% if bgp_sess.has_key('max_med_time') %} +{% set ns = namespace(max_med = '') %} +{% set ns.max_med = ns.max_med + bgp_sess['max_med_time'] %} +{% if bgp_sess.has_key('max_med_val') %} +{% set ns.max_med = ns.max_med + ' ' + bgp_sess['max_med_val'] %} +{% endif %} + bgp max-med on-startup {{ns.max_med}} +{% endif %} +{% if bgp_sess.has_key('max_med_admin') %} +{% set adm_ns = namespace(admin_val = '') %} +{% if bgp_sess.has_key('max_med_admin_val') %} +{% set adm_ns.admin_val = adm_ns.admin_val + ' ' + bgp_sess['max_med_admin_val'] %} +{% endif %} + bgp max-med administrative {{adm_ns.admin_val}} +{% endif %} +{% if bgp_sess.has_key('read_quanta') %} + read-quanta {{bgp_sess['read_quanta']}} +{% endif %} +{% if bgp_sess.has_key('write_quanta') %} + write-quanta {{bgp_sess['write_quanta']}} +{% endif %} +{% if bgp_sess.has_key('coalesce_time') %} + coalesce-time {{bgp_sess['coalesce_time']}} +{% endif %} +{# --------------------------bgp graceful-restart - start ----------------------------- #} +{% if bgp_sess.has_key('gr_stale_routes_time') %} + bgp graceful-restart stalepath-time {{bgp_sess['gr_stale_routes_time']}} +{% endif %} +{% if bgp_sess.has_key('gr_restart_time') %} + bgp graceful-restart restart-time {{bgp_sess['gr_restart_time']}} +{% endif %} +{% if bgp_sess.has_key('graceful_restart_enable') and bgp_sess['graceful_restart_enable'] == 'true' %} + bgp graceful-restart +{% endif %} +{% if bgp_sess.has_key('graceful_shutdown') and bgp_sess['graceful_shutdown'] == 'true' %} + bgp graceful-shutdown +{% endif %} +{% if bgp_sess.has_key('gr_preserve_fw_state') and bgp_sess['gr_preserve_fw_state'] == 'true' %} + bgp graceful-restart preserve-fw-state +{% endif %} +{# --------------------------bgp graceful-restart - end ----------------------------- #} +{# --------------------------bgp bestpath as-path - start ----------------------------- #} +{% if bgp_sess.has_key('ignore_as_path_length') %} + bgp bestpath as-path ignore +{% endif %} +{% if bgp_sess.has_key('compare_confed_as_path') and bgp_sess['compare_confed_as_path'] == 'true' %} + bgp bestpath as-path confed +{% endif %} +{% if bgp_sess.has_key('load_balance_mp_relax') and bgp_sess['load_balance_mp_relax'] == 'true' %} +{% set mp_ns = namespace(mp_val = '') %} +{% if bgp_sess.has_key('as_path_mp_as_set') and bgp_sess['as_path_mp_as_set'] == 'true' %} +{% set mp_ns.mp_val = mp_ns.mp_val + 'as-set' %} +{% elif bgp_sess.has_key('as_path_mp_as_set') and bgp_sess['as_path_mp_as_set'] == 'false' %} +{% set mp_ns.mp_val = mp_ns.mp_val + 'no-as-set' %} +{% endif %} + bgp bestpath as-path multipath-relax {{mp_ns.mp_val}} +{% endif %} +{# --------------------------bgp bestpath as-path - end ----------------------------- #} +{% if bgp_sess.has_key('rr_allow_out_policy') and bgp_sess['rr_allow_out_policy'] == 'true' %} + bgp route-reflector allow-outbound-policy +{% endif %} +{% if bgp_sess.has_key('external_compare_router_id') %} + bgp bestpath compare-routerid +{% endif %} +{% if bgp_sess.has_key('med_confed') and bgp_sess['med_confed'] == 'true' %} + bgp bestpath med confed +{% endif %} +{% if bgp_sess.has_key('med_missing_as_worst') and bgp_sess['med_missing_as_worst'] == 'true' %} + bgp bestpath med confed missing-as-worst +{% endif %} +{% if bgp_sess.has_key('network_import_check') and bgp_sess['network_import_check'] == 'true' %} + bgp network import-check +{% endif %} +{# -------globals end --------------------------- #} +{# -------peer-group --------------------------- #} +{% if BGP_PEER_GROUP is defined and BGP_PEER_GROUP|length > 0 %} +{% for peer_group, nbr_or_peer in BGP_PEER_GROUP.iteritems() %} +{% if vrf == peer_group[0] %} +{% set name_or_ip = peer_group[1] %} +{% set nbr_or_peer_type = 'peer-group' %} +{% include "bgpd.conf.db.nbr_or_peer.j2" %} +{% endif %} +{% endfor %} +{% endif %} +{# -------peer-group end --------------------------- #} +{# -------neighbor --------------------------- #} +{% if BGP_NEIGHBOR is defined and BGP_NEIGHBOR|length > 0 %} +{% for nbr_addr, nbr_or_peer in BGP_NEIGHBOR.iteritems() %} +{% if nbr_addr is not string and nbr_addr|length > 1 %} +{% if vrf == nbr_addr[0] %} +{% set name_or_ip = nbr_addr[1] %} +{% set nbr_or_peer_type = 'neighbor' %} +{% include "bgpd.conf.db.nbr_or_peer.j2" %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# -------neighbor end --------------------------- #} +{% if bgp_sess.has_key('max_dynamic_neighbors') %} + bgp listen limit {{bgp_sess['max_dynamic_neighbors']}} +{% endif %} +{% if bgp_sess.has_key('route_map_process_delay') %} + bgp route-map delay-timer {{bgp_sess['route_map_process_delay']}} +{% endif %} +{# -------listen-prefix --------------------------- #} +{% if BGP_GLOBALS_LISTEN_PREFIX is defined and BGP_GLOBALS_LISTEN_PREFIX|length > 0 %} +{% for lpfx, lpfx_val in BGP_GLOBALS_LISTEN_PREFIX.items() %} +{% if vrf == lpfx[0] %} +{% if lpfx_val.has_key('peer_group') %} + bgp listen range {{lpfx[1]}} peer-group {{lpfx_val['peer_group']}} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# -------listen-prefix end --------------------------- #} +{# -------address-family --------------------------- #} +{% include "bgpd.conf.db.addr_family.j2" %} +{# -------address-family --------------------------- #} +{% endif %} +{% endfor %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 new file mode 100644 index 000000000000..41d309e4ef3e --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 @@ -0,0 +1,150 @@ +{# ------------------------------------------------------------ #} +{# this is called with the "vrf" and "address-family matched #} +{# ------------------------------------------------------------ #} +{% if n_af_val.has_key('admin_status') %} +{% if n_af_val['admin_status'] == 'true' %} + neighbor {{nbr_name}} activate +{% else %} + no neighbor {{nbr_name}} activate +{% endif %} +{% endif %} +{% if n_af_val.has_key('tx_add_paths') %} +{% if n_af_val['tx_add_paths'] == 'tx_all_paths' %} + neighbor {{nbr_name}} addpath-tx-all-paths +{% elif n_af_val['tx_add_paths'] == 'tx_best_path_per_as' %} + neighbor {{nbr_name}} addpath-tx-bestpath-per-AS +{% endif %} +{% endif %} +{% if n_af_val.has_key('nhself') and n_af_val['nhself'] == 'true' %} +{% if n_af_val.has_key('nexthop_self_force') and n_af_val['nexthop_self_force'] == 'true' %} + neighbor {{nbr_name}} next-hop-self force +{% else %} + neighbor {{nbr_name}} next-hop-self +{% endif %} +{% endif %} +{% if n_af_val.has_key('remove_private_as_enabled') and n_af_val['remove_private_as_enabled'] == 'true' %} +{% set ns = namespace(rpas_str='') %} +{% if n_af_val.has_key('remove_private_as_all') and n_af_val['remove_private_as_all'] == 'true' %} +{% set ns.rpas_str = ns.rpas_str + ' all' %} +{% endif %} +{% if n_af_val.has_key('replace_private_as') and n_af_val['replace_private_as'] == 'true' %} +{% set ns.rpas_str = ns.rpas_str + ' replace-AS' %} +{% endif %} + neighbor {{nbr_name}} remove-private-AS{{ns.rpas_str}} +{% endif %} +{% if n_af_val.has_key('send_community') %} +{% if n_af_val['send_community'] == 'standard' %} + no neighbor {{nbr_name}} send-community extended + no neighbor {{nbr_name}} send-community large +{% elif n_af_val['send_community'] == 'extended' %} + no neighbor {{nbr_name}} send-community + no neighbor {{nbr_name}} send-community large +{% elif n_af_val['send_community'] == 'large' %} + no neighbor {{nbr_name}} send-community + no neighbor {{nbr_name}} send-community extended +{% elif n_af_val['send_community'] == 'both' %} + no neighbor {{nbr_name}} send-community large +{% elif n_af_val['send_community'] == 'none' %} + no neighbor {{nbr_name}} send-community all +{% endif %} +{% endif %} +{% if n_af_val.has_key('as_override') and n_af_val['as_override'] == 'true' %} + neighbor {{nbr_name}} as-override +{% endif %} +{% if n_af_val.has_key('send_default_route') and n_af_val['send_default_route'] == 'true' %} +{% if n_af_val.has_key('default_rmap') %} + neighbor {{nbr_name}} default-originate route-map {{n_af_val['default_rmap']}} +{% else %} + neighbor {{nbr_name}} default-originate +{% endif %} +{% endif %} +{% if n_af_val.has_key('rrclient') and n_af_val['rrclient'] == 'true' %} + neighbor {{nbr_name}} route-reflector-client +{% endif %} +{% if n_af_val.has_key('soft_reconfiguration_in') and n_af_val['soft_reconfiguration_in'] == 'true' %} + neighbor {{nbr_name}} soft-reconfiguration inbound +{% endif %} +{# ------- maximum-prefix --------------------------- #} +{% if n_af_val.has_key('max_prefix_limit') %} +{% set ns = namespace(mpfx_str='maximum-prefix ' + n_af_val['max_prefix_limit']) %} +{% if n_af_val.has_key('max_prefix_warning_threshold') %} +{% set ns.mpfx_str = ns.mpfx_str + ' ' + n_af_val['max_prefix_warning_threshold'] %} +{% endif %} +{% if n_af_val.has_key('max_prefix_restart_interval') %} +{% set ns.mpfx_str = ns.mpfx_str + ' restart ' + n_af_val['max_prefix_restart_interval'] %} +{% elif n_af_val.has_key('max_prefix_warning_only') and n_af_val['max_prefix_warning_only'] == 'true' %} +{% set ns.mpfx_str = ns.mpfx_str + ' warning-only' %} +{% endif %} + neighbor {{nbr_name}} {{ns.mpfx_str}} +{% endif %} +{# ------- maximum-prefix end --------------------------- #} +{% if n_af_val.has_key('route_server_client') and n_af_val['route_server_client'] == 'true' %} + neighbor {{nbr_name}} route-server-client +{% endif %} +{# ------- allow-as --------------------------- #} +{% if n_af_val.has_key('allow_as_in') and n_af_val['allow_as_in'] == 'true' %} +{% if n_af_val.has_key('allow_as_origin') and n_af_val['allow_as_origin'] == 'true' %} + neighbor {{nbr_name}} allowas-in origin +{% elif n_af_val.has_key('allow_as_count') %} + neighbor {{nbr_name}} allowas-in {{n_af_val['allow_as_count']}} +{% else %} + neighbor {{nbr_name}} allowas-in +{% endif %} +{% endif %} +{# ------- allow-as end --------------------------- #} +{% if n_af_val.has_key('add_path_tx_all') and n_af_val['add_path_tx_all'] == 'true' %} + neighbor {{nbr_name}} addpath-tx-all-paths +{% endif %} +{% if n_af_val.has_key('add_path_tx_bestpath') and n_af_val['add_path_tx_bestpath'] == 'true' %} + neighbor {{nbr_name}} addpath-tx-bestpath-per-AS +{% endif %} +{% if n_af_val.has_key('cap_orf') %} + neighbor {{nbr_name}} capability orf prefix-list {{n_af_val['cap_orf']}} +{% endif %} +{% if n_af_val.has_key('weight') %} + neighbor {{nbr_name}} weight {{n_af_val['weight']}} +{% endif %} +{% if n_af_val.has_key('prefix_list_in') %} + neighbor {{nbr_name}} prefix-list {{n_af_val['prefix_list_in']}} in +{% endif %} +{% if n_af_val.has_key('prefix_list_out') %} + neighbor {{nbr_name}} prefix-list {{n_af_val['prefix_list_out']}} out +{% endif %} +{# ------- route-map in --------------------------- #} +{% if n_af_val.has_key('route_map_in') %} +{% for map in n_af_val['route_map_in'] %} + neighbor {{nbr_name}} route-map {{map}} in +{% endfor %} +{% endif %} +{# ------- route-map in end --------------------------- #} +{# ------- route-map out --------------------------- #} +{% if n_af_val.has_key('route_map_out') %} +{% for map in n_af_val['route_map_out'] %} + neighbor {{nbr_name}} route-map {{map}} out +{% endfor %} +{% endif %} +{# ------- route-map out end --------------------------- #} +{% if n_af_val.has_key('unsuppress_map_name') %} + neighbor {{nbr_name}} unsuppress-map {{n_af_val['unsuppress_map_name']}} +{% endif %} +{% if n_af_val.has_key('filter_list_in') %} + neighbor {{nbr_name}} filter-list {{n_af_val['filter_list_in']}} in +{% endif %} +{% if n_af_val.has_key('filter_list_out') %} + neighbor {{nbr_name}} filter-list {{n_af_val['filter_list_out']}} out +{% endif %} +{# ------- attribute-unchanged --------------------------- #} +{% set attr = '' %} +{% if n_af_val.has_key('unchanged_as_path') and n_af_val['unchanged_as_path'] == 'true' %} +{% set attr = 'as-path ' %} +{% endif %} +{% if n_af_val.has_key('unchanged_med') and n_af_val['unchanged_med'] == 'true' %} +{% set attr = attr + 'med ' %} +{% endif %} +{% if n_af_val.has_key('unchanged_nexthop') and n_af_val['unchanged_nexthop'] == 'true' %} +{% set attr = attr + 'next-hop' %} +{% endif %} +{% if attr != '' %} + neighbor {{nbr_name}} attribute-unchanged {{attr}} +{% endif %} +{# ------- attribute-unchanged end --------------------------- #} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 new file mode 100644 index 000000000000..1ecf4fa04135 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 @@ -0,0 +1,103 @@ +{# ------------------------------------------------------------- #} +{# this is called with the "vrf" matched #} +{# nbr_or_peer contains the information for the neighbor or peer #} +{# name_or_ip will be the IP or the name of the neighbor or peer #} +{# ------------------------------------------------------------- #} +{% set ns_intf = namespace(intf_arg = '') %} +{% if nbr_or_peer_type == 'peer-group' %} + neighbor {{name_or_ip}} peer-group +{% else %} +{% if not (name_or_ip | ipv4 or name_or_ip | ipv6) %} +{% set ns_intf.intf_arg = 'interface ' %} +{% endif %} +{% endif %} +{% set remote_as = '' %} +{% if nbr_or_peer.has_key('asn') %} +{% set remote_as = nbr_or_peer['asn'] %} +{% endif %} +{% if nbr_or_peer.has_key('peer_type') %} +{% set remote_as = nbr_or_peer['peer_type'] %} +{% endif %} +{% if remote_as != '' %} + neighbor {{name_or_ip}} {{ns_intf.intf_arg}}remote-as {{remote_as}} +{% endif %} +{% if nbr_or_peer.has_key('peer_group_name') %} + neighbor {{name_or_ip}} {{ns_intf.intf_arg}}peer-group {{nbr_or_peer['peer_group_name']}} +{% endif %} +{% if nbr_or_peer.has_key('local_asn') %} + neighbor {{name_or_ip}} local-as {{nbr_or_peer['local_asn']}} +{% endif %} +{% if nbr_or_peer.has_key('name') %} + neighbor {{name_or_ip}} description {{nbr_or_peer['name']}} +{% endif %} +{% if nbr_or_peer.has_key('admin_status') and nbr_or_peer['admin_status'] == 'false' %} +{% if nbr_or_peer.has_key('shutdown_message') %} + neighbor {{name_or_ip}} shutdown message {{nbr_or_peer['shutdown_message']}} +{% else %} + neighbor {{name_or_ip}} shutdown +{% endif %} +{% endif %} +{% if nbr_or_peer.has_key('bfd') and nbr_or_peer['bfd'] == 'true' %} + neighbor {{name_or_ip}} bfd +{% endif %} +{% if nbr_or_peer.has_key('ttl_security_hops') %} + neighbor {{name_or_ip}} ttl-security hops {{nbr_or_peer['ttl_security_hops']}} +{% endif %} +{% if nbr_or_peer.has_key('auth_password') %} + neighbor {{name_or_ip}} password {{nbr_or_peer['auth_password']}} encrypted +{% endif %} +{% if nbr_or_peer.has_key('solo_peer') and nbr_or_peer['solo_peer'] == 'true' %} + neighbor {{name_or_ip}} solo +{% endif %} +{% if nbr_or_peer.has_key('peer_port') %} + neighbor {{name_or_ip}} port {{nbr_or_peer['peer_port']}} +{% endif %} +{% if nbr_or_peer.has_key('passive_mode') and nbr_or_peer['passive_mode'] == 'true' %} + neighbor {{name_or_ip}} passive +{% endif %} +{% set mhop = '' %} +{% if nbr_or_peer.has_key('ebgp_multihop') and nbr_or_peer['ebgp_multihop'] == 'true' %} +{% set mhop = 255 %} +{% endif %} +{% if nbr_or_peer.has_key('ebgp_multihop_ttl') %} +{% set mhop = nbr_or_peer['ebgp_multihop_ttl'] %} +{% endif %} +{% if mhop != '' %} + neighbor {{name_or_ip}} ebgp-multihop {{mhop}} +{% endif %} +{% if nbr_or_peer.has_key('disable_ebgp_connected_route_check') and nbr_or_peer['disable_ebgp_connected_route_check'] == 'true' %} + neighbor {{name_or_ip}} disable-connected-check +{% endif %} +{% if nbr_or_peer.has_key('enforce_first_as') and nbr_or_peer['enforce_first_as'] == 'true' %} + neighbor {{name_or_ip}} enforce-first-as +{% endif %} +{% if nbr_or_peer.has_key('local_addr') %} + neighbor {{name_or_ip}} update-source {{nbr_or_peer['local_addr']}} +{% endif %} +{% if nbr_or_peer.has_key('strict_capability_match') and nbr_or_peer['strict_capability_match'] == true %} + neighbor {{name_or_ip}} strict-capability-match {{nbr_or_peer['strict_capability_match']}} +{% endif %} +{% if nbr_or_peer.has_key('min_adv_interval') %} + neighbor {{name_or_ip}} advertisement-interval {{nbr_or_peer['min_adv_interval']}} +{% endif %} +{% if nbr_or_peer.has_key('keepalive') and nbr_or_peer.has_key('holdtime') %} + neighbor {{name_or_ip}} timers {{nbr_or_peer['keepalive']}} {{nbr_or_peer['holdtime']}} +{% endif %} +{% if nbr_or_peer.has_key('conn_retry') %} + neighbor {{name_or_ip}} timers connect {{nbr_or_peer['conn_retry']}} +{% endif %} +{% if nbr_or_peer.has_key('capability_dynamic') and nbr_or_peer['capability_dynamic'] == 'true' %} + neighbor {{name_or_ip}} capability dynamic +{% endif %} +{% if nbr_or_peer.has_key('capability_ext_nexthop') and nbr_or_peer['capability_ext_nexthop'] == 'true' %} + neighbor {{name_or_ip}} capability extended-nexthop +{% endif %} +{% if nbr_or_peer.has_key('dont_negotiate_capability') and nbr_or_peer['dont_negotiate_capability'] == 'true' %} + neighbor {{name_or_ip}} dont-capability-negotiate +{% endif %} +{% if nbr_or_peer.has_key('enforce_multihop') and nbr_or_peer['enforce_multihop'] == 'true' %} + neighbor {{name_or_ip}} enforce-multihop +{% endif %} +{% if nbr_or_peer.has_key('override_capability') and nbr_or_peer['override_capability'] == 'true' %} + neighbor {{name_or_ip}} override-capability +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 new file mode 100644 index 000000000000..b13cf6f6189a --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 @@ -0,0 +1,30 @@ +{# ------------------------------------------------------------------------------------ #} +{% if (PREFIX_SET is defined and PREFIX_SET|length > 0) and + (PREFIX is defined and PREFIX|length > 0) %} +{% set modes = ['IPv4', 'IPv6'] %} +{% set ip_str = {'IPv4':'ip', 'IPv6':'ipv6' } %} +{% for md in modes %} +! +{% for key, val in PREFIX_SET.items() %} +{% if val.has_key('mode') %} +{% for pf_key, pf_val in PREFIX.items() %} +{% if pf_key[0] == key and md == val['mode'] %} +{% if pf_key[2] == 'exact' %} +{{ip_str[md]}} prefix-list {{key}} permit {{pf_key[1]}} +{% else %} +{% set len = pf_key[1].split('/')[1] %} +{% set rb = pf_key[2].split('..')[0] %} +{% set re = pf_key[2].split('..')[1] %} +{% if rb > len %} +{{ip_str[md]}} prefix-list {{key}} permit {{pf_key[1]}} ge {{rb}} le {{re}} +{% else %} +{{ip_str[md]}} prefix-list {{key}} permit {{pf_key[1]}} le {{re}} +{% endif %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +{% endfor %} +{% endif %} +{# ------------------------------------------------------------------------------------ #} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 new file mode 100644 index 000000000000..a7a9cb1012e2 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 @@ -0,0 +1,150 @@ +{% if ROUTE_MAP is defined and ROUTE_MAP|length > 0 %} +{% for rm_key, rm_val in ROUTE_MAP.items() %} +{% if rm_val.has_key('route_operation') %} +! +route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} +{% if rm_val.has_key('match_as_path') %} + match as-path {{rm_val['match_as_path']}} +{% endif %} +{% if rm_val.has_key('call_route_map') %} + call {{rm_val['call_route_map']}} +{% endif %} +{% if rm_val.has_key('match_community') %} + match community {{rm_val['match_community']}} +{% endif %} +{% if rm_val.has_key('match_ext_community') %} + match extcommunity {{rm_val['match_ext_community']}} +{% endif %} +{% if rm_val.has_key('match_interface') %} + match interface {{rm_val['match_interface']}} +{% endif %} +{% if rm_val.has_key('match_tag') %} + match tag {{rm_val['match_tag'][0]}} +{% endif %} +{% if rm_val.has_key('match_src_vrf') %} + match source-vrf {{rm_val['match_src_vrf']}} +{% endif %} +{# ---------------match ip/ipv6-Start-------------------------- #} +{% set ip_str = {'ipv4':'ip', 'ipv6':'ipv6' } %} +{% if PREFIX_SET is defined and PREFIX_SET|length > 0 %} +{% if rm_val.has_key('match_prefix_set') %} +{% for pfx_key, pfx_val in PREFIX_SET.items() %} +{% if rm_val['match_prefix_set'] == pfx_key %} + match {{ip_str[pfx_val['mode']]}} address prefix-list {{rm_val['match_prefix_set']}} +{% endif %} +{% endfor %} +{% endif %} +{% if rm_val.has_key('match_next_hop_set') %} +{% for pfx_key, pfx_val in PREFIX_SET.items() %} +{% if rm_val['match_next_hop_set'] == pfx_key %} + match {{ip_str[pfx_val['mode']]}} next-hop prefix-list {{rm_val['match_next_hop_set']}} +{% endif %} +{% endfor %} +{% endif %} +{% endif %} +{# ---------------match ip/ipv6- End-------------------------- #} +{% if rm_val.has_key('match_local_pref') %} + match local-preference {{rm_val['match_local_pref']}} +{% endif %} +{% if rm_val.has_key('match_med') %} + match metric {{rm_val['match_med']}} +{% endif %} +{% if rm_val.has_key('match_origin') %} + match origin {{rm_val['match_origin']|lower}} +{% endif %} +{% if rm_val.has_key('match_neighbor') %} + match peer {{rm_val['match_neighbor'][0]}} +{% endif %} +{% if rm_val.has_key('match_protocol') %} + match source-protocol {{rm_val['match_protocol']}} +{% endif %} +{# ---------------set as-path prepend - Start ----------------- #} +{% if rm_val.has_key('set_asn') and rm_val.has_key('set_repeat_asn') %} +{% set ns = namespace(as_str='') %} +{% if rm_val['set_repeat_asn'] > 0 %} +{% for i in range(rm_val['set_repeat_asn']|int) %} +{% set ns.as_str = ns.as_str+' '+rm_val['set_asn'] %} +{% endfor %} +{% else %} +{% set ns.as_str = rm_val['set_asn'] %} +{% endif %} + set as-path prepend{{ns.as_str}} +{% endif %} +{# ---------------set as-path prepend - End ------------------- #} +{# ---------------set community - Start------------------------ #} +{% if rm_val.has_key('set_community_inline') %} +{% set ns = namespace(comms = '') %} +{% for cm in rm_val['set_community_inline'] %} +{% set ns.comms = ns.comms + ' ' + cm %} +{% endfor %} + set community{{ns.comms}} +{% endif %} +{# ---------------set community - End-------------------------- #} +{% if rm_val.has_key('set_community_ref') %} + set community {{rm_val['set_community_ref']}} +{% endif %} +{# ---------------set extcommunity - Start--------------------- #} +{% if rm_val.has_key('set_ext_community_inline') %} +{% set ec_ns = namespace(rt_str='', soo_str='') %} +{% for ext_comm in rm_val['set_ext_community_inline'] %} +{% set comm = ext_comm.split(':') %} +{% if comm[0] == 'route-target' %} +{% set ec_ns.rt_str = ec_ns.rt_str+' '+comm[1]+':'+comm[2] %} +{% endif %} +{% if comm[0] == 'route-origin' %} +{% set ec_ns.soo_str = ec_ns.soo_str+' '+comm[1]+':'+comm[2] %} +{% endif %} +{% endfor %} +{% if ec_ns.rt_str != '' %} + set extcommunity rt{{ec_ns.rt_str}} +{% endif %} +{% if ec_ns.soo_str != '' %} + set extcommunity soo{{ec_ns.rt_str}} +{% endif %} +{% endif %} +{# ---------------set extcommunity - End----------------------- #} +{% if rm_val.has_key('set_ext_community_ref') %} + set extcommunity {{rm_val['set_ext_community_ref']}} +{% endif %} +{% if rm_val.has_key('set_next_hop') %} + set ip next-hop {{rm_val['set_next_hop']}} +{% endif %} +{% if rm_val.has_key('set_ipv6_next_hop_global') %} + set ipv6 next-hop global {{rm_val['set_ipv6_next_hop_global']}} +{% endif %} +{% if rm_val.has_key('set_ipv6_next_hop_prefer_global') and rm_val['set_ipv6_next_hop_prefer_global'] == 'true' %} + set ipv6 next-hop prefer-global +{% endif %} +{% if rm_val.has_key('set_local_preference') %} + set local-preference {{rm_val['set_local_preference']}} +{% endif %} +{# ---------------set metric and med - Start--------------------- #} +{% if rm_val.has_key('set_metric_action') %} +{% if rm_val.has_key('set_metric') %} +{% if rm_val['set_metric_action'] == 'METRIC_SET_VALUE' %} + set metric {{rm_val['set_metric']}} +{% elif rm_val['set_metric_action'] == 'METRIC_ADD_VALUE' %} + set metric +{{rm_val['set_metric']}} +{% elif rm_val['set_metric_action'] == 'METRIC_SUBTRACT_VALUE' %} + set metric -{{rm_val['set_metric']}} +{% endif %} +{% endif %} +{% if rm_val['set_metric_action'] == 'METRIC_SET_RTT' %} + set metric rtt +{% elif rm_val['set_metric_action'] == 'METRIC_ADD_RTT' %} + set metric +rtt +{% elif rm_val['set_metric_action'] == 'METRIC_SUBTRACT_RTT' %} + set metric -rtt +{% endif %} +{% elif rm_val.has_key('set_med') %} + set metric {{rm_val['set_med']}} +{% elif rm_val.has_key('set_metric') %} + set metric {{rm_val['set_metric']}} +{% endif %} +{# ---------------set metric and med - End--------------------- #} +{% if rm_val.has_key('set_origin') %} + set origin {{rm_val['set_origin']|lower}} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 index 85182e5430e8..13f2ce655115 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 @@ -18,7 +18,11 @@ agentx {% include "bgpd.spine_chassis_frontend_router.conf.j2" %} {% endif %} ! +{% if DEVICE_METADATA['localhost'].has_key('bgp_template_config') and DEVICE_METADATA['localhost']['bgp_template_config'] == 'false' %} +{% include "bgpd.conf.db.j2" %} +{% else %} {% include "bgpd.main.conf.j2" %} +{% endif %} ! ! end of template: bgpd/bgpd.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 new file mode 100644 index 000000000000..c3dc50449d35 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 @@ -0,0 +1,38 @@ +{% block bgp_peer %} + neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} +{# set the bgp neighbor timers if they have not default values #} +{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) + or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} + neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} +{% endif %} +{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} + neighbor {{ neighbor_addr }} shutdown +{% endif %} +{% if neighbor_addr | ipv4 %} + address-family ipv4 + neighbor {{ neighbor_addr }} peer-group PEER_V4 +{% elif neighbor_addr | ipv6 %} + address-family ipv6 +{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %} + neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in +{% endif %} + neighbor {{ neighbor_addr }} peer-group PEER_V6 +{% endif %} +{% if bgp_session['rrclient'] | int != 0 %} + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} +{% if bgp_session['nhopself'] | int != 0 %} + neighbor {{ neighbor_addr }} next-hop-self +{% endif %} +{% if bgp_session["asn"] == DEVICE_METADATA['localhost']['bgp_asn'] + and DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" + and (not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets) %} + address-family l2vpn evpn + neighbor {{ neighbor_addr }} activate + advertise-all-vni + exit-address-family +{% endif %} + neighbor {{ neighbor_addr }} activate + exit-address-family +{% endblock bgp_peer %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 new file mode 100644 index 000000000000..11c1c0b5ca96 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 @@ -0,0 +1,37 @@ +{% set areaid = areakey[1] %} +{% if area_instance.has_key('authentication') %} +{% if area_instance['authentication'] == "MD5HMAC" %} + area {{ areaid }} authentication message-digest +{% else %} + area {{ areaid }} authentication +{% endif %} +{% endif %} +{% if area_instance.has_key('stub-no-summary') %} +{% if area_instance['stub-no-summary'] == 'true' %} + area {{ areaid }} stub no-summary +{% endif %} +{% else %} +{% if area_instance.has_key('stub') %} +{% if area_instance['stub'] == 'true' %} + area {{ areaid }} stub +{% endif %} +{% endif %} +{% endif %} +{% if area_instance.has_key('stub-default-cost') %} + area {{ areaid }} default-cost {{ area_instance['stub-default-cost'] }} +{% endif %} +{% if area_instance.has_key('import-list') %} + area {{ areaid }} import-list {{ area_instance['import-list'] }} +{% endif %} +{% if area_instance.has_key('export-list') %} + area {{ areaid }} export-list {{ area_instance['export-list'] }} +{% endif %} +{% if area_instance.has_key('filter-list-in') %} + area {{ areaid }} filter-list prefix {{ area_instance['filter-list-in'] }} in +{% endif %} +{% if area_instance.has_key('filter-list-out') %} + area {{ areaid }} filter-list prefix {{ area_instance['filter-list-out'] }} out +{% endif %} +{% if area_instance.has_key('shortcut') %} + area {{ areaid }} shortcut {{ (area_instance['shortcut']).lower() }} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 new file mode 100644 index 000000000000..61237e9a1506 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 @@ -0,0 +1,129 @@ +{# ------------------------------------------------------------------------------------ #} +{# ------------------------------------------------------------------------------------ #} +{% if OSPFV2_ROUTER is defined and OSPFV2_ROUTER|length > 0 %} +{% for vrf, ospf_instance in OSPFV2_ROUTER.items() %} +! +router ospf vrf {{ vrf }} +{% if ospf_instance.has_key('router-id') %} + ospf router-id {{ ospf_instance['router-id'] }} +{% endif %} +{% if ospf_instance.has_key('abr-type') %} + ospf abr-type {{ (ospf_instance['abr-type']).lower() }} +{% endif %} +{% if ospf_instance.has_key('auto-cost-reference-bandwidth') %} + auto-cost reference-bandwidth {{ (ospf_instance['auto-cost-reference-bandwidth']) }} +{% endif %} +{% if ospf_instance.has_key('log-adjacency-changes') %} +{% if ospf_instance['log-adjacency-changes'] == 'DETAIL' %} + log-adjacency-changes detail +{% else %} + log-adjacency-changes +{% endif %} +{% endif %} +{% if ospf_instance.has_key('default-metric') %} + default-metric {{ ospf_instance['default-metric'] }} +{% endif %} +{% if ospf_instance.has_key('ospf-rfc1583-compatible') %} +{% if ospf_instance['ospf-rfc1583-compatible'] == 'true' %} + compatible rfc1583 +{% endif %} +{% endif %} +{% if ospf_instance.has_key('passive-interface-default') %} + passive-interface default +{% endif %} +{% if ospf_instance.has_key('write-multiplier') %} + write-multiplier {{ ospf_instance['write-multiplier'] }} +{% endif %} +{% if ospf_instance.has_key('spf-throttle-delay') and ospf_instance.has_key('spf-initial-delay') and ospf_instance.has_key('spf-maximum-delay') %} + timers throttle spf {{ ospf_instance['spf-throttle-delay'] }} {{ ospf_instance['spf-initial-delay'] }} {{ ospf_instance['spf-maximum-delay'] }} +{% endif %} +{% if ospf_instance.has_key('lsa-min-interval-timer') %} + timers throttle lsa all {{ ospf_instance['lsa-min-interval-timer'] }} +{% endif %} +{% if ospf_instance.has_key('lsa-min-arrival-timer') %} + timers lsa min-arrival {{ ospf_instance['lsa-min-arrival-timer'] }} +{% endif %} +{% if ospf_instance.has_key('lsa-refresh-timer') %} + refresh timer {{ ospf_instance['lsa-refresh-timer'] }} +{% endif %} +{% if ospf_instance.has_key('max-metric-administrative') %} +{% if ospf_instance['max-metric-administrative'] == 'true' %} + max-metric router-lsa administrative +{% endif %} +{% endif %} +{% if ospf_instance.has_key('max-metric-on-startup') %} + max-metric router-lsa on-startup {{ ospf_instance['max-metric-on-startup'] }} +{% endif %} +{% if ospf_instance.has_key('max-metric-on-shutdown') %} + max-metric router-lsa on-shutdown {{ ospf_instance['max-metric-on-shutdown'] }} +{% endif %} +{% if ospf_instance.has_key('distance-all') %} + distance {{ ospf_instance['distance-all'] }} +{% endif %} +{% if ospf_instance.has_key('distance-inter-area') or ospf_instance.has_key('distance-intra-area') or ospf_instance.has_key('distance-external')%} +{% set distance_cmd = '' %} +{% set distance_cmd = 'distance ospf' %} +{% if ospf_instance.has_key('distance-intra-area') %} +{% set distance_cmd = distance_cmd + ' intra-area ' + ospf_instance['distance-intra-area'] %} +{% endif %} +{% if ospf_instance.has_key('distance-inter-area') %} +{% set distance_cmd = distance_cmd + ' inter-area ' + ospf_instance['distance-inter-area'] %} +{% endif %} +{% if ospf_instance.has_key('distance-external') %} +{% set distance_cmd = distance_cmd + ' external ' + ospf_instance['distance-external'] %} +{% endif %} + {{ distance_cmd }} +{% endif %} +{# -------OSPFV2_ROUTER end --------------------------- #} +{# -------OSPFV2_ROUTER_AREA Begin --------------------------- #} +{% if OSPFV2_ROUTER_AREA is defined and OSPFV2_ROUTER_AREA|length > 0 %} +{% for areakey, area_instance in OSPFV2_ROUTER_AREA.items() %} +{% include "ospfd.conf.db.area.j2" %} +{% endfor %} +{% endif %} +{# -------OSPFV2_ROUTER_AREA end --------------------------- #} +{# -------OSPFV2_ROUTER_AREA_NETWORK Begin --------------------------- #} +{% if OSPFV2_ROUTER_AREA_NETWORK is defined and OSPFV2_ROUTER_AREA_NETWORK|length > 0 %} +{% for networkkey, ospf_network_instance in OSPFV2_ROUTER_AREA_NETWORK.items() %} +{% set networkareaid = networkkey[1] %} +{% set networkid = networkkey[2] %} + network {{ networkid }} area {{ networkareaid }} +{% endfor %} +{% endif %} +{# -------OSPFV2_ROUTER_AREA_NETWORK end --------------------------- #} +{# -------OSPFV2_ROUTER_AREA_VIRTUAL_LINK Begin --------------------------- #} +{% if OSPFV2_ROUTER_AREA_VIRTUAL_LINK is defined and OSPFV2_ROUTER_AREA_VIRTUAL_LINK|length > 0 %} +{% for vlinkkey, vlink_instance in OSPFV2_ROUTER_AREA_VIRTUAL_LINK.items() %} +{% include "ospfd.conf.db.vlink.j2" %} +{% endfor %} +{% endif %} +{# -------OSPFV2_ROUTER_AREA_VIRTUAL_LINK end --------------------------- #} +{# -------OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE Begin --------------------------- #} +{% if OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE is defined and OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE|length > 0 %} +{% for rangekey, area_range_instance in OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE.items() %} +{% include "ospfd.conf.db.policyrange.j2" %} +{% endfor %} +{% endif %} +{# -------OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE end --------------------------- #} +{# -------OSPFV2_ROUTER_DISTRIBUTE_ROUTE Begin --------------------------- #} +{% if OSPFV2_ROUTER_DISTRIBUTE_ROUTE is defined and OSPFV2_ROUTER_DISTRIBUTE_ROUTE|length > 0 %} +{% for routekey, route_instance in OSPFV2_ROUTER_DISTRIBUTE_ROUTE.items() %} +{% include "ospfd.conf.db.distributeroute.j2" %} +{% endfor %} +{% endif %} +{# -------OSPFV2_ROUTER_DISTRIBUTE_ROUTE end --------------------------- #} +{# -------OSPFV2_ROUTER_PASSIVE_INTERFACE Begin --------------------------- #} +{% if OSPFV2_ROUTER_PASSIVE_INTERFACE is defined and OSPFV2_ROUTER_PASSIVE_INTERFACE|length > 0 %} +{% for passintfkey, passintf_instance in OSPFV2_ROUTER_PASSIVE_INTERFACE.items() %} +{% set passintfname = passintfkey[1] %} +{% set passintfaddr = passintfkey[2] %} +{% if passintfaddr == '0.0.0.0' %} + passive-interface {{ passintfname }} +{% else %} + passive-interface {{ passintfname }} {{ passintfaddr }} +{% endif %} +{% endfor %} +{% endif %} +{# -------OSPFV2_ROUTER_PASSIVE_INTERFACE end --------------------------- #} +{% endfor %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 new file mode 100644 index 000000000000..49c58f35859a --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 @@ -0,0 +1,52 @@ +{% set routeproto = routekey[1] %} +{% set routedirection = routekey[2] %} +{% set generic_protocols = [ "BGP", "KERNEL", "STATIC", "DIRECTLY_CONNECTED"] %} +{% if routeproto == "DEFAULT_ROUTE" and routedirection == "IMPORT" %} +{% set defaultinfo_cmd = '' %} +{% set defaultinfo_cmd = 'default-information originate' %} +{% if route_instance.has_key('always') %} +{% if route_instance['always'] == 'true' %} +{% set defaultinfo_cmd = defaultinfo_cmd + ' always' %} +{% endif %} +{% endif %} +{% if route_instance.has_key('metric') %} +{% set defaultinfo_cmd = defaultinfo_cmd + ' metric ' + route_instance['metric'] %} +{% endif %} +{% if route_instance.has_key('metric-type') %} +{% if route_instance['metric-type'] == "TYPE_1"%} +{% set defaultinfo_cmd = defaultinfo_cmd + ' metric-type ' + '1' %} +{% endif %} +{% endif %} +{% if route_instance.has_key('route-map') %} +{% set defaultinfo_cmd = defaultinfo_cmd + ' route-map ' + route_instance['route-map'] %} +{% endif %} + {{ defaultinfo_cmd }} +{% elif routedirection == "IMPORT" and routeproto in generic_protocols %} +{% set redistribute_cmd = '' %} +{% if routeproto == "DIRECTLY_CONNECTED" %} +{% set redistribute_cmd = 'redistribute ' + 'connected' %} +{% else %} +{% set redistribute_cmd = 'redistribute ' + routeproto.lower() %} +{% endif %} +{% if route_instance.has_key('metric') %} +{% set redistribute_cmd = redistribute_cmd + ' metric ' + route_instance['metric'] %} +{% endif %} +{% if route_instance.has_key('metric-type') %} +{% if route_instance['metric-type'] == "TYPE_1"%} +{% set redistribute_cmd = redistribute_cmd + ' metric-type ' + '1' %} +{% endif %} +{% endif %} +{% if route_instance.has_key('route-map') %} +{% set redistribute_cmd = redistribute_cmd + ' route-map ' + route_instance['route-map'] %} +{% endif %} + {{ redistribute_cmd }} +{% elif routedirection == "EXPORT" and routeproto in generic_protocols %} +{% if route_instance.has_key('route-map') %} +{% if routeproto == "DIRECTLY_CONNECTED" %} + distribute-list {{ route_instance['route-map'] }} out connected +{% else %} + distribute-list {{ route_instance['route-map'] }} out {{ routeproto.lower() }} +{% endif %} +{% endif %} +{% endif %} + diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 new file mode 100644 index 000000000000..b8c86b2bb834 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 @@ -0,0 +1,76 @@ +{# ------------------------------------------------------------------------------------ #} +{# ------------------------------------------------------------------------------------ #} +{% if OSPFV2_INTERFACE is defined and OSPFV2_INTERFACE|length > 0 %} +{% for (intfkey, ospf_intf_instance) in OSPFV2_INTERFACE.iteritems() %} +! +{% set intfname = intfkey[0] %} +{% set intfaddr = intfkey[1] %} +{% if intfaddr == "0.0.0.0" %} +{% set intfaddr = "" %} +{% endif %} +interface {{ intfname }} +{% if ospf_intf_instance.has_key('area-id') %} + ip ospf area {{ ospf_intf_instance['area-id'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('network-type') %} +{% if ospf_intf_instance['network-type'] == 'BROADCAST_NETWORK' %} + ip ospf network broadcast {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance['network-type'] == 'POINT_TO_POINT_NETWORK' %} + ip ospf network point-to-point {{ intfaddr }} +{% endif %} +{% endif %} +{% if ospf_intf_instance.has_key('metric') %} + ip ospf cost {{ ospf_intf_instance['metric'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('priority') %} + ip ospf priority {{ ospf_intf_instance['priority'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('mtu-ignore') %} +{% if ospf_intf_instance['mtu-ignore'] == 'true' %} + ip ospf mtu-ignore {{ intfaddr }} +{% endif %} +{% endif %} +{% if ospf_intf_instance.has_key('bfd-enable') %} +{% if ospf_intf_instance['bfd-enable'] == 'true' %} + ip ospf bfd +{% endif %} +{% endif %} +{% if ospf_intf_instance.has_key('authentication-type') %} +{% if ospf_intf_instance['authentication-type'] == 'MD5HMAC' %} + ip ospf authentication message-digest {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance['authentication-type'] == 'NONE' %} + ip ospf authentication null {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance['authentication-type'] == 'TEXT' %} + ip ospf authentication {{ intfaddr }} +{% endif %} +{% endif %} +{% if ospf_intf_instance.has_key('authentication-key') %} + ip ospf authentication-key {{ ospf_intf_instance['authentication-key'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('authentication-key-id') and ospf_intf_instance.has_key('authentication-md5-key') %} + ip ospf message-digest-key {{ ospf_intf_instance['authentication-key-id'] }} md5 {{ ospf_intf_instance['authentication-md5-key'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('dead-interval') %} + ip ospf dead-interval {{ ospf_intf_instance['dead-interval'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('dead-interval-minimal') %} +{% if ospf_intf_instance.has_key('hello-multiplier') %} + ip ospf dead-interval minimal hello-multiplier {{ ospf_intf_instance['hello-multiplier'] }} {{ intfaddr }} +{% else %} + ip ospf dead-interval minimal {{ intfaddr }} +{% endif %} +{% endif %} +{% if ospf_intf_instance.has_key('hello-interval') %} + ip ospf hello-interval {{ ospf_intf_instance['hello-interval'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('retransmission-interval') %} + ip ospf retransmit-interval {{ ospf_intf_instance['retransmission-interval'] }} {{ intfaddr }} +{% endif %} +{% if ospf_intf_instance.has_key('transmit-delay') %} + ip ospf transmit-delay {{ ospf_intf_instance['transmit-delay'] }} {{ intfaddr }} +{% endif %} +{% endfor %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 new file mode 100644 index 000000000000..6f1ef89cc3bf --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 @@ -0,0 +1,16 @@ +{% set rangeareaid = rangekey[1] %} +{% set rangeid = rangekey[2] %} + area {{ rangeareaid }} range {{ rangeid }} +{% if area_range_instance.has_key('advertise') %} +{% if area_range_instance['advertise'] == 'true' %} + area {{ rangeareaid }} range {{ rangeid }} advertise +{% else %} + area {{ rangeareaid }} range {{ rangeid }} not-advertise +{% endif %} +{% endif %} +{% if area_range_instance.has_key('metric') %} + area {{ rangeareaid }} range {{ rangeid }} advertise cost {{ area_range_instance['metric'] }} +{% endif %} +{% if area_range_instance.has_key('substitue-prefix') %} + area {{ rangeareaid }} range {{ rangeid }} substitute {{ area_range_instance['substitue-prefix'] }} +{% endif %} \ No newline at end of file diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 new file mode 100644 index 000000000000..e8af99abe299 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 @@ -0,0 +1,29 @@ +{% set vlinkareaid = vlinkkey[1] %} +{% set vlinkid = vlinkkey[2] %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} +{% if vlink_instance.has_key('authentication') %} +{% if vlink_instance['authentication'] == 'MD5HMAC' %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} authentication message-digest +{% else %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} null +{% endif %} +{% endif %} +{% if vlink_instance.has_key('authentication-key') %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} authentication-key {{ vlink_instance['authentication-key'] }} +{% endif %} +{% if vlink_instance.has_key('authentication-key-id') and vlink_instance.has_key('authentication-md5-key') %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} authentication message-digest message-digest-key {{ vlink_instance['authentication-key-id'] }} md5 {{ vlink_instance['authentication-md5-key'] }} +{% endif %} +{% if vlink_instance.has_key('dead-interval') %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} dead-interval {{ vlink_instance['dead-interval'] }} +{% endif %} +{% if vlink_instance.has_key('hello-interval') %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} hello-interval {{ vlink_instance['hello-interval'] }} +{% endif %} +{% if vlink_instance.has_key('retransmission-interval') %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} retransmit-interval {{ vlink_instance['retransmission-interval'] }} +{% endif %} +{% if vlink_instance.has_key('transmit-delay') %} + area {{ vlinkareaid }} virtual-link {{ vlinkid }} transmit-delay {{ vlink_instance['transmit-delay'] }} +{% endif %} + diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 index 932871dfce4b..9509ba61d21c 100644 --- a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 @@ -10,3 +10,5 @@ ! {% include "staticd.default_route.conf.j2" %} ! +{% include "staticd.db.conf.j2" %} +! diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 new file mode 100644 index 000000000000..58ee06bc8592 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 @@ -0,0 +1,149 @@ +{% macro iproute(ip_prefix, nh_blackhole, nh_ip, nh_intf, nh_dist, nh_tag, nh_vrf) %} + {%- set ns = namespace(str = None) %} + {%- set ip_addr = ip_prefix.split('/')[0] %} + {%- if ip_addr|ipv4 %} + {%- set ns.str = 'ip route' %} + {%- else %} + {%- set ns.str = 'ipv6 route' %} + {%- endif %} + {%- if nh_blackhole %} + {#- ------------------------------ blackhole route ------------------------------ #} + {%- for item in [ip_prefix, 'blackhole', nh_tag, nh_dist] %} + {%- if item != None %} + {%- set ns.str = ns.str + ' ' + item %} + {%- endif %} + {%- endfor %} + {%- else %} + {#- ------------------------------ non-blackhole route ------------------------------ #} + {%- for item in [ip_prefix, nh_ip, nh_intf, nh_tag, nh_dist, nh_vrf] %} + {%- if item != None %} + {%- set ns.str = ns.str + ' ' + item %} + {%- endif %} + {%- endfor %} + {%- endif %} +{{ ns.str }} +{%- endmacro %} +{% if STATIC_ROUTE is defined and STATIC_ROUTE|length > 0 %} + {%- set vrf_rt_list = {} %} + {%- for key, val in STATIC_ROUTE.items() %} + {#- ------------------------------ for each route - start ------------------------------ #} + {%- set rt = namespace(vrf = 'default', ip_prefix = '', nh_num = 0, nh_list = [], valid = True) %} + {%- if key is not string and key|length > 1 %} + {%- set rt.vrf = key[0] %} + {%- set rt.ip_prefix = key[1] %} + {%- else %} + {%- set rt.ip_prefix = key %} + {%- endif %} + {%- set nh_attr = {} %} + {#- ------------------------------ get nh count - start ------------------------------ #} + {%- for fld_key, fld_val in val.items() if rt.valid %} + {%- set attr_list = fld_val.split(',') %} + {%- if rt.nh_num == 0 %} + {%- set rt.nh_num = attr_list|length %} + {%- else %} + {%- if rt.nh_num != attr_list|length %} + {%- set rt.valid = False %} + {%- endif %} + {%- endif %} + {%- if nh_attr.update({fld_key: attr_list}) %} + {%- endif %} + {%- endfor %} + {#- ------------------------------ get nh count - end ------------------------------ #} + {%- if rt.valid %} + {%- for nh_idx in range(rt.nh_num) %} + {#- ------------------------------ parse nh - start ------------------------------ #} + {%- set nh = namespace(blackhole = False, ip = None, intf = None, dist = None, tag = None, vrf = None) %} + {#- ------------------------------ nexthop blackhole ------------------------------ #} + {%- if nh_attr.has_key('blackhole') %} + {%- set nh.blackhole = nh_attr['blackhole'][nh_idx] %} + {%- if nh.blackhole == 'true' %} + {%- set nh.blackhole = True %} + {%- else %} + {%- set nh.blackhole = False %} + {%- endif %} + {%- endif %} + {#- ------------------------------ nexthop IP ------------------------------ #} + {%- if nh_attr.has_key('nexthop') %} + {%- set nh.ip = nh_attr['nexthop'][nh_idx] %} + {%- if nh.ip == '0.0.0.0' or nh.ip == '::' %} + {%- set nh.ip = None %} + {%- endif %} + {%- endif %} + {#- ------------------------------ nexthop interface ------------------------------ #} + {%- if nh_attr.has_key('ifname') %} + {%- set nh.intf = nh_attr['ifname'][nh_idx] %} + {%- if nh.intf == '' %} + {%- set nh.intf = None %} + {%- endif %} + {%- endif %} + {#- ------------------------------ nexthop distance ------------------------------ #} + {%- if nh_attr.has_key('distance') %} + {%- set nh.dist = nh_attr['distance'][nh_idx] %} + {%- if nh.dist == '0' %} + {%- set nh.dist = None %} + {%- endif %} + {%- endif %} + {#- ------------------------------ nexthop tag ------------------------------ #} + {%- if nh_attr.has_key('tag') %} + {%- set nh.tag = nh_attr['tag'][nh_idx] %} + {%- if nh.tag == '0' %} + {%- set nh.tag = None %} + {%- endif %} + {%- if nh.tag != None %} + {%- set nh.tag = 'tag ' + nh.tag %} + {%- endif %} + {%- endif %} + {#- ------------------------------ nexthop VRF ------------------------------ #} + {%- if nh_attr.has_key('nexthop-vrf') %} + {%- set nh.vrf = nh_attr['nexthop-vrf'][nh_idx] %} + {%- if nh.vrf == '' %} + {%- set nh.vrf = None %} + {%- endif %} + {%- if nh.vrf != None %} + {%- set nh.vrf = 'nexthop-vrf ' + nh.vrf %} + {%- endif %} + {%- endif %} + {#- ------------------------------ parse nh - end ------------------------------ #} + {%- if nh.blackhole or nh.ip != None or nh.intf != None %} + {%- if rt.nh_list.append(nh) %} + {%- endif %} + {%- endif %} + {%- endfor %} + {#- ------------------------------ for each route - end ------------------------------ #} + {%- if not vrf_rt_list.has_key(rt.vrf) %} + {%- if vrf_rt_list.update({rt.vrf: []}) %} + {%- endif %} + {%- endif %} + {%- if vrf_rt_list[rt.vrf].append(rt) %} + {%- endif %} + {%- endif %} + {%- endfor %} + +{# ------------------------------ dump route - start ------------------------------ #} +{# ------------------------------ default VRF ------------------------------ #} +{% for vrf, rt_list in vrf_rt_list.items() if vrf == 'default' %} +{% for rt in rt_list %} +{% if rt.valid %} +{% for nh in rt.nh_list %} +{{ iproute(rt.ip_prefix, nh.blackhole, nh.ip, nh.intf, nh.dist, nh.tag, nh.vrf) }} +{% endfor %} +{% endif %} +{% endfor %} +{% endfor %} +{# ------------------------------ non-default VRF ------------------------------ #} +{% for vrf, rt_list in vrf_rt_list.items() if vrf != 'default' %} +! +vrf {{ vrf }} +{% for rt in rt_list %} +{% if rt.valid %} +{% for nh in rt.nh_list %} + {{ iproute(rt.ip_prefix, nh.blackhole, nh.ip, nh.intf, nh.dist, nh.tag, nh.vrf) }} +{% endfor %} +{% endif %} +{% endfor %} + exit-vrf +! +{% endfor %} +{# ------------------------------ dump route - end ------------------------------ #} + +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 index e752b1ca05fb..afdc13400573 100644 --- a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 +++ b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 @@ -49,6 +49,18 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=zebra:running +[program:bfdd] +command=/usr/lib/frr/bfdd -A 127.0.0.1 +priority=4 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + [program:bgpd] command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp priority=5 @@ -61,6 +73,30 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=zebra:running +[program:ospfd] +command=/usr/lib/frr/ospfd -A 127.0.0.1 -M snmp +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:pimd] +command=/usr/lib/frr/pimd -A 127.0.0.1 +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + [program:fpmsyncd] command=fpmsyncd priority=6 @@ -73,7 +109,11 @@ dependent_startup=true dependent_startup_wait_for=bgpd:running [program:bgpcfgd] +{% if DEVICE_METADATA.localhost.bgp_template_config is defined and DEVICE_METADATA.localhost.bgp_template_config == "false" %} +command=/usr/local/bin/bgpcfgd_no_template +{% else %} command=/usr/local/bin/bgpcfgd +{% endif %} priority=6 autostart=false autorestart=false diff --git a/src/sonic-bgpcfgd/bgpcfgd_no_template b/src/sonic-bgpcfgd/bgpcfgd_no_template new file mode 100755 index 000000000000..37d684c723e0 --- /dev/null +++ b/src/sonic-bgpcfgd/bgpcfgd_no_template @@ -0,0 +1,3770 @@ +#!/usr/bin/env python + +import copy +import subprocess +import time +import syslog +import os +from swsssdk import ConfigDBConnector +import socket +import threading +import pty +import Queue +import signal +import re +import logging +import netaddr +import cStringIO +import struct + +class CachedDataWithOp: + OP_NONE = 0 + OP_ADD = 1 + OP_DELETE = 2 + OP_UPDATE = 3 + + STAT_SUCC = 0 + STAT_FAIL = 1 + + def __init__(self, data = None, op = OP_NONE): + self.data = data + self.op = op + self.status = self.STAT_FAIL + + def __repr__(self): + op_str = '' + if self.op == self.OP_NONE: + op_str = 'NONE' + elif self.op == self.OP_ADD: + op_str = 'ADD' + elif self.op == self.OP_DELETE: + op_str = 'DELETE' + elif self.op == self.OP_UPDATE: + op_str = 'UPDATE' + return '(%s, %s)' % (self.data, op_str) + +bgpd_client = None + +def g_run_command(table, command, use_bgpd_client, daemons, ignore_fail = False): + syslog.syslog(syslog.LOG_DEBUG, "execute command {} for table {}.".format(command, table)) + if not command.startswith('vtysh '): + use_bgpd_client = False + if use_bgpd_client: + if not bgpd_client.run_vtysh_command(table, command, daemons) and not ignore_fail: + syslog.syslog(syslog.LOG_ERR, 'command execution failure. Command: "{}"'.format(command)) + return False + else: + p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + stdout = p.communicate()[0] + p.wait() + if p.returncode != 0 and not ignore_fail: + syslog.syslog(syslog.LOG_ERR, '[bgp cfgd] command execution returned {}. Command: "{}", stdout: "{}"'.\ + format(p.returncode, command, stdout)) + return False + return True + +def extract_cmd_daemons(cmd_str): + # daemon list could be given within brackets at head of input lines + dm_mark = re.match(r'\[(?P.+)\]', cmd_str) + if dm_mark is not None and 'daemons' in dm_mark.groupdict(): + cmd_str = cmd_str[dm_mark.end():] + daemons = dm_mark.groupdict()['daemons'].split(',') + else: + daemons = None + return (daemons, cmd_str) + +class BgpdClientMgr(threading.Thread): + VTYSH_MARK = 'vtysh ' + PROXY_SERVER_ADDR = '/etc/frr/bgpd_client_sock' + ALL_DAEMONS = ['bgpd', 'zebra', 'staticd', 'bfdd', 'ospfd', 'pimd'] + TABLE_DAEMON = { + 'DEVICE_METADATA': ['bgpd'], + 'BGP_GLOBALS': ['bgpd'], + 'BGP_GLOBALS_AF': ['bgpd'], + 'PREFIX_SET': ['bgpd'], + 'PREFIX': ['bgpd'], + 'COMMUNITY_SET': ['bgpd'], + 'EXTENDED_COMMUNITY_SET': ['bgpd'], + 'ROUTE_MAP': ['zebra', 'bgpd', 'ospfd'], + 'PREFIX': ['zebra', 'bgpd', 'ospfd', 'pimd'], + 'BGP_PEER_GROUP': ['bgpd'], + 'BGP_NEIGHBOR': ['bgpd'], + 'BGP_PEER_GROUP_AF': ['bgpd'], + 'BGP_NEIGHBOR_AF': ['bgpd'], + 'BGP_GLOBALS_LISTEN_PREFIX': ['bgpd'], + 'NEIGHBOR_SET': ['bgpd'], + 'NEXTHOP_SET': ['bgpd'], + 'TAG_SET': ['bgpd'], + 'AS_PATH_SET': ['bgpd'], + 'ROUTE_REDISTRIBUTE': ['bgpd'], + 'BGP_GLOBALS_AF_AGGREGATE_ADDR': ['bgpd'], + 'BGP_GLOBALS_AF_NETWORK': ['bgpd'], + 'VRF': ['zebra'], + 'BGP_GLOBALS_EVPN_VNI': ['bgpd'], + 'BGP_GLOBALS_EVPN_RT': ['bgpd'], + 'BGP_GLOBALS_EVPN_VNI_RT': ['bgpd'], + 'BFD_PEER': ['bfdd'], + 'BFD_PEER_SINGLE_HOP': ['bfdd'], + 'BFD_PEER_MULTI_HOP': ['bfdd'], + 'IP_SLA': ['iptrackd'], + 'OSPFV2_ROUTER': ['ospfd'], + 'OSPFV2_ROUTER_AREA': ['ospfd'], + 'OSPFV2_ROUTER_AREA_VIRTUAL_LINK': ['ospfd'], + 'OSPFV2_ROUTER_AREA_NETWORK': ['ospfd'], + 'OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE': ['ospfd'], + 'OSPFV2_ROUTER_DISTRIBUTE_ROUTE': ['ospfd'], + 'OSPFV2_INTERFACE': ['ospfd'], + 'OSPFV2_ROUTER_PASSIVE_INTERFACE': ['ospfd'], + 'STATIC_ROUTE': ['staticd'], + 'PIM_GLOBALS': ['pimd'], + 'PIM_INTERFACE': ['pimd'], + 'IGMP_INTERFACE': ['pimd'], + 'IGMP_INTERFACE_QUERY': ['pimd'], + } + VTYSH_CMD_DAEMON = [(r'show (ip|ipv6) route($|\s+\S+)', ['zebra']), + (r'show ip mroute($|\s+\S+)', ['pimd']), + (r'show bfd($|\s+\S+)', ['bfdd']), + (r'clear bfd($|\s+\S+)', ['bfdd']), + (r'clear ip mroute($|\s+\S+)', ['pimd']), + (r'clear ip pim($|\s+\S+)', ['pimd']), + (r'show ip ospf($|\s+\S+)', ['ospfd']), + (r'show ip pim($|\s+\S+)', ['pimd']), + (r'show ip igmp($|\s+\S+)', ['pimd']), + (r'clear ip ospf($|\s+\S+)', ['ospfd']), + (r'show ip sla($|\s+\S+)', ['iptrackd']), + (r'clear ip sla($|\s+\S+)', ['iptrackd']), + (r'clear ip igmp($|\s+\S+)', ['pimd']), + (r'.*', ['bgpd'])] + @staticmethod + def __create_proxy_socket(): + try: + os.unlink(BgpdClientMgr.PROXY_SERVER_ADDR) + except OSError: + if os.path.exists(BgpdClientMgr.PROXY_SERVER_ADDR): + raise + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(BgpdClientMgr.PROXY_SERVER_ADDR) + sock.listen(1) + return sock + @staticmethod + def __get_reply(sock): + reply_msg = None + ret_code = None + msg_buf = cStringIO.StringIO() + while True: + try: + rd_msg = sock.recv(16384) + msg_buf.write(rd_msg) + except socket.timeout: + syslog.syslog(syslog.LOG_ERR, 'socket reading timeout') + break + if len(rd_msg) < 4: + rd_msg = msg_buf.getvalue() + if len(rd_msg) < 4: + continue + msg_tail = rd_msg[-4:] + if msg_tail[0] == '\0' and msg_tail[1] == '\0' and msg_tail[2] == '\0': + ret_code = ord(msg_tail[3]) + reply_msg = msg_buf.getvalue()[:-4] + break + msg_buf.close() + return (ret_code, reply_msg) + def __create_frr_client(self): + self.client_socks = {} + for daemon in self.ALL_DAEMONS: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + serv_addr = '/run/frr/%s.vty' % daemon + retry_cnt = 0 + while True: + try: + sock.connect(serv_addr) + break + except socket.error, msg: + syslog.syslog(syslog.LOG_ERR, 'failed to connect to frr daemon %s: %s' % (daemon, msg)) + retry_cnt += 1 + if retry_cnt > 100 or not main_loop: + syslog.syslog(syslog.LOG_ERR, 're-tried too many times, give up') + for _, sock in self.client_socks.items(): + sock.close() + return False + time.sleep(2) + continue + sock.settimeout(120) + self.client_socks[daemon] = sock + for daemon, sock in self.client_socks.items(): + syslog.syslog(syslog.LOG_DEBUG, 'send initial enable command to %s' % daemon) + try: + sock.sendall('enable\0') + except socket.error, msg: + syslog.syslog(syslog.LOG_ERR, 'failed to send initial enable command to %s' % daemon) + return False + ret_code, reply = self.__get_reply(sock) + if ret_code is None: + syslog.syslog(syslog.LOG_ERR, 'failed to command response for enable command') + return False + if ret_code != 0: + syslog.syslog(syslog.LOG_ERR, 'enable command failed: ret_code=%d' % ret_code) + syslog.syslog(syslog.LOG_ERR, reply) + return False + return True + def __init__(self): + super(BgpdClientMgr, self).__init__(name = 'VTYSH sub-process manager') + if not self.__create_frr_client(): + syslog.syslog(syslog.LOG_ERR, 'failed to create socket to FRR daemon') + raise RuntimeError('connect to FRR daemon failed') + self.proxy_running = True + self.lock = threading.Lock() + self.proxy_sock = self.__create_proxy_socket() + self.cmd_to_daemon = [] + for pat, daemons in self.VTYSH_CMD_DAEMON: + try: + self.cmd_to_daemon.append((re.compile(pat), daemons)) + except Exception: + syslog.syslog(syslog.LOG_ERR, 'invalid regex format: %s' % pat) + continue + def __get_cmd_daemons(self, cmd_list): + cmn_daemons = None + for cmd in cmd_list: + found = False + for re_comp, daemons in self.cmd_to_daemon: + if re_comp.match(cmd.strip()) is not None: + found = True + break + if not found: + syslog.syslog(syslog.LOG_ERR, 'no matched daemons found for command %s' % cmd) + return None + if cmn_daemons is None: + cmn_daemons = set(daemons) + else: + cmn_daemons = cmn_daemons.intersection(set(daemons)) + if len(cmn_daemons) == 0: + return [] + return list(cmn_daemons) + def __proc_command(self, command, daemons): + syslog.syslog(syslog.LOG_DEBUG, 'VTYSH CMD: %s daemons: %s' % (command, daemons)) + resp = '' + ret_val = False + for daemon in daemons: + sock = self.client_socks.get(daemon, None) + if sock is None: + syslog.syslog(syslog.LOG_ERR, 'daemon %s is not connected' % daemon) + continue + try: + sock.sendall(command + '\0') + except socket.error, msg: + syslog.syslog(syslog.LOG_ERR, 'failed to send command to frr daemon: %s' % msg) + return (False, None) + ret_code, reply = self.__get_reply(sock) + if ret_code is None or ret_code != 0: + if ret_code is None: + syslog.syslog(syslog.LOG_ERR, 'failed to get reply from frr daemon') + continue + else: + syslog.syslog(syslog.LOG_DEBUG, '[%s] command return code: %d' % (daemon, ret_code)) + syslog.syslog(syslog.LOG_DEBUG, reply) + else: + # command is running successfully by at least one daemon + ret_val = True + resp += reply + return (ret_val, resp) + def run_vtysh_command(self, table, command, daemons): + if not command.startswith(self.VTYSH_MARK): + syslog.syslog(syslog.LOG_ERR, 'command %s is not for vtysh config' % command) + return False + cmd_line = command[len(self.VTYSH_MARK):] + cmd_list = re.findall(r"-c\s+'([^']+)'\s*", cmd_line) + cmd_list.append('end') + if daemons is None: + daemons = self.TABLE_DAEMON.get(table, None) + if daemons is None: + daemons = self.__get_cmd_daemons(cmd_list) + if daemons is None or len(daemons) == 0: + syslog.syslog(syslog.LOG_ERR, 'no common daemon list found for given commands') + return False + ret_val = True + with self.lock: + for cmd in cmd_list: + succ, reply = self.__proc_command(cmd.strip(), daemons) + if not succ: + ret_val = False + return ret_val + @staticmethod + def __read_all(sock, data_len): + in_buf = cStringIO.StringIO() + left_len = data_len + while left_len > 0: + data = sock.recv(left_len) + if data is None: + break + in_buf.write(data) + left_len -= len(data) + return in_buf.getvalue() + def shutdown(self): + syslog.syslog(syslog.LOG_DEBUG, 'terminate bgpd client manager') + if self.is_alive(): + self.proxy_running = False + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + sock.connect(self.PROXY_SERVER_ADDR) + finally: + sock.close() + self.join() + for _, sock in self.client_socks.items(): + sock.close() + def run(self): + syslog.syslog(syslog.LOG_DEBUG, 'entering VTYSH proxy thread') + while self.proxy_running: + syslog.syslog(syslog.LOG_DEBUG, 'waiting for client connection ...') + conn_sock, clnt_addr = self.proxy_sock.accept() + if not self.proxy_running: + conn_sock.close() + break + try: + syslog.syslog(syslog.LOG_DEBUG, 'client connection from %s' % clnt_addr) + data = self.__read_all(conn_sock, 4) + if len(data) == 4: + data_len = struct.unpack('>I', data)[0] + in_cmd = self.__read_all(conn_sock, data_len) + if len(in_cmd) == data_len: + daemons, in_cmd = extract_cmd_daemons(in_cmd) + in_lines = in_cmd.splitlines() + if daemons is None: + daemons = self.__get_cmd_daemons(in_lines) + if daemons is not None and len(daemons) > 0: + with self.lock: + for line in in_lines: + _, reply = self.__proc_command(line.strip(), daemons) + if reply is not None: + conn_sock.sendall(reply) + else: + syslog.syslog(syslog.LOG_ERR, 'failed running VTYSH command') + else: + syslog.syslog(syslog.LOG_ERR, 'could not find common daemons for input commands') + else: + syslog.syslog(syslog.LOG_ERR, 'read data of length %d is not expected length %d' % (data_len, len(in_cmd))) + else: + syslog.syslog(syslog.LOG_ERR, 'invalid data length %d' % len(data)) + except socket.error, msg: + syslog.syslog(syslog.LOG_ERR, 'socket writing failed: %s' % msg) + finally: + syslog.syslog(syslog.LOG_DEBUG, 'closing data socket from client') + conn_sock.close() + syslog.syslog(syslog.LOG_DEBUG, 'leaving VTYSH proxy thread') +class BGPPeerGroup: + def __init__(self, vrf): + self.vrf = vrf + self.ref_nbrs = set() + +def get_command_cmn(daemon, cmd_str, op, st_idx, vals, bool_values): + chk_val = None + if op == CachedDataWithOp.OP_DELETE: + if bool_values is not None and len(bool_values) >= 3: + # set to default if given + cmd_enable = bool_values[2] + else: + cmd_enable = False + else: + cmd_enable = True + if bool_values is not None: + if len(vals) <= st_idx: + syslog.syslog(syslog.LOG_ERR, 'No bool token of index %d for running cmd: %s' % (st_idx, cmd_str)) + return None + chk_val = vals[st_idx] + if type(chk_val) is dict: + cmd_enable = False + for _, v in chk_val.items(): + if not v[1]: + continue + if v[0] == bool_values[0]: + cmd_enable = True + break + else: + if chk_val == bool_values[0]: + cmd_enable = True + elif chk_val == bool_values[1]: + cmd_enable = False + else: + syslog.syslog(syslog.LOG_ERR, 'Input token %s is neither %s or %s for cmd: %s' % + (chk_val, bool_values[0], bool_values[1], cmd_str)) + return None + else: + cmd_enable = True + cmd_args = [] + for idx in range(len(vals)): + if bool_values is not None and idx == st_idx: + continue + cmd_args.append(CommandArgument(daemon, cmd_enable, vals[idx])) + return [cmd_str.format(*cmd_args, no = CommandArgument(daemon, cmd_enable))] + +def hdl_set_extcomm(daemon, cmd_str, op, st_idx, args, is_inline): + if is_inline: + if type(args[0]) is list: + com_list = args[0] + else: + com_list = [args[0]] + else: + com_set = daemon.extcomm_set_list.get(args[0], None) + if com_set is None or not com_set.is_configurable(): + syslog.syslog(syslog.LOG_ERR, 'extended community set %s not found or configured' % args[0]) + return None + com_list = com_set.mbr_list + rt_cnt = soo_cnt = 0 + for comm in com_list: + if comm.startswith(CommunityList.RT_TYPE_MARK): + rt_cnt += 1 + elif comm.startswith(CommunityList.SOO_TYPE_MARK): + soo_cnt += 1 + cmd_list = [] + if op != CachedDataWithOp.OP_DELETE: + for comm_type in ['rt', 'soo']: + cmd_list.append(('no set extcommunity %s' % comm_type, True)) + if rt_cnt > 0: + new_args = ((args[0], True),) + args[1:] + cmd_list += get_command_cmn(daemon, cmd_str, op, st_idx, new_args, None) + if soo_cnt > 0: + new_args = ((args[0], False),) + args[1:] + cmd_list += get_command_cmn(daemon, cmd_str, op, st_idx, new_args, None) + return cmd_list + +def hdl_set_asn(daemon, cmd_str, op, st_idx, args, data): + if 0 not in args[0]: + return None + if op == CachedDataWithOp.OP_DELETE: + if args[0][0][1]: + args[0][1] = ('0', True) + else: + args[0].pop(1, None) + op = CachedDataWithOp.OP_UPDATE + return get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + +def hdl_set_asn_list(daemon, cmd_str, op, st_idx, args, data): + if op == CachedDataWithOp.OP_DELETE: + args = ('',) + return get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + +def hdl_set_pim_hello_parms (daemon, cmd_str, op, st_idx, args, data): + if op == CachedDataWithOp.OP_DELETE: + args = ('',) + return get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + +def handle_rmap_set_metric(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + syslog.syslog(syslog.LOG_INFO, 'handle_rmap_set_metric cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + arg_len = len(args) + metric_action = args[0] if arg_len >= 1 else '' + metric_value = args[1] if arg_len >= 2 else '' + med_value = args[2] if arg_len >= 3 else '' + metric_param = '' + + if metric_action != '' : + if metric_value != '' : + if metric_action == 'METRIC_SET_VALUE' : + metric_param = "{}".format(metric_value) + elif metric_action == 'METRIC_ADD_VALUE' : + metric_param = "+{}".format(metric_value) + elif metric_action == 'METRIC_SUBTRACT_VALUE' : + metric_param = "-{}".format(metric_value) + if metric_action == 'METRIC_SET_RTT' : + metric_param = "rtt" + elif metric_action == 'METRIC_ADD_RTT' : + metric_param = "+rtt" + elif metric_action == 'METRIC_SUBTRACT_RTT' : + metric_param = "-rtt" + + if metric_param == '' and med_value != '' : + metric_param = "{}".format(med_value) + + if op == CachedDataWithOp.OP_DELETE : + metric_param = '' + else : + if metric_param == '' : + syslog.syslog(syslog.LOG_ERR, 'handle_rmap_set_metric not set for {}'.format(args)) + return None + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, metric_param))) + return cmd_list + +class BGPKeyMapInfo: + def __init__(self, cmd_str, hdlr, data): + self.daemons, self.run_cmd = extract_cmd_daemons(cmd_str) + if hdlr is None: + self.hdl_func = get_command_cmn + else: + self.hdl_func = hdlr + self.data = data + def get_command(self, daemon, op, st_idx, *vals): + return self.hdl_func(daemon, self.run_cmd, op, st_idx, vals, self.data) + def __str__(self): + ret_str = '[CMD: %s' % self.run_cmd + if self.hdl_func == get_command_cmn and self.data is not None: + ret_str += ' BOOL: %s/%s' % (self.data[0], self.data[1]) + if len(self.data) >= 3: + ret_str += ' DFT: %s' % self.data[2] + ret_str += ']' + return ret_str + +class BGPKeyMapList(list): + def __init__(self, key_map_list, table_name, table_key = None): + super(BGPKeyMapList, self).__init__() + self.table_name = table_name + self.table_key = table_key + for key_map in key_map_list: + if len(key_map) < 2: + continue + db_field = key_map[0] + cmd_str = key_map[1] + hdl_data = None + hdl_func = None + if len(key_map) >= 3: + if callable(key_map[2]): + hdl_func = key_map[2] + if len(key_map) >= 4: + hdl_data = key_map[3] + else: + if len(key_map[2]) < 2: + continue + hdl_data = key_map[2] + fld_name, fld_key = self.get_map_field_key(db_field) + if fld_name is not None: + if table_key is not None and fld_name in table_key and table_key[fld_name] != fld_key: + continue + if type(db_field) is str: + db_field = fld_name + elif type(db_field) is list: + db_field = copy.copy(db_field) + try: + idx = db_field.index('|'.join([fld_name, fld_key])) + db_field[idx] = fld_name + except ValueError: + pass + super(BGPKeyMapList, self).append((db_field, BGPKeyMapInfo(cmd_str, hdl_func, hdl_data))) + @staticmethod + def get_map_field_key(field): + if type(field) is str: + field = [field] + elif type(field) is not list: + return (None, None) + for idx in range(len(field)): + tokens = field[idx].split('|', 1) + if len(tokens) == 2: + return tokens + return (None, None) + @staticmethod + def get_cmd_data(key_list, req_idx_list, opt_idx_list, data, chg_list, no_chg_list, merge_data, is_del): + for idx in req_idx_list: + if idx not in chg_list and idx not in no_chg_list: + syslog.syslog(syslog.LOG_DEBUG, 'mandatory key %s of idx %d not found in list' % (key_list[idx], idx)) + return None + if merge_data: + op = CachedDataWithOp.OP_DELETE if is_del else CachedDataWithOp.OP_UPDATE + cmd_data = {} + for idx in chg_list: + key = key_list[idx] + cmd_data[idx] = (data[key].data, True) + for idx in no_chg_list: + key = key_list[idx] + cmd_data[idx] = (data[key].data, False) + return ((cmd_data,), op) + else: + min_id = lambda id_set: None if len(id_set) == 0 else sorted(list(id_set))[0] + min_chg_id = min_id(chg_list) + if min_chg_id is None: + min_id_chged = False + else: + if min_chg_id in opt_idx_list: + min_id_chged = len(no_chg_list) == 0 + else: + min_unchg_id = min_id(no_chg_list) + min_id_chged = min_unchg_id is None or min_chg_id < min_unchg_id + op = CachedDataWithOp.OP_DELETE if is_del and min_id_chged else CachedDataWithOp.OP_UPDATE + cmd_data = [] + for idx in range(len(key_list)): + if (((not is_del or op == CachedDataWithOp.OP_DELETE) and (idx in chg_list or idx in no_chg_list)) or + (is_del and op == CachedDataWithOp.OP_UPDATE and idx in no_chg_list)): + cmd_data.append(data[key_list[idx]].data) + else: + if idx in opt_idx_list: + cmd_data.append('') + continue + else: + # stop adding following tokens + break + if len(cmd_data) == 0: + return None + idx = len(cmd_data) + while idx < len(key_list): + cmd_data.append('') + idx += 1 + return (tuple(cmd_data), op) + @staticmethod + def is_cmd_covered(src_cmd, dst_cmd): + src_tks = src_cmd.split() + dst_tks = dst_cmd.split() + if len(src_tks) >= len(dst_tks): + return False + for idx in range(len(src_tks)): + if src_tks[idx] != dst_tks[idx]: + return False + return True + @staticmethod + def is_cmd_list_covered(src_list, dst_list): + if len(src_list) == 0: + return True + if len(src_list) > len(dst_list): + return False + for idx in range(len(src_list)): + if not BGPKeyMapList.is_cmd_covered(src_list[idx], dst_list[idx]): + return False + return True + def run_command(self, daemon, table, data, prefix_list=None, *upper_vals): + start_idx = len(upper_vals) + ret_val = False + run_cmd_cnt = 0 + for db_field, key_map in self: + merge_vals = False + if type(db_field) is not list and type(db_field) is not tuple: + db_field = [db_field] + elif type(db_field) is tuple: + db_field = list(db_field) + merge_vals = True + + idx = 0 + req_idx_list = [] + key_list_list = [] + opt_idx_list = set() + run_cmd = True + for dkey in db_field: + optional = False + if len(dkey) > 0 and dkey[0] == '+': + if len(dkey) > 1 and dkey[1] == '+': + opt_idx_list.add(idx) + dkey = dkey[2:] + else: + dkey = dkey[1:] + optional = True + else: + req_idx_list.append(idx) + key_list = [] + for k in dkey.split('&'): + if k in data and isinstance(data[k], CachedDataWithOp): + key_list.append(k) + if not optional and len(key_list) == 0: + run_cmd = False + break + if len(key_list) == 0: + if len(key_list_list) == 0: + key_list_list.append([None]) + else: + for k_lst in key_list_list: + k_lst.append(None) + else: + new_list = [] + if len(key_list_list) == 0: + for k in key_list: + key_list_list.append([k]) + else: + for k_lst in key_list_list: + if len(key_list) == 1: + k_lst.append(key_list[0]) + else: + for k in key_list: + new_list.append(k_lst + [k]) + if len(new_list) > 0: + key_list_list = new_list + idx += 1 + if not run_cmd: + continue + + cmd_list_list = [] + for key_list in key_list_list: + upd_id_list = set() + del_id_list = set() + no_chg_id_list = set() + idx = 0 + for dkey in key_list: + if dkey is not None: + dval = data[dkey] + if dval.op == CachedDataWithOp.OP_NONE: + no_chg_id_list.add(idx) + elif dval.op == CachedDataWithOp.OP_ADD or dval.op == CachedDataWithOp.OP_UPDATE: + upd_id_list.add(idx) + elif dval.op == CachedDataWithOp.OP_DELETE: + del_id_list.add(idx) + idx += 1 + cmd_list = [] + if len(del_id_list) > 0: + data_val_op = self.get_cmd_data(key_list, req_idx_list, opt_idx_list, data, del_id_list, no_chg_id_list, merge_vals, True) + if data_val_op is not None: + cmd = key_map.get_command(daemon, data_val_op[1], start_idx, *(upper_vals + data_val_op[0])) + if cmd is not None: + cmd_list += cmd + else: + syslog.syslog(syslog.LOG_ERR, 'failed to get del cmd from value: %s' % data_val_op[0]) + if len(upd_id_list) > 0: + data_val_op = self.get_cmd_data(key_list, req_idx_list, opt_idx_list, data, upd_id_list, no_chg_id_list, merge_vals, False) + if data_val_op is not None: + cmd = key_map.get_command(daemon, data_val_op[1], start_idx, *(upper_vals + data_val_op[0])) + if cmd is not None: + cmd_list += cmd + else: + syslog.syslog(syslog.LOG_ERR, 'failed to get upd cmd from value: %s' % str(data_val_op[0])) + if len(cmd_list) > 0: + cmd_list_list.append(cmd_list) + cmd_list = [] + for chk_list in cmd_list_list: + if self.is_cmd_list_covered(cmd_list, chk_list): + cmd_list = chk_list + failed = False + if len(cmd_list) > 0: + run_cmd_cnt += 1 + cmd_prefix = 'vtysh ' + for pfx in prefix_list: + cmd_prefix += "-c '%s' " % pfx + for cmd in cmd_list: + ignore_fail = False + if type(cmd) is tuple: + cmd, ignore_fail = cmd + if not g_run_command(table, cmd_prefix + "-c '%s'" % cmd, True, key_map.daemons, ignore_fail): + syslog.syslog(syslog.LOG_ERR, 'failed running FRR command: %s' % cmd) + failed = True + break + if not failed: + ret_val = True + if not failed: + for key_list in key_list_list: + for dkey in key_list: + if dkey in data: + data[dkey].status = CachedDataWithOp.STAT_SUCC + if run_cmd_cnt == 0: + return True + return ret_val + +class CommandArgument(object): + def __init__(self, daemon, enabled, val = None): + self.daemon = daemon + self.enabled = enabled + self.value = val + self.tolower = False + def to_str(self): + if type(self.value) is list or type(self.value) is tuple: + ret_val = ' '.join([v for v in self.value]) + elif type(self.value) is dict: + id_list = self.value.keys() + id_list.sort() + ret_val = ' '.join([self.value[i][0] for i in id_list]) + else: + ret_val = str(self.value) + if self.tolower: + ret_val = ret_val.lower() + return ret_val + @staticmethod + def parse_ext_community(com_str, is_rt = None): + if com_str.startswith(CommunityList.RT_TYPE_MARK): + com_str = com_str[len(CommunityList.RT_TYPE_MARK):] + if is_rt is None: + return 'rt %s' % com_str + else: + return (com_str if is_rt else None) + elif com_str.startswith(CommunityList.SOO_TYPE_MARK): + com_str = com_str[len(CommunityList.SOO_TYPE_MARK):] + if is_rt is None: + return 'soo %s' % com_str + else: + return (None if is_rt else com_str) + return None + def __format__(self, format): + bool_format = {'allow-as-in': 'origin', + 'match-clust-len': 'equal-cluster-length', + 'network-backdoor': 'backdoor', + 'aggr-as-set': 'as-set', + 'aggr-summary-only': 'summary-only', + 'uchg-as-path': 'as-path', + 'uchg-med': 'med', + 'uchg-nh': 'next-hop', + 'rm-as-all': 'all', + 'rm-as-repl': 'replace-AS', + 'mp-as-set': ('as-set', 'no-as-set'), + 'no-prepend': 'no-prepend', + 'replace-as': 'replace-as', + 'blackhole': 'blackhole' + } + if format == 'no-prefix': + return 'no ' if not self.enabled else '' + elif format == 'enable-only' and not self.enabled: + return '' + elif format == 'com-ref': + com_set = self.daemon.comm_set_list.get(self.value, None) + if com_set is not None and com_set.is_configurable(): + return ' '.join(com_set.mbr_list) + elif format == 'ext-com-list': + if type(self.value) is tuple: + com_val, is_rt = self.value + else: + com_val = self.value + is_rt = None + if type(com_val) is list: + com_list = com_val + else: + com_list = [com_val] + frr_com_list = [] + for comm in com_list: + frr_comm = self.parse_ext_community(comm, is_rt) + if frr_comm is not None: + frr_com_list.append(frr_comm) + if is_rt is None: + return ' '.join(frr_com_list) + else: + return ('rt ' if is_rt else 'soo ') + ' '.join(frr_com_list) + elif format == 'ext-com-ref': + com_set_name, is_rt = self.value + com_set = self.daemon.extcomm_set_list.get(com_set_name, None) + if com_set is not None and com_set.is_configurable(): + frr_com_list = [] + for comm in com_set.mbr_list: + frr_comm = self.parse_ext_community(comm, is_rt) + if frr_comm is not None: + frr_com_list.append(frr_comm) + return ('rt ' if is_rt else 'soo ') + ' '.join(frr_com_list) + elif format == 'repeat' and type(self.value) is dict: + if 1 in self.value: + rep_cnt = int(self.value[1][0]) + else: + rep_cnt = 1 + if 0 in self.value: + return ' '.join([self.value[0][0]] * rep_cnt) + elif format == 'neighbor-set': + ret_val = BGPConfigDaemon.get_prefix_set_name(self.value, 'NEIGHBOR_SET') + return ret_val + elif format == 'nexthop-set': + ret_val = BGPConfigDaemon.get_prefix_set_name(self.value, 'NEXTHOP_SET') + return ret_val + elif format == 'peer-ip': + if type(self.value) is list and len(self.value) > 0: + return self.value[0] + else: + return self.value + elif format == 'tx-add-paths': + if self.value == 'tx_all_paths': + return 'addpath-tx-all-paths' + elif self.value == 'tx_best_path_per_as': + return 'addpath-tx-bestpath-per-AS' + elif format == 'shutdown-msg': + if len(self.value) > 0: + self.value = 'message %s' % self.value + elif format == 'default-rmap': + if len(self.value) > 0: + self.value = 'route-map %s' % self.value + elif format in bool_format: + false_val = '' + if type(bool_format[format]) is tuple: + if len(bool_format[format]) == 2: + true_val, false_val = bool_format[format] + else: + true_val = bool_format[format][0] + else: + true_val = bool_format[format] + if self.value == 'true': + self.value = true_val + elif self.value == 'false': + self.value = false_val + elif format == 'restart': + if self.value == 'true': + self.value = 'warning-only' + elif self.value == 'false': + self.value = '' + elif len(self.value) > 0: + self.value = 'restart %s' % self.value + elif format == 'redist-route-map': + if len(self.value) > 0: + self.value = 'route-map %s' % self.to_str() + elif format == 'redist-metric': + if len(self.value) > 0: + self.value = 'metric %s' % self.to_str() + elif format == 'track': + if len(self.value) > 0: + self.value = 'track %s' % self.to_str() + elif format == 'network-policy': + if len(self.value) > 0: + self.value = 'route-map %s' % self.to_str() + elif format == 'src-proto': + if self.value == 'ospf3': + self.value = 'ospf6' + elif format == 'aggr-policy': + if len(self.value) > 0: + self.value = 'route-map %s' % self.to_str() + elif format == 'asn_list': + self.value = ' '.join(self.value.split(',')) + elif format == 'nh-tag': + if len(self.value) > 0: + self.value = 'tag %s' % self.to_str() + elif format == 'nh-vrf': + if len(self.value) > 0: + self.value = 'nexthop-vrf %s' % self.to_str() + elif format == 'tolower': + self.tolower = True + elif format == 'pim_hello_parms': + self.value = ' '.join(self.value.split(',')) + return self.to_str() + +def hdl_send_com(daemon, cmd_str, op, st_idx, args, data): + if len(args) < 2: + return None + cmd_list = [] + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, 'all'), no = CommandArgument(daemon, False))) + if op == CachedDataWithOp.OP_DELETE: + com_type = 'all' + else: + com_type = args[1] + if com_type != 'none': + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, com_type), no = CommandArgument(daemon, True))) + return cmd_list + +def hdl_rm_priv_as(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, ''), CommandArgument(daemon, True, ''), + no = CommandArgument(daemon, False))) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, 'true'), CommandArgument(daemon, True, ''), + no = CommandArgument(daemon, False))) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, ''), CommandArgument(daemon, True, 'true'), + no = CommandArgument(daemon, False))) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, 'true'), CommandArgument(daemon, True, 'true'), + no = CommandArgument(daemon, False))) + if op != CachedDataWithOp.OP_DELETE: + cmd_list += get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + return cmd_list + +def hdl_capa_orf_pfxlist(daemon, cmd_str, op, st_idx, args, data): + if len(args) < 2: + return None + cmd_list = [] + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, 'both'), no = CommandArgument(daemon, False))) + if op != CachedDataWithOp.OP_DELETE: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[0]), CommandArgument(daemon, True, args[1]), no = CommandArgument(daemon, True))) + return cmd_list + +def hdl_com_set(daemon, cmd_str, op, st_idx, args, extended): + if len(args) < 2 or 0 not in args[1] or 1 not in args[1] or 2 not in args[1]: + return None + com_name = args[0] + set_type = args[1][0][0].lower() + arg_str = '{} {}'.format(set_type, com_name) + cmd_list = [] + com_set_list = daemon.comm_set_list if not extended else daemon.extcomm_set_list + if com_name in com_set_list and com_set_list[com_name].is_configurable(): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, arg_str), no = CommandArgument(daemon, False))) + if op != CachedDataWithOp.OP_DELETE: + match_action = args[1][1][0].lower() + member_list = args[1][2][0] + if match_action == 'all': + if extended and set_type == 'standard': + mbr_str = '{} permit {:ext-com-list}'.format(arg_str, CommandArgument(daemon, True, member_list)) + else: + mbr_str = '{} permit {}'.format(arg_str, ' '.join(member_list)) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, mbr_str), no = CommandArgument(daemon, True))) + elif match_action == 'any': + for member in member_list: + if extended and set_type == 'standard': + mbr_str = '{} permit {:ext-com-list}'.format(arg_str, CommandArgument(daemon, True, member)) + else: + mbr_str = '{} permit {}'.format(arg_str, member) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, mbr_str), no = CommandArgument(daemon, True))) + return cmd_list + +def hdl_aspath_set(daemon, cmd_str, op, st_idx, args, data): + if len(args) < 2: + return None + cmd_list = [] + as_set_name = args[0] + if as_set_name in daemon.as_path_set_list: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, as_set_name), no = CommandArgument(daemon, False))) + if op != CachedDataWithOp.OP_DELETE and len(args[1]) > 0: + for asn in args[1]: + mbr_str = '{} permit {}'.format(as_set_name, asn) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, mbr_str), no = CommandArgument(daemon, True))) + return cmd_list + +def hdl_ibgp_maxpath(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if op != CachedDataWithOp.OP_DELETE: + # blindly run no command first + cmd_list = [cmd_str.format(CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, 'false'), + no = CommandArgument(daemon, False))] + upd_cmd_list = get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + if upd_cmd_list is None: + return None + return cmd_list + upd_cmd_list + +def hdl_ospf_log(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + if (no_op == 'no '): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, ""))) + elif (args[0] == "DETAIL"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0].lower()))) + elif (args[0] == "BRIEF"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, ""))) + + return cmd_list + +def handle_ospf_area_auth(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + if (args[1] == "MD5HMAC"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, "message-digest"))) + + elif (args[1] == "TEXT"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, ""))) + elif (args[1] == "NONE"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, 'no '), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, ""))) + return cmd_list + +def handle_ospf_area_shortcut(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + if (args[1] == "DEFAULT") and (no_op != 'no '): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, "default"))) + + elif (args[1] == "ENABLE"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, "enable"))) + elif (args[1] == "DISABLE"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, "disable"))) + return cmd_list + +def handle_ospf_area_vlink_auth(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + if (args[2] == "MD5HMAC"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, args[1]), + CommandArgument(daemon, True, "message-digest"))) + elif (args[2] == "NONE"): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, args[1]), + CommandArgument(daemon, True, "null"))) + + return cmd_list + +def handle_ospf_area_range_advt(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + if (args[2] == 'true'): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, args[1]), + CommandArgument(daemon, True, "advertise"))) + elif (args[2] == 'false'): + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, args[1]), + CommandArgument(daemon, True, "not-advertise"))) + return cmd_list + +def handle_ospf_abrtype(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, args[0].lower()))) + + return cmd_list + + +def handle_ospf_if_common(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if_addr = "" if args[1] == '0.0.0.0' else args[1] + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + param_value = args[2] + + syslog.syslog(syslog.LOG_INFO, 'handle_ospf_if_common cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, param_value), + CommandArgument(daemon, True, if_addr))) + return cmd_list + + +def handle_ospf_if_authtype(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if_addr = "" if args[1] == '0.0.0.0' else args[1] + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + authtype = '' + if args[2] == 'TEXT' : + authtype = '' + elif args[2] == 'MD5HMAC' : + authtype = 'message-digest' + elif args[2] == 'NONE' : + authtype = 'null' + else : + syslog.syslog(syslog.LOG_ERR, 'handle_ospf_if_nwtype invalid auth type args {}'.format(args)) + + syslog.syslog(syslog.LOG_INFO, 'handle_ospf_if_authtype cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, authtype), + CommandArgument(daemon, True, if_addr))) + return cmd_list + + +def handle_ospf_if_md5key(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if_addr = "" if args[1] == '0.0.0.0' else args[1] + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + md5key_id = args[2] + md5key = args[3] + + syslog.syslog(syslog.LOG_INFO, 'handle_ospf_if_md5key cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, md5key_id), + CommandArgument(daemon, True, md5key), + CommandArgument(daemon, True, if_addr))) + return cmd_list + + +def handle_ospf_if_mtu_ignore(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if_addr = "" if args[1] == '0.0.0.0' else args[1] + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + syslog.syslog(syslog.LOG_INFO, 'handle_ospf_if_mtu_ignore cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, if_addr))) + return cmd_list + + +def handle_ospf_if_nwtype(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if_addr = "" if args[1] == '0.0.0.0' else args[1] + no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' + + nwtype = '' + if args[2] == 'POINT_TO_POINT_NETWORK' : + nwtype = 'point-to-point' + elif args[2] == 'BROADCAST_NETWORK' : + nwtype = 'broadcast' + else : + syslog.syslog(syslog.LOG_ERR, 'handle_ospf_if_nwtype invalid nw type args {}'.format(args)) + + syslog.syslog(syslog.LOG_INFO, 'handle_ospf_if_nwtype cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, no_op), + CommandArgument(daemon, True, nwtype))) + return cmd_list + +def handle_igmp_if_common(daemon, cmd_str, op, st_idx, args, data): + if len(args) != 1: + return None + cmd_list = [] + param_value = args[0] + + syslog.syslog(syslog.LOG_INFO, 'handle_igmp_if_common cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + if op != CachedDataWithOp.OP_DELETE: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, param_value))) + else: + cmd_list.append('no ' + cmd_str.format(CommandArgument(daemon, True, ''))) + + syslog.syslog(syslog.LOG_INFO, 'handle_igmp_if_common param {}, cmd_list {}'.format(param_value, cmd_list)) + return cmd_list + +def handle_igmp_if_enable(daemon, cmd_str, op, st_idx, args, data): + if len(args) != 1: + return None + cmd_list = [] + param_value = args[0] + + syslog.syslog(syslog.LOG_INFO, 'handle_igmp_if_enable cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + if op != CachedDataWithOp.OP_DELETE: + if param_value == 'false': + cmd_list.append('no ' + cmd_str.format(CommandArgument(daemon, True, ''))) + else: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, ''))) + else: + cmd_list.append('no ' + cmd_str.format(CommandArgument(daemon, True, ''))) + + syslog.syslog(syslog.LOG_INFO, 'handle_igmp_if_enable param {}, cmd_list {}'.format(param_value, cmd_list)) + return cmd_list + +def handle_ip_sla_common(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + param_value = args[0] + + syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + + if op != CachedDataWithOp.OP_DELETE: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[1]))) + else: + cmd_list.append('no ' + cmd_str.format(CommandArgument(daemon, True, ''))) + + return cmd_list + +def handle_ip_sla_tcp_connect(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + param_value = args[0] + + syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla_tcp_connect cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + tcp_cmd_token = ("tcp", "connect") + tcp_cmd_str = "-".join(tcp_cmd_token) + tcp_cmd_deconfig = ' no ' + tcp_cmd_str + + if op != CachedDataWithOp.OP_DELETE: + cmd_list.append(' ') + else: + cmd_list.append(tcp_cmd_deconfig) + + return cmd_list + +def handle_ip_sla_icmp_echo(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + param_value = args[0] + + syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla_icmp_echo cmd_str {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + icmp_cmd_token = ("icmp", "echo") + icmp_cmd_str = "-".join(icmp_cmd_token) + icmp_cmd_deconfig = ' no ' + icmp_cmd_str + + if op != CachedDataWithOp.OP_DELETE: + cmd_list.append(' ') + syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla_icmp_echo cmd_list {}'.format(cmd_list)) + else: + cmd_list.append(icmp_cmd_deconfig) + + syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla_icmp_echo cmd_list {}'.format(cmd_list)) + return cmd_list + + + +def hdl_af_aggregate(daemon, cmd_str, op, st_idx, args, data): + if len(args) < 5: + return None + cmd_list = [] + if op != CachedDataWithOp.OP_DELETE: + vrf = args[0] + af = args[1] + ip_prefix = args[2] + if vrf in daemon.af_aggr_list and ip_prefix in daemon.af_aggr_list[vrf]: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, vrf), CommandArgument(daemon, True, af), CommandArgument(daemon, True, ip_prefix), + CommandArgument(daemon, True, ''), CommandArgument(daemon, True, ''), CommandArgument(daemon, True, ''), + no = CommandArgument(daemon, False))) + upd_cmd_list = get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + if upd_cmd_list is None: + return None + return cmd_list + upd_cmd_list + +def hdl_route_redist_set(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + if op != CachedDataWithOp.OP_DELETE: + proto = args[0] + # blindly run no command first + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, proto), CommandArgument(daemon, True, ''), CommandArgument(daemon, True, ''), + no = CommandArgument(daemon, False))) + upd_cmd_list = get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + if upd_cmd_list is None: + return None + return cmd_list + upd_cmd_list + +def hdl_attr_unchanged(daemon, cmd_str, op, st_idx, args, data): + # blindly run no command first + cmd_list = [cmd_str.format(CommandArgument(daemon, True, args[0]), + CommandArgument(daemon, True, ''), + CommandArgument(daemon, True, ''), + CommandArgument(daemon, True, ''), + no = CommandArgument(daemon, False))] + if op != CachedDataWithOp.OP_DELETE: + upd_cmd_list = get_command_cmn(daemon, cmd_str, op, st_idx, args, data) + if upd_cmd_list is None: + return None + cmd_list += upd_cmd_list + return cmd_list + +def hdl_leaf_list_expansion(daemon, cmd_str, op, st_idx, args, data, table_key, item_key): + cmd_list = [] + old_list = [] + if op != CachedDataWithOp.OP_DELETE: + new_list = args[st_idx] + else: + new_list = [] + + syslog.syslog(syslog.LOG_DEBUG, 'handle_leaf_list_expansion {} op {} st_idx {} args {} data {} table_key {} item_key {}'.format( + cmd_str, op, st_idx, args, data, table_key, item_key)) + + if table_key in daemon.table_data_cache.keys(): + cache_tbl_data = daemon.table_data_cache[table_key] + if item_key in cache_tbl_data: + old_list = cache_tbl_data[item_key] + + del_list = list(set(old_list) - set(new_list)) + add_list = list(set(new_list) - set(old_list)) + + for value in add_list: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, value), no = CommandArgument(daemon, True))) + for value in del_list: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, value), no = CommandArgument(daemon, False))) + + syslog.syslog(syslog.LOG_DEBUG, 'cmd_list {}'.format(cmd_list)) + return cmd_list + +def hdl_import_list(daemon, cmd_str, op, st_idx, args, data): + return hdl_leaf_list_expansion(daemon, cmd_str, op, st_idx, args, data, daemon.tmp_cache_key, 'import-rts') + +def hdl_export_list(daemon, cmd_str, op, st_idx, args, data): + return hdl_leaf_list_expansion(daemon, cmd_str, op, st_idx, args, data, daemon.tmp_cache_key, 'export-rts') + +def hdl_enum_conversion(daemon, cmd_str, op, st_idx, args, data): + cmd_list = [] + syslog.syslog(syslog.LOG_DEBUG, 'handle_enum_conversion {} op {} st_idx {} args {} data {}'.format( + cmd_str, op, st_idx, args, data)) + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, args[st_idx].lower().replace('_','-')), + no = CommandArgument(daemon, (op != CachedDataWithOp.OP_DELETE)))) + syslog.syslog(syslog.LOG_DEBUG, 'cmd_list {}'.format(cmd_list)) + return cmd_list + +def hdl_confed_peers(daemon, cmd_str, op, st_idx, args, data): + del_list = [] + add_list = [] + if op == CachedDataWithOp.OP_DELETE: + del_list = list(daemon.upd_confed_peers) + daemon.upd_confed_peers.clear() + else: + for peer in args[0]: + if peer not in daemon.upd_confed_peers: + add_list.append(peer) + else: + daemon.upd_confed_peers.remove(peer) + del_list = list(daemon.upd_confed_peers) + daemon.upd_confed_peers = set(args[0]) + cmd_list = [] + if len(del_list) > 0: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, del_list), no = CommandArgument(daemon, False))) + if len(add_list) > 0: + cmd_list.append(cmd_str.format(CommandArgument(daemon, True, add_list), no = CommandArgument(daemon, True))) + return cmd_list + +def hdl_static_route(daemon, cmd_str, op, st_idx, args, data): + if len(args) < 6: + return None + vrf = args[0] + ip_prefix = args[1] + af = data + if op == CachedDataWithOp.OP_DELETE: + ip_nh_set = IpNextHopSet(af) + else: + arg_list = lambda v: v.split(',') if len(v.strip()) != 0 else None + bkh_list = arg_list(args[2]) + nh_list = arg_list(args[3]) + track_list = arg_list(args[5]) + intf_list = arg_list(args[4]) + tag_list = arg_list(args[6]) + dist_list = arg_list(args[7]) + nh_vrf_list = arg_list(args[8]) + ip_nh_set = IpNextHopSet(af, bkh_list, nh_list, track_list, intf_list, tag_list, dist_list, nh_vrf_list) + cur_nh_set = daemon.static_route_list.get(vrf, {}).get(ip_prefix, IpNextHopSet(af)) + diff_set = ip_nh_set.symmetric_difference(cur_nh_set) + op_cmd_list = {} + for ip_nh in diff_set: + if ip_nh in cur_nh_set: + op = CachedDataWithOp.OP_DELETE + else: + op = CachedDataWithOp.OP_ADD + try: + op_cmds = op_cmd_list.setdefault(op, []) + op_cmds += get_command_cmn(daemon, cmd_str, op, st_idx, [ip_prefix] + ip_nh.get_arg_list(), None) + except socket.error: + syslog.syslog(syslog.LOG_ERR, 'Invalid IP in next-hop %s' % ip_nh) + return None + cmd_list = op_cmd_list.get(CachedDataWithOp.OP_DELETE, []) + cmd_list += op_cmd_list.get(CachedDataWithOp.OP_ADD, []) + daemon.upd_nh_set = ip_nh_set + return cmd_list + +class ExtConfigDBConnector(ConfigDBConnector): + def __init__(self, ns_attrs = None): + super(ExtConfigDBConnector, self).__init__() + self.nosort_attrs = ns_attrs if ns_attrs is not None else {} + def __raw_to_typed(self, table, raw_data): + if len(raw_data) == 0: + raw_data = None + data = super(ExtConfigDBConnector, self)._ConfigDBConnector__raw_to_typed(raw_data) + if data is None: + return None + for key, val in data.items(): + if type(val) is list and key not in self.nosort_attrs.get(table, set()): + val.sort() + return data + def sub_msg_handler(self, msg_item): + if msg_item['type'] == 'pmessage': + key = msg_item['channel'].split(':', 1)[1] + try: + (table, row) = key.split(self.TABLE_NAME_SEPARATOR, 1) + if self.handlers.has_key(table): + client = self.get_redis_client(self.db_name) + data = self.__raw_to_typed(table, client.hgetall(key)) + super(ExtConfigDBConnector, self)._ConfigDBConnector__fire(table, row, data) + except ValueError: + pass #Ignore non table-formated redis entries + except Exception as e: + syslog.syslog(syslog.LOG_ERR, '[bgp cfgd] Failed handling config DB update with exception:' + str(e)) + logging.exception(e) + def listen(self): + """Start listen Redis keyspace events and will trigger corresponding handlers when content of a table changes. + """ + self.pubsub = self.get_redis_client(self.db_name).pubsub() + self.pubsub.psubscribe(**{"__keyspace@{}__:*".format(self.get_dbid(self.db_name)): self.sub_msg_handler}) + self.sub_thread = self.pubsub.run_in_thread(sleep_time = 0.01) + @staticmethod + def get_table_key(table, key): + return table + '&&' + key + def get_table_data(self, table_list): + ret_data = {} + for table in table_list: + table_data = self.get_table(table) + for key, data in table_data.items(): + table_key = self.get_table_key(table, self.serialize_key(key)) + ret_data[table_key] = data + return ret_data + +class CommunityList: + MATCH_ALL = 0 + MATCH_ANY = 1 + RT_TYPE_MARK = 'route-target:' + SOO_TYPE_MARK = 'route-origin:' + def __init__(self, name, extended): + self.name = name + self.is_ext = extended + self.match_action = None + self.is_std = None + self.mbr_list = [] + def is_configurable(self): + return (self.match_action is not None and self.is_std is not None and + len(self.mbr_list) > 0) + def db_data_to_attr(self, name, val): + if name == 'match_action': + if val is None: + self.match_action = None + else: + if val.lower() == 'all': + self.match_action = self.MATCH_ALL + else: + self.match_action = self.MATCH_ANY + elif name == 'set_type': + if val is None: + self.is_std = None + else: + self.is_std = (val.lower() == 'standard') + elif name == 'community_member': + self.mbr_list = [] + if val is not None: + if type(val) is not list: + self.mbr_list = val.split(',') + else: + self.mbr_list = val + +class MatchPrefix: + IPV4_MAXLEN = 32 + IPV6_MAXLEN = 128 + @staticmethod + def normalize_ip_prefix(af, ip_prefix): + ip_mask = ip_prefix.split('/') + ip_addr = ip_mask[0] + if len(ip_mask) < 2: + mask_len = MatchPrefix.IPV4_MAXLEN if af == socket.AF_INET else MatchPrefix.IPV6_MAXLEN + return '%s/%d' % (ip_addr, mask_len) + mask_len = int(ip_mask[1]) + ip_net = netaddr.IPNetwork('%s/%d' % (ip_addr, mask_len)) + try: + normal_ip = socket.inet_ntop(af, ip_net.cidr.ip.packed) + except ValueError: + return None + return '%s/%d' % (normal_ip, mask_len) + def __init__(self, af, ip_prefix, len_range = None, action = 'permit'): + self.ip_prefix = self.normalize_ip_prefix(af, ip_prefix) + if self.ip_prefix is None: + raise ValueError + if len_range is not None: + min_len, max_len = len_range.split('..') + self.min_len = int(min_len) + self.max_len = int(max_len) + _, pfx_len = self.ip_prefix.split('/') + if int(pfx_len) >= self.min_len: + self.min_len = None + elif ((af == socket.AF_INET and self.max_len == self.IPV4_MAXLEN) or + (af == socket.AF_INET6 and self.max_len == self.IPV6_MAXLEN)): + self.max_len = None + else: + self.min_len = self.max_len = None + self.action = action + def __str__(self): + ret_str = '%s %s' % (self.action.lower(), self.ip_prefix) + if self.min_len is not None: + ret_str += ' ge %d' % self.min_len + if self.max_len is not None: + ret_str += ' le %d' % self.max_len + return ret_str + def __eq__(self, other): + return (self.ip_prefix == other.ip_prefix and + self.min_len == other.min_len and + self.max_len == other.max_len) + +class MatchPrefixList(list): + def __init__(self, af_mode = None): + super(MatchPrefixList, self).__init__() + if af_mode is None: + self.af = None + else: + self.af = socket.AF_INET if af_mode == 'ipv4' else socket.AF_INET6 + @staticmethod + def __get_ip_af(ip_pfx): + ip_pfx = ip_pfx.split('/') + ip_addr = ip_pfx[0] + af_list = [socket.AF_INET, socket.AF_INET6] + for af in af_list: + try: + socket.inet_pton(af, ip_addr) + return af + except socket.error: + continue + return None + def add_prefix(self, ip_pfx, len_range = None, action = 'permit'): + af = self.__get_ip_af(ip_pfx) + if self.af is None: + self.af = af + else: + if self.af != af: + syslog.syslog(syslog.LOG_ERR, 'af of prefix %s is not the same as prefix set' % ip_pfx) + raise ValueError + self.append(MatchPrefix(self.af, ip_pfx, len_range, action)) + return self[-1] + def get_prefix(self, ip_pfx, len_range = None, action = 'permit'): + if self.af is None: + return (None, None) + prefix = MatchPrefix(self.af, ip_pfx, len_range, action) + try: + idx = self.index(prefix) + except ValueError: + return (None, None) + return (self[idx], idx) + +class AggregateAddr: + def __init__(self): + self.as_set = False + self.summary_only = False + +class IpNextHop: + def __init__(self, af_id, blackhole, dst_ip, track, if_name, tag, dist, vrf): + zero_ip = lambda af: '0.0.0.0' if af == socket.AF_INET else '::' + self.af = af_id + self.blackhole = 'false' if blackhole is None or blackhole == '' else blackhole + self.distance = 0 if dist is None else int(dist) + self.track = 0 if track is None else int(track) + if self.blackhole == 'true': + dst_ip = if_name = vrf = None + self.ip = zero_ip(af_id) if dst_ip is None else dst_ip + self.interface = '' if if_name is None else if_name + self.tag = 0 if tag is None else int(tag) + self.nh_vrf = '' if vrf is None else vrf + if self.blackhole != 'true' and self.is_zero_ip() and len(self.interface.strip()) == 0: + syslog.syslog(syslog.LOG_ERR, 'Mandatory attribute not found for nexthop') + raise ValueError + def __eq__(self, other): + return (self.af == other.af and self.blackhole == other.blackhole and + self.ip == other.ip and self.track == other.track and self.interface == other.interface and + self.tag == other.tag and self.distance == other.distance and self.nh_vrf == other.nh_vrf) + def __hash__(self): + return hash((self.af, self.blackhole, self.ip, self.track, self.interface, self.tag, self.distance, self.nh_vrf)) + def __str__(self): + return 'AF %d BKH %s IP %s TRACK %d INTF %s TAG %d DIST %d VRF %s' % ( + self.af, self.blackhole, self.ip, self.track, self.interface, self.tag, self.distance, self.nh_vrf) + def is_zero_ip(self): + return sum([ord(x) for x in socket.inet_pton(self.af, self.ip)]) == 0 + def get_arg_list(self): + arg = lambda x: '' if x is None else x + num_arg = lambda x: '' if x is None or x == 0 else str(x) + ip_arg = lambda : '' if self.ip is None else ('' if self.is_zero_ip() else self.ip) + return [self.blackhole, ip_arg(), arg(self.interface), num_arg(self.track), num_arg(self.tag), num_arg(self.distance), arg(self.nh_vrf)] + +class IpNextHopSet(set): + def __init__(self, af, bkh_list = None, ip_list = None, track_list = None, intf_list = None, tag_list = None, dist_list = None, vrf_list = None): + super(IpNextHopSet, self).__init__() + if bkh_list is None and ip_list is None and intf_list is None: + # empty set, for delete case + return + nums = {len(x) for x in [bkh_list, ip_list, track_list, intf_list, tag_list, dist_list, vrf_list] if x is not None} + if len(nums) != 1: + syslog.syslog(syslog.LOG_ERR, 'Lists of next-hop attribute have different sizes: %s' % nums) + for x in [bkh_list, ip_list, track_list, intf_list, tag_list, dist_list, vrf_list]: + syslog.syslog(syslog.LOG_DEBUG, 'List: %s' % x) + return + nh_cnt = nums.pop() + item = lambda lst, i: lst[i] if lst is not None else None + for idx in range(nh_cnt): + try: + self.add(IpNextHop(af, item(bkh_list, idx), item(ip_list, idx), item(track_list, idx), item(intf_list, idx), + item(tag_list, idx), item(dist_list, idx), item(vrf_list, idx), )) + except ValueError: + continue + @staticmethod + def get_af_norm_prefix(ip_prefix): + for af_id in [socket.AF_INET, socket.AF_INET6]: + new_prefix = MatchPrefix.normalize_ip_prefix(af_id, ip_prefix) + if new_prefix is not None: + return (af_id, new_prefix) + return (None, None) + +class BGPConfigDaemon: + DEFAULT_VRF = 'default' + + global_key_map = [('router_id', '{no:no-prefix}bgp router-id {}'), + (['load_balance_mp_relax', '+as_path_mp_as_set'], '{no:no-prefix}bgp bestpath as-path multipath-relax {:mp-as-set}', ['true', 'false']), + ('always_compare_med', '{no:no-prefix}bgp always-compare-med', ['true', 'false']), + ('external_compare_router_id', '{no:no-prefix}bgp bestpath compare-routerid', ['true', 'false']), + ('ignore_as_path_length', '{no:no-prefix}bgp bestpath as-path ignore', ['true', 'false']), + ('graceful_restart_enable', '{no:no-prefix}bgp graceful-restart', ['true', 'false']), + ('gr_restart_time', '{no:no-prefix}bgp graceful-restart restart-time {}'), + ('gr_stale_routes_time', '{no:no-prefix}bgp graceful-restart stalepath-time {}'), + ('gr_preserve_fw_state', '{no:no-prefix}bgp graceful-restart preserve-fw-state', ['true', 'false']), + ('log_nbr_state_changes', '{no:no-prefix}bgp log-neighbor-changes', ['true', 'false']), + ('rr_cluster_id', '{no:no-prefix}bgp cluster-id {}'), + ('rr_allow_out_policy', '{no:no-prefix}bgp route-reflector allow-outbound-policy', ['true', 'false']), + ('disable_ebgp_connected_rt_check', '{no:no-prefix}bgp disable-ebgp-connected-route-check', ['true', 'false']), + ('fast_external_failover', '{no:no-prefix}bgp fast-external-failover', ['true', 'false', True]), + ('network_import_check', '{no:no-prefix}bgp network import-check', ['true', 'false']), + ('graceful_shutdown', '{no:no-prefix}bgp graceful-shutdown', ['true', 'false']), + ('rr_clnt_to_clnt_reflection', '{no:no-prefix}bgp client-to-client reflection', ['true', 'false', True]), + ('max_dynamic_neighbors', '{no:no-prefix}bgp listen limit {}'), + ('read_quanta', '{no:no-prefix}read-quanta {}'), + ('write_quanta', '{no:no-prefix}write-quanta {}'), + ('coalesce_time', '{no:no-prefix}coalesce-time {}'), + ('route_map_process_delay', '{no:no-prefix}bgp route-map delay-timer {}'), + ('deterministic_med', '{no:no-prefix}bgp deterministic-med', ['true', 'false']), + ('med_confed', '{no:no-prefix}bgp bestpath med confed', ['true', 'false']), + ('med_missing_as_worst', '{no:no-prefix}bgp bestpath med missing-as-worst', ['true', 'false']), + ('compare_confed_as_path', '{no:no-prefix}bgp bestpath as-path confed', ['true', 'false']), + ('default_ipv4_unicast', '{no:no-prefix}bgp default ipv4-unicast', ['true', 'false']), + ('default_local_preference', '{no:no-prefix}bgp default local-preference {}'), + ('default_show_hostname', '{no:no-prefix}bgp default show-hostname', ['true', 'false']), + ('default_shutdown', '{no:no-prefix}bgp default shutdown', ['true', 'false']), + ('default_subgroup_pkt_queue_max', '{no:no-prefix}bgp default subgroup-pkt-queue-max {}'), + (['max_med_time', '+max_med_val'], '{no:no-prefix}bgp max-med on-startup {} {}'), + (['max_delay', '+establish_wait'], '{no:no-prefix}update-delay {} {}'), + ('confed_id', '{no:no-prefix}bgp confederation identifier {}'), + ('confed_peers', '{no:no-prefix}bgp confederation peers {}', hdl_confed_peers), + (['keepalive', 'holdtime'], '{no:no-prefix}timers bgp {} {}'), + (['max_med_admin', '+max_med_admin_val'], '{no:no-prefix}bgp max-med administrative {}', ['true', 'false']) + ] + + global_af_key_map = [(['ebgp_route_distance', + 'ibgp_route_distance', + 'local_route_distance'], '{no:no-prefix}distance bgp {} {} {}'), + ('max_ebgp_paths', '{no:no-prefix}maximum-paths {}'), + (['max_ibgp_paths', + '+ibgp_equal_cluster_length'], '{no:no-prefix}maximum-paths ibgp {} {:match-clust-len}', hdl_ibgp_maxpath), + ('route_download_filter', '{no:no-prefix}table-map {}'), + (['route_flap_dampen', + '+route_flap_dampen_half_life', + '+route_flap_dampen_reuse_threshold', + '+route_flap_dampen_suppress_threshold', + '+route_flap_dampen_max_suppress'], '{no:no-prefix}bgp dampening {} {} {} {}', ['true', 'false']), + ('advertise-all-vni', '{no:no-prefix}advertise-all-vni', ['true','false']), + ('advertise-default-gw', '{no:no-prefix}advertise-default-gw', ['true','false']), + ('advertise-ipv4-unicast', '{no:no-prefix}advertise ipv4 unicast', ['true','false']), + ('advertise-ipv6-unicast', '{no:no-prefix}advertise ipv6 unicast', ['true','false']), + ('default-originate-ipv4', '{no:no-prefix}default-originate ipv4', ['true','false']), + ('default-originate-ipv6', '{no:no-prefix}default-originate ipv6', ['true','false']), + ('autort', '{no:no-prefix}autort {}', hdl_enum_conversion), + ('flooding', '{no:no-prefix}flooding {}'), + ('dad-enabled', '{no:no-prefix}dup-addr-detection', ['true','false']), + (['dad-max-moves', + 'dad-time'], '{no:no-prefix}dup-addr-detection max-moves {} time {}'), + ('dad-freeze', '{no:no-prefix}dup-addr-detection freeze {}'), + ('route-distinguisher', '{no:no-prefix}rd {}'), + ('import-rts', '{no:no-prefix}route-target import {}', hdl_import_list), + ('export-rts', '{no:no-prefix}route-target export {}', hdl_export_list), + ('import_vrf', '{no:no-prefix}import vrf {}'), + ('import_vrf_route_map', '{no:no-prefix}import vrf route-map {}') + ] + + cmn_key_map = [('asn&peer_type', '{no:no-prefix}neighbor {} remote-as {}'), + (['local_asn', '+local_as_no_prepend', + '+local_as_replace_as'], '{no:no-prefix}neighbor {} local-as {} {:no-prepend} {:replace-as}'), + (['admin_status', '+shutdown_message'], '{no:no-prefix}neighbor {} shutdown {:shutdown-msg}', ['false', 'true']), + ('local_addr', '{no:no-prefix}neighbor {} update-source {}'), + ('name', '{no:no-prefix}neighbor {} description {}'), + (['ebgp_multihop', '+ebgp_multihop_ttl'],'{no:no-prefix}neighbor {} ebgp-multihop {}', ['true', 'false']), + ('auth_password', '{no:no-prefix}neighbor {} password {} encrypted'), + (['keepalive', 'holdtime'], '{no:no-prefix}neighbor {} timers {} {}'), + ('conn_retry', '{no:no-prefix}neighbor {} timers connect {}'), + ('min_adv_interval', '{no:no-prefix}neighbor {} advertisement-interval {}'), + ('passive_mode', '{no:no-prefix}neighbor {} passive', ['true', 'false']), + ('capability_ext_nexthop', '{no:no-prefix}neighbor {} capability extended-nexthop', ['true', 'false']), + ('disable_ebgp_connected_route_check', '{no:no-prefix}neighbor {} disable-connected-check', ['true', 'false']), + ('enforce_first_as', '{no:no-prefix}neighbor {} enforce-first-as', ['true', 'false']), + ('solo_peer', '{no:no-prefix}neighbor {} solo', ['true', 'false']), + ('ttl_security_hops', '{no:no-prefix}neighbor {} ttl-security hops {}'), + ('bfd', '{no:no-prefix}neighbor {} bfd', ['true', 'false']), + ('bfd_check_ctrl_plane_failure', '{no:no-prefix}neighbor {} bfd check-control-plane-failure', ['true', 'false']), + ('capability_dynamic', '{no:no-prefix}neighbor {} capability dynamic', ['true', 'false']), + ('dont_negotiate_capability', '{no:no-prefix}neighbor {} dont-capability-negotiate', ['true', 'false']), + ('enforce_multihop', '{no:no-prefix}neighbor {} enforce-multihop', ['true', 'false']), + ('override_capability', '{no:no-prefix}neighbor {} override-capability', ['true', 'false']), + ('peer_port', '{no:no-prefix}neighbor {} port {}'), + ('strict_capability_match', '{no:no-prefix}neighbor {} strict-capability-match', ['true', 'false']) + ] + + nbr_key_map = [('peer_group_name', '{no:no-prefix}neighbor {} peer-group {}')] + + nbr_af_key_map = [(['allow_as_in', '+allow_as_count&allow_as_origin'], '{no:no-prefix}neighbor {} allowas-in {:allow-as-in}', ['true', 'false']), + ('admin_status|ipv4', '{no:no-prefix}neighbor {} activate', ['true', 'false', False]), + ('admin_status|ipv6', '{no:no-prefix}neighbor {} activate', ['true', 'false', False]), + ('admin_status|l2vpn', '{no:no-prefix}neighbor {} activate', ['true', 'false', False]), + (['send_default_route', '+default_rmap'], '{no:no-prefix}neighbor {} default-originate {:default-rmap}', ['true', 'false']), + ('default_rmap', '{no:no-prefix}neighbor {} default-originate route-map {}'), + (['max_prefix_limit', '++max_prefix_warning_threshold', + '+max_prefix_restart_interval&max_prefix_warning_only'], '{no:no-prefix}neighbor {} maximum-prefix {} {} {:restart}'), + ('route_map_in', '{no:no-prefix}neighbor {} route-map {} in'), + ('route_map_out', '{no:no-prefix}neighbor {} route-map {} out'), + ('soft_reconfiguration_in', '{no:no-prefix}neighbor {} soft-reconfiguration inbound', ['true', 'false']), + ('unsuppress_map_name', '{no:no-prefix}neighbor {} unsuppress-map {}'), + ('rrclient', '{no:no-prefix}neighbor {} route-reflector-client', ['true', 'false']), + ('weight', '{no:no-prefix}neighbor {} weight {}'), + ('as_override', '{no:no-prefix}neighbor {} as-override', ['true', 'false']), + ('send_community', '{no:no-prefix}neighbor {} send-community {}', hdl_send_com), + ('tx_add_paths', '{no:no-prefix}neighbor {} {:tx-add-paths}'), + (['++unchanged_as_path', + '++unchanged_med', '++unchanged_nexthop'], '{no:no-prefix}neighbor {} attribute-unchanged {:uchg-as-path} {:uchg-med} {:uchg-nh}', hdl_attr_unchanged), + ('filter_list_in', '{no:no-prefix}neighbor {} filter-list {} in'), + ('filter_list_out', '{no:no-prefix}neighbor {} filter-list {} out'), + ('nhself', '{no:no-prefix}neighbor {} next-hop-self', ['true', 'false']), + ('nexthop_self_force', '{no:no-prefix}neighbor {} next-hop-self force', ['true', 'false']), + ('prefix_list_in', '{no:no-prefix}neighbor {} prefix-list {} in'), + ('prefix_list_out', '{no:no-prefix}neighbor {} prefix-list {} out'), + (['remove_private_as_enabled', + '++remove_private_as_all', + '+replace_private_as'], '{no:no-prefix}neighbor {} remove-private-AS {:rm-as-all} {:rm-as-repl}', hdl_rm_priv_as, ['true', 'false']), + ('cap_orf', '{no:no-prefix}neighbor {} capability orf prefix-list {}', hdl_capa_orf_pfxlist), + ('route_server_client', '{no:no-prefix}neighbor {} route-server-client', ['true', 'false']), + ] + + route_map_key_map = [('match_interface', '{no:no-prefix}match interface {}'), + ('match_prefix_set|ipv4', '{no:no-prefix}match ip address prefix-list {}'), + ('match_prefix_set|ipv6', '{no:no-prefix}match ipv6 address prefix-list {}'), + ('match_neighbor', '[bgpd]{no:no-prefix}match peer {:peer-ip}'), + ('match_tag', '{no:no-prefix}match tag {}'), + ('match_protocol', '[zebra]{no:no-prefix}match source-protocol {:src-proto}'), + ('match_next_hop_set|ipv4', '{no:no-prefix}match ip next-hop prefix-list {}'), + ('match_next_hop_set|ipv6', '{no:no-prefix}match ip next-hop prefix-list {}'), #match ipv6 next-hop prefix-list not suppported by frr + ('match_med', '{no:no-prefix}match metric {}'), + ('match_origin', '[bgpd]{no:no-prefix}match origin {:tolower}'), + ('match_local_pref', '[bgpd]{no:no-prefix}match local-preference {}'), + ('match_community', '[bgpd]{no:no-prefix}match community {}'), + ('match_ext_community', '[bgpd]{no:no-prefix}match extcommunity {}'), + ('match_as_path', '[bgpd]{no:no-prefix}match as-path {}'), + ('match_src_vrf', '[bgpd]{no:no-prefix}match source-vrf {}'), + ('call_route_map', '{no:no-prefix}call {:enable-only}'), + ('set_origin', '[bgpd]{no:no-prefix}set origin {:tolower}'), + ('set_local_pref', '[bgpd]{no:no-prefix}set local-preference {}'), + ('set_next_hop', '{no:no-prefix}set ip next-hop {}'), + ('set_ipv6_next_hop_global', '[bgpd]{no:no-prefix}set ipv6 next-hop global {}'), + ('set_ipv6_next_hop_prefer_global', '[bgpd]{no:no-prefix}set ipv6 next-hop prefer-global', ['true', 'false']), + (['set_metric_action', '+set_metric', '+set_med'], '{}set metric {} ', handle_rmap_set_metric), + ('set_med', '{no:no-prefix}set metric {}'), + (('set_asn', '+set_repeat_asn'), '[bgpd]{no:no-prefix}set as-path prepend {:repeat}', hdl_set_asn), + ('set_asn_list', '[bgpd]{no:no-prefix}set as-path prepend {:asn_list}', hdl_set_asn_list), + ('set_community_inline', '[bgpd]{no:no-prefix}set community {}'), + ('set_community_ref', '[bgpd]{no:no-prefix}set community {:com-ref}'), + ('set_ext_community_inline', '[bgpd]{no:no-prefix}set extcommunity {:ext-com-list}', hdl_set_extcomm, True), + ('set_ext_community_ref', '[bgpd]{no:no-prefix}set extcommunity {:ext-com-ref}', hdl_set_extcomm, False) + ] + + bfd_peer_shop_key_map = [('enabled', '{no:no-prefix}shutdown', ['false', 'true']), + ('desired-minimum-tx-interval', '{no:no-prefix}transmit-interval {}'), + ('required-minimum-receive', '{no:no-prefix}receive-interval {}'), + ('desired-minimum-echo-receive', '{no:no-prefix}echo-interval {}'), + ('detection-multiplier', '{no:no-prefix}detect-multiplier {}'), + ('echo-active', '{no:no-prefix}echo-mode', ['true', 'false']) + ] + + bfd_peer_mhop_key_map = [('enabled', '{no:no-prefix}shutdown', ['false', 'true']), + ('desired-minimum-tx-interval', '{no:no-prefix}transmit-interval {}'), + ('required-minimum-receive', '{no:no-prefix}receive-interval {}'), + ('detection-multiplier', '{no:no-prefix}detect-multiplier {}'), + ] + + listen_prefix_key_map = [('peer_group', '{no:no-prefix}bgp listen range {} peer-group {}')] + + community_set_key_map = [(('set_type', 'match_action', 'community_member'), '{no:no-prefix}bgp community-list {}', hdl_com_set, False)] + extcommunity_set_key_map = [(('set_type', 'match_action', 'community_member'), '{no:no-prefix}bgp extcommunity-list {}', hdl_com_set, True)] + + aspath_set_key_map = [('as_path_set_member', '{no:no-prefix}bgp as-path access-list {}', hdl_aspath_set)] + + route_redist_key_map = [(['protocol', '++metric', '+route_map'], + '{no:no-prefix}redistribute {} {:redist-metric} {:redist-route-map}', hdl_route_redist_set)] + + af_aggregate_key_map = [(['ip_prefix', '++as_set', '++summary_only', '+policy'], + '{no:no-prefix}aggregate-address {2} {3:aggr-as-set} {4:aggr-summary-only} {5:aggr-policy}', hdl_af_aggregate)] + + af_network_key_map = [(['ip_prefix', '++policy', '+backdoor'], '{no:no-prefix}network {2} {3:network-policy} {4:network-backdoor}')] + + global_evpn_vni_key_map = [('advertise-default-gw', '{no:no-prefix}advertise-default-gw', ['true','false']), + ('route-distinguisher', '{no:no-prefix}rd {}'), + ('import-rts', '{no:no-prefix}route-target import {}', hdl_import_list), + ('export-rts', '{no:no-prefix}route-target export {}', hdl_export_list)] + + ospfv2_global_key_map = [('enable', '{no:no-prefix}'), + ('auto-cost-reference-bandwidth', '{no:no-prefix}auto-cost reference-bandwidth {}'), + ('ospf-rfc1583-compatible', '{no:no-prefix}compatible rfc1583', ['true', 'false']), + ('max-metric-administrative', '{no:no-prefix}max-metric router-lsa administrative', ['true', 'false']), + ('max-metric-on-shutdown', '{no:no-prefix}max-metric router-lsa on-shutdown {}'), + ('max-metric-on-startup', '{no:no-prefix}max-metric router-lsa on-startup {}'), + ('router-id', '{no:no-prefix}ospf router-id {}'), + ('abr-type', '{}ospf abr-type {:abrtype}', handle_ospf_abrtype), + ('write-multiplier', '{no:no-prefix}write-multiplier {}'), + ('passive-interface-default', '{no:no-prefix}passive-interface default', ['true', 'false']), + ('lsa-refresh-timer', '{no:no-prefix}refresh timer {}'), + ('lsa-min-arrival-timer', '{no:no-prefix}timers lsa min-arrival {}'), + ('lsa-min-interval-timer', '{no:no-prefix}timers throttle lsa all {}'), + (['spf-initial-delay', 'spf-maximum-delay', 'spf-throttle-delay'], '{no:no-prefix}timers throttle spf {} {} {}'), + ('log-adjacency-changes', '{}log-adjacency-changes {}', hdl_ospf_log), + ('default-metric', '{no:no-prefix}default-metric {}'), + ('distance-all', '{no:no-prefix}distance {}'), + ('distance-external', '{no:no-prefix}distance ospf external {}'), + ('distance-inter-area', '{no:no-prefix}distance ospf inter-area {}'), + ('distance-intra-area', '{no:no-prefix}distance ospf intra-area {}')] + + ospfv2_area_key_map = [('stub', '{no:no-prefix}area {} stub'), + ('stub-no-summary', '{no:no-prefix}area {} stub no-summary'), + ('import-list', '{no:no-prefix}area {} import-list {}'), + ('export-list', '{no:no-prefix}area {} export-list {}'), + ('filter-list-in', '{no:no-prefix}area {} filter-list prefix {} in'), + ('filter-list-out', '{no:no-prefix}area {} filter-list prefix {} out'), + ('authentication', '{}area {} authentication {}', handle_ospf_area_auth), + ('stub-default-cost', '{no:no-prefix}area {} default-cost {}'), + ('shortcut', '{}area {} shortcut {}', handle_ospf_area_shortcut)] + + ospfv2_area_vlink_key_map = [('enable', '{no:no-prefix}area {} virtual-link {}'), + ('dead-interval', '{no:no-prefix}area {} virtual-link {} dead-interval {}'), + ('hello-interval', '{no:no-prefix}area {} virtual-link {} hello-interval {}'), + ('retransmission-interval', '{no:no-prefix}area {} virtual-link {} retransmit-interval {}'), + ('transmit-delay', '{no:no-prefix}area {} virtual-link {} transmit-delay {}'), + ('authentication-type', '{}area {} virtual-link {} authentication {}', handle_ospf_area_vlink_auth), + ('authentication-key', '{no:no-prefix}area {} virtual-link {} authentication-key {}'), + (['authentication-key-id', 'authentication-md5-key'], '{no:no-prefix}area {} virtual-link {} authentication message-digest message-digest-key {} md5 {}')] + + ospfv2_area_range_key_map =[('advertise', '{} area {} range {} {}', handle_ospf_area_range_advt), + ('metric', '{no:no-prefix} area {} range {} cost {}'), + ('substitue-prefix', '{no:no-prefix} area {} range {} substitute {}')] + + ospfv2_distribution_key_map = [('route-map|BGP|IMPORT', '{no:no-prefix}distribute-list {} out bgp'), + ('route-map|STATIC|IMPORT', '{no:no-prefix}distribute-list {} out static')] + + ospfv2_interface_key_map = [ + ('area-id', '{}ip ospf area {} {}', handle_ospf_if_common), + ('authentication-type', '{}ip ospf authentication {} {}', handle_ospf_if_authtype), + ('authentication-key', '{}ip ospf authentication-key {} {}', handle_ospf_if_common), + ('bfd-enable', '{no:no-prefix}ip ospf bfd ', ['true', 'false']), + ('metric', '{}ip ospf cost {} {}', handle_ospf_if_common), + ('dead-interval', '{}ip ospf dead-interval {} {}', handle_ospf_if_common), + ('hello-multiplier', '{}ip ospf dead-interval minimal hello-multiplier {} {}', handle_ospf_if_common), + ('hello-interval', '{}ip ospf hello-interval {} {}', handle_ospf_if_common), + (['authentication-key-id', '+authentication-md5-key'], '{}ip ospf message-digest-key {} md5 {} {}', handle_ospf_if_md5key), + ('mtu-ignore', '{}ip ospf mtu-ignore {}', handle_ospf_if_mtu_ignore), + ('network-type', '{}ip ospf network {}', handle_ospf_if_nwtype), + ('priority', '{}ip ospf priority {} {}', handle_ospf_if_common), + ('retransmission-interval', '{}ip ospf retransmit-interval {} {}', handle_ospf_if_common), + ('transmit-delay', '{}ip ospf transmit-delay {} {}', handle_ospf_if_common), + ] + static_route_map = [(['ip_prefix|ipv4', '++blackhole', '++nexthop', '++ifname', '++track', '++tag', '++distance', '++nexthop-vrf'], + '{no:no-prefix}ip route {} {:blackhole} {} {} {:track} {:nh-tag} {} {:nh-vrf}', hdl_static_route, socket.AF_INET), + (['ip_prefix|ipv6', '++blackhole', '++nexthop', '++ifname', '++track', '++tag', '++distance', '++nexthop-vrf'], + '{no:no-prefix}ipv6 route {} {:blackhole} {} {} {:track} {:nh-tag} {} {:nh-vrf} ', hdl_static_route, socket.AF_INET6)] + pim_interface_key_map = [('mode', '{no:no-prefix}ip pim', ['sm','']), + ('dr-priority', '{no:no-prefix}ip pim drpriority {}'), + ('hello-interval', '{no:no-prefix}ip pim hello {:pim_hello_parms}', + hdl_set_pim_hello_parms), + ('bfd-enabled', '{no:no-prefix}ip pim bfd', ['true', 'false']), + ] + pim_global_key_map = [('join-prune-interval', '{no:no-prefix}ip pim join-prune-interval {}'), + ('keep-alive-timer', '{no:no-prefix}ip pim keep-alive-timer {}'), + ('ssm-ranges', '{no:no-prefix}ip pim ssm prefix-list {}'), + ('ecmp-enabled', '{no:no-prefix}ip pim ecmp', ['true', 'false']), + ('ecmp-rebalance-enabled', '{no:no-prefix}ip pim ecmp rebalance',['true', 'false']), + ] + + igmp_mcast_grp_key_map =[('enable', '{no:no-prefix}ip igmp join {} {}'), + ] + + igmp_interface_config_key_map = [ + ('enabled', 'ip igmp {}', handle_igmp_if_enable), + ('version', '{no:no-prefix}ip igmp version {}'), + ('query-interval', 'ip igmp query-interval {}', handle_igmp_if_common), + ('query-max-response-time', 'ip igmp query-max-response-time {}', handle_igmp_if_common), + ('last-member-query-count', 'ip igmp last-member-query-count {}', handle_igmp_if_common), + ('last-member-query-interval', 'ip igmp last-member-query-interval {}', handle_igmp_if_common), + ] + ip_sla_key_map = [ + ('sla_id', '{no:no-prefix}ip sla {}'), + ('frequency', 'frequency {}', handle_ip_sla_common), + ('threshold', 'threshold {}', handle_ip_sla_common), + ('timeout', 'timeout {}', handle_ip_sla_common), + ('tcp_source_port', 'source-port {}', handle_ip_sla_common), + ('tcp_source_ip', 'source-address {}', handle_ip_sla_common), + ('tcp_dst_ip', 'tcp-connect {} port {}', handle_ip_sla_tcp_connect), + ('tcp_vrf', 'source-vrf {}', handle_ip_sla_common), + ('tcp_dst_port', 'tcp-connect {} port {}', handle_ip_sla_tcp_connect), + ('tcp_source_interface', 'source-interface {}', handle_ip_sla_common), + ('tcp_ttl', 'ttl {}', handle_ip_sla_common), + ('tcp_tos', 'tos {}', handle_ip_sla_common), + ('icmp_source_interface', 'source-interface {}', handle_ip_sla_common), + ('icmp_source_ip', 'source-address {}', handle_ip_sla_common), + ('icmp_dst_ip', 'icmp-echo {}', handle_ip_sla_icmp_echo), + ('icmp_vrf', 'source-vrf {}', handle_ip_sla_common), + ('icmp_size', 'request-data-size {}', handle_ip_sla_common), + ('icmo_ttl', 'ttl {}', handle_ip_sla_common), + ('icmp_tos', 'tos {}', handle_ip_sla_common), + ] + + + tbl_to_key_map = {'BGP_GLOBALS': global_key_map, + 'BGP_GLOBALS_AF': global_af_key_map, + 'BGP_GLOBALS_LISTEN_PREFIX': listen_prefix_key_map, + 'BGP_NEIGHBOR': cmn_key_map[0:2] + nbr_key_map + cmn_key_map[2:], + 'BGP_PEER_GROUP': cmn_key_map, + 'BGP_NEIGHBOR_AF': nbr_af_key_map, + 'BGP_PEER_GROUP_AF': nbr_af_key_map, + 'ROUTE_MAP': route_map_key_map, + 'COMMUNITY_SET': community_set_key_map, + 'EXTENDED_COMMUNITY_SET': extcommunity_set_key_map, + 'AS_PATH_SET': aspath_set_key_map, + 'ROUTE_REDISTRIBUTE': route_redist_key_map, + 'BGP_GLOBALS_AF_AGGREGATE_ADDR': af_aggregate_key_map, + 'BGP_GLOBALS_AF_NETWORK': af_network_key_map, + 'BGP_GLOBALS_EVPN_VNI': global_evpn_vni_key_map, + 'BFD_PEER_SINGLE_HOP': bfd_peer_shop_key_map, + 'BFD_PEER_MULTI_HOP': bfd_peer_mhop_key_map, + 'IP_SLA': ip_sla_key_map, + 'OSPFV2_ROUTER': ospfv2_global_key_map, + 'OSPFV2_ROUTER_AREA': ospfv2_area_key_map, + 'OSPFV2_ROUTER_AREA_VIRTUAL_LINK':ospfv2_area_vlink_key_map, + 'OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE':ospfv2_area_range_key_map, + 'OSPFV2_INTERFACE': ospfv2_interface_key_map, + 'STATIC_ROUTE': static_route_map, + 'PIM_GLOBALS': pim_global_key_map, + 'PIM_INTERFACE': pim_interface_key_map, + 'IGMP_INTERFACE': igmp_mcast_grp_key_map, + 'IGMP_INTERFACE_QUERY': igmp_interface_config_key_map + } + + vrf_tables = {'BGP_GLOBALS', 'BGP_GLOBALS_AF', + 'BGP_NEIGHBOR', 'BGP_PEER_GROUP', 'BGP_NEIGHBOR_AF', 'BGP_PEER_GROUP_AF', + 'BGP_GLOBALS_LISTEN_PREFIX', 'ROUTE_REDISTRIBUTE', + 'BGP_GLOBALS_AF_AGGREGATE_ADDR', 'BGP_GLOBALS_AF_NETWORK', + 'BGP_GLOBALS_EVPN_RT', 'BGP_GLOBALS_EVPN_VNI', 'BGP_GLOBALS_EVPN_VNI_RT'} + + @staticmethod + def __peer_is_ip(peer): + try: + socket.inet_pton(socket.AF_INET, peer) + return True + except socket.error: + pass + try: + socket.inet_pton(socket.AF_INET6, peer) + return True + except socket.error: + pass + return False + + def __init__(self): + self.config_db = ExtConfigDBConnector({'STATIC_ROUTE': {'nexthop', 'ifname', 'distance', 'nexthop-vrf', 'blackhole', 'track'}}) + try: + self.config_db.connect() + except Exception as e: + syslog.syslog(syslog.LOG_ERR, '[bgp cfgd] Failed connecting to config DB with exception:' + str(e)) + db_entry = self.config_db.get_entry('DEVICE_METADATA', 'localhost') + if 'bgp_asn' in db_entry: + self.metadata_asn = db_entry['bgp_asn'] + else: + self.metadata_asn = None + if 'docker_routing_config_mode' in db_entry: + self.config_mode = db_entry['docker_routing_config_mode'] + else: + self.config_mode = "separated" + # VRF ==> local_as + self.bgp_asn = {} + # VRF ==> confederation peer list + self.bgp_confed_peers = {} + glb_table = self.config_db.get_table('BGP_GLOBALS') + for vrf, entry in glb_table.items(): + if 'local_asn' in entry: + self.bgp_asn[vrf] = entry['local_asn'] + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: VRF %s Local_ASN %s' % (vrf, self.bgp_asn[vrf])) + if 'confed_peers' in entry: + self.bgp_confed_peers[vrf] = set(entry['confed_peers']) + # VRF ==> grp_name ==> peer_group + self.bgp_peer_group = {} + # VRF ==> set of interface neighbor + self.bgp_intf_nbr = {} + nbr_table = self.config_db.get_table('BGP_NEIGHBOR') + pg_table = self.config_db.get_table('BGP_PEER_GROUP') + for key, entry in pg_table.items(): + vrf, pg = key + self.bgp_peer_group.setdefault(vrf, {})[pg] = BGPPeerGroup(vrf) + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: VRF %s Peer_Group %s' % (vrf, pg)) + for key, entry in nbr_table.items(): + if len(key) != 2: + continue + vrf, peer = key + if 'peer_group_name' in entry: + pg_name = entry['peer_group_name'] + if vrf in self.bgp_peer_group and pg_name in self.bgp_peer_group[vrf]: + self.bgp_peer_group[vrf][pg_name].ref_nbrs.add(peer) + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: VRF %s Neighbor %s Peer_Group %s' % + (vrf, peer, pg_name)) + if not self.__peer_is_ip(peer): + self.bgp_intf_nbr.setdefault(vrf, set()).add(peer) + # map_name ==> seq_no ==> operation + self.route_map = {} + rtmap_table = self.config_db.get_table('ROUTE_MAP') + for key, entry in rtmap_table.items(): + rtmap_name, seq_no = key + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: Route_Map %s Seq_NO %s' % (rtmap_name, seq_no)) + if 'route_operation' in entry: + self.route_map.setdefault(rtmap_name, {})[seq_no] = entry['route_operation'] + + self.comm_set_list = {} + comm_table = self.config_db.get_table('COMMUNITY_SET') + for key, entry in comm_table.items(): + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: Community %s' % key) + self.comm_set_list[key] = CommunityList(key, False) + for k, v in entry.items(): + self.comm_set_list[key].db_data_to_attr(k, v) + self.extcomm_set_list = {} + extcomm_table = self.config_db.get_table('EXTENDED_COMMUNITY_SET') + for key, entry in extcomm_table.items(): + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: Extended_Community %s' % key) + self.extcomm_set_list[key] = CommunityList(key, True) + for k, v in entry.items(): + self.extcomm_set_list[key].db_data_to_attr(k, v) + self.prefix_set_list = {} + pfx_set_table = self.config_db.get_table('PREFIX_SET') + for key, entry in pfx_set_table.items(): + if 'mode' in entry: + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: Prefix_Set %s mode %s' % (key, entry['mode'])) + self.prefix_set_list[key] = MatchPrefixList(entry['mode'].lower()) + pfx_table = self.config_db.get_table('PREFIX') + for key, entry in pfx_table.items(): + pfx_set_name, ip_pfx, len_range = key + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: Prefix %s range %s of set %s' % (ip_pfx, len_range, pfx_set_name)) + if len_range == 'exact': + len_range = None + if pfx_set_name in self.prefix_set_list and 'action' in entry: + try: + self.prefix_set_list[pfx_set_name].add_prefix(ip_pfx, len_range, entry['action']) + except ValueError: + pass + self.as_path_set_list = {} + aspath_table = self.config_db.get_table('AS_PATH_SET') + for key, entry in aspath_table.items(): + if 'as_path_set_member' in entry: + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: AS_Path_Set %s member %s' % (key, entry['as_path_set_member'])) + self.as_path_set_list[key] = entry['as_path_set_member'][:] + self.tag_set_list = {} + + self.af_aggr_list = {} + af_aggr_table = self.config_db.get_table('BGP_GLOBALS_AF_AGGREGATE_ADDR') + for key, entry in af_aggr_table.items(): + vrf, af_type, ip_pfx = key + af, _ = af_type.lower().split('_') + norm_ip_pfx = MatchPrefix.normalize_ip_prefix((socket.AF_INET if af == 'ipv4' else socket.AF_INET6), ip_pfx) + if norm_ip_pfx is not None: + syslog.syslog(syslog.LOG_DEBUG, 'Init Config DB Data: AF Aggregate Prefix %s of vrf %s AF %s' % (norm_ip_pfx, vrf, af)) + aggr_obj = AggregateAddr() + for k, v in entry.items(): + if v == 'true': + setattr(aggr_obj, k, True) + self.af_aggr_list.setdefault(vrf, {})[norm_ip_pfx] = aggr_obj + + self.vrf_vni_map = {} + vrf_table = self.config_db.get_table('VRF') + for key, entry in vrf_table.items(): + if 'vni' in entry: + self.vrf_vni_map[key] = entry['vni'] + + # VRF ==> ip_prefix ==> nexthop list + self.static_route_list = {} + sroute_table = self.config_db.get_table('STATIC_ROUTE') + get_list = lambda v: v.split(',') if v is not None else None + for key, entry in sroute_table.items(): + if type(key) is tuple and len(key) == 2: + vrf, ip_prefix = key + else: + vrf = self.DEFAULT_VRF + ip_prefix = key + af, ip_prefix = IpNextHopSet.get_af_norm_prefix(ip_prefix) + nh_attr = lambda k: get_list(entry.get(k, None)) + self.static_route_list.setdefault(vrf, {})[ip_prefix] = IpNextHopSet(af, + nh_attr('blackhole'), nh_attr('nexthop'),nh_attr('track'), + nh_attr('ifname'), nh_attr('tag'), nh_attr('distance'), + nh_attr('nexthop-vrf')) + + self.table_handler_list = [ + ('VRF', self.vrf_handler), + ('DEVICE_METADATA', self.metadata_handler), + ('BGP_GLOBALS', self.bgp_global_handler), + ('BGP_GLOBALS_AF', self.bgp_af_handler), + ('PREFIX_SET', self.bgp_table_handler_common), + ('PREFIX', self.bgp_table_handler_common), + ('COMMUNITY_SET', self.comm_set_handler), + ('EXTENDED_COMMUNITY_SET', self.comm_set_handler), + ('ROUTE_MAP', self.bgp_table_handler_common), + ('BGP_PEER_GROUP', self.bgp_neighbor_handler), + ('BGP_NEIGHBOR', self.bgp_neighbor_handler), + ('BGP_PEER_GROUP_AF', self.bgp_table_handler_common), + ('BGP_NEIGHBOR_AF', self.bgp_table_handler_common), + ('BGP_GLOBALS_LISTEN_PREFIX', self.bgp_table_handler_common), + ('BGP_GLOBALS_EVPN_VNI', self.bgp_table_handler_common), + ('BGP_GLOBALS_EVPN_RT', self.bgp_table_handler_common), + ('BGP_GLOBALS_EVPN_VNI_RT', self.bgp_table_handler_common), + ('BFD_PEER', self.bfd_handler), + ('NEIGHBOR_SET', self.bgp_table_handler_common), + ('NEXTHOP_SET', self.bgp_table_handler_common), + ('TAG_SET', self.bgp_table_handler_common), + ('AS_PATH_SET', self.bgp_table_handler_common), + ('ROUTE_REDISTRIBUTE', self.bgp_table_handler_common), + ('BGP_GLOBALS_AF_AGGREGATE_ADDR', self.bgp_table_handler_common), + ('BGP_GLOBALS_AF_NETWORK', self.bgp_table_handler_common), + ('BFD_PEER_SINGLE_HOP', self.bgp_table_handler_common), + ('BFD_PEER_MULTI_HOP', self.bgp_table_handler_common), + ('IP_SLA', self.bgp_table_handler_common), + ('OSPFV2_ROUTER', self.bgp_table_handler_common), + ('OSPFV2_ROUTER_AREA', self.bgp_table_handler_common), + ('OSPFV2_ROUTER_AREA_VIRTUAL_LINK', self.bgp_table_handler_common), + ('OSPFV2_ROUTER_AREA_NETWORK', self.bgp_table_handler_common), + ('OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE', self.bgp_table_handler_common), + ('OSPFV2_ROUTER_DISTRIBUTE_ROUTE', self.bgp_table_handler_common), + ('OSPFV2_INTERFACE', self.bgp_table_handler_common), + ('OSPFV2_ROUTER_PASSIVE_INTERFACE', self.bgp_table_handler_common), + ('STATIC_ROUTE', self.bgp_table_handler_common), + ('PIM_GLOBALS', self.bgp_table_handler_common), + ('PIM_INTERFACE', self.bgp_table_handler_common), + ('IGMP_INTERFACE', self.bgp_table_handler_common), + ('IGMP_INTERFACE_QUERY', self.bgp_table_handler_common) + ] + self.bgp_message = Queue.Queue(0) + self.table_data_cache = self.config_db.get_table_data([tbl for tbl, _ in self.table_handler_list]) + syslog.syslog(syslog.LOG_DEBUG, 'Init Cached DB data') + for key, entry in self.table_data_cache.items(): + syslog.syslog(syslog.LOG_DEBUG, ' %-20s : %s' % (key, entry)) + if self.config_mode == "unified": + for table, _ in self.table_handler_list: + table_list = self.config_db.get_table(table) + for key, data in table_list.items(): + syslog.syslog(syslog.LOG_DEBUG, 'config replay for table {} key {}'.format(table, key)) + upd_data = {} + for upd_key, upd_val in data.items(): + upd_data[upd_key] = CachedDataWithOp(upd_val, CachedDataWithOp.OP_ADD) + self.bgp_message.put((self.config_db.serialize_key(key), False, table, upd_data)) + upd_data_list = [] + self.__update_bgp(upd_data_list) + for table1, key1, data1 in upd_data_list: + table_key = ExtConfigDBConnector.get_table_key(table1, key1) + self.__update_cache_data(table_key, data1) + + def subscribe_all(self): + for table, hdlr in self.table_handler_list: + self.config_db.subscribe(table, hdlr) + + @staticmethod + def __run_command(table, command, daemons = None): + return g_run_command(table, command, True, daemons) + + def metadata_handler(self, table, key, data): + if key != 'localhost': + syslog.syslog(syslog.LOG_DEBUG, 'not localhost data update') + return + if data is None or 'bgp_asn' not in data: + self.metadata_asn = None + else: + self.metadata_asn = data['bgp_asn'] + + def bfd_handler(self, table, key, data): + syslog.syslog(syslog.LOG_INFO, '[bgp cfgd](bfd) value for {} changed to {}'.format(key, data)) + #get frr bfd session key + key_params = key.split('|') + cmd = 'peer {}'.format(key_params[0]) + if len(key_params) == 4 and key_params[3] == 'multihop': + cmd = cmd + ' multihop ' + if key_params[1] != 'null': + cmd = cmd + ' local-address ' + key_params[1] + if key_params[2] != 'null': + cmd = cmd + ' interface ' + key_params[2] + if not data: + #BFD peer is deleted + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no {}'".format(cmd) + self.__run_command(table, command) + else: + #create/update case + command = "vtysh -c 'configure terminal' -c 'bfd' -c '{}'".format(cmd) + for param in data: + if param == 'transmit_interval': + command = command + " -c 'transmit-interval {}'".format(data[param]) + elif param == 'receive_interval': + command = command + " -c 'receive-interval {}'".format(data[param]) + elif param == 'multiplier': + command = command + " -c 'detect-multiplier {}'".format(data[param]) + elif param == 'echo_mode' and data[param] == 'true': + command = command + " -c 'echo-mode'" + elif param == 'echo_interval': + command = command + " -c 'echo-interval {}'".format(data[param]) + elif param == 'label': + command = command + " -c 'label {}'".format(data[param]) + elif param == 'admin_status' and data[param] == 'up': + command = command + " -c 'no shutdown'" + elif param == 'admin_status' and data[param] == 'down': + command = command + " -c 'shutdown'" + self.__run_command(table, command) + + def vrf_handler(self, table, key, data): + syslog.syslog(syslog.LOG_INFO, '[bgp cfgd](vrf) value for {} changed to {}'.format(key, data)) + #get vrf key + key_params = key.split('|') + cmd = 'vrf {}'.format(key_params[0]) + if not data: + #VRF is deleted + command = "vtysh -c 'configure terminal' -c '{}'".format(cmd) + if key_params[0] in self.vrf_vni_map: + command = command + " -c 'no vni {}'".format(self.vrf_vni_map[key_params[0]]) + del self.vrf_vni_map[key_params[0]] + self.__run_command(table, command) + else: + #create/update case + command = "vtysh -c 'configure terminal' -c '{}'".format(cmd) + positive_execute = False + for param in data: + if param == 'vni': + if data[param] != '0': + command = command + " -c 'vni {}'".format(data[param]) + self.vrf_vni_map[key_params[0]] = data[param] + positive_execute = True + elif key_params[0] in self.vrf_vni_map: + command = command + " -c 'no vni {}'".format(self.vrf_vni_map[key_params[0]]) + del self.vrf_vni_map[key_params[0]] + positive_execute = True + if positive_execute == True: + self.__run_command(table, command) + + def __get_vrf_asn(self, vrf): + if vrf in self.bgp_asn: + return self.bgp_asn[vrf] + if vrf == self.DEFAULT_VRF and self.metadata_asn is not None: + return self.metadata_asn + return None + + def __delete_vrf_asn(self, vrf, table, data): + if vrf != self.DEFAULT_VRF and vrf not in self.bgp_asn: + syslog.syslog(syslog.LOG_ERR, 'non-default VRF {} was not configured'.format(vrf)) + return False + local_asn = self.__get_vrf_asn(vrf) + if local_asn is None: + syslog.syslog(syslog.LOG_ERR, 'failed to get local ASN of VRF {} for delete'.format(vrf)) + return False + command = "vtysh -c 'configure terminal' -c 'no router bgp {}".format(local_asn) + if vrf != self.DEFAULT_VRF: + command += " vrf {}'".format(vrf) + else: + command += "'" + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete local_asn for VRF %s' % vrf) + return False + if vrf in self.bgp_asn: + del(self.bgp_asn[vrf]) + for dkey, dval in data.items(): + # force delete all VRF instance attributes in cache + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_DELETE + return True + + def __cleanup_nbr_cache(self, vrf, nbr): + nbr_key = ExtConfigDBConnector.get_table_key('BGP_NEIGHBOR', + self.config_db.serialize_key((vrf, nbr))) + self.table_data_cache.pop(nbr_key, None) + for af in ['ipv4', 'ipv6']: + nbr_af_key = ExtConfigDBConnector.get_table_key('BGP_NEIGHBOR_AF', + self.config_db.serialize_key((vrf, nbr, af + '_unicast'))) + self.table_data_cache.pop(nbr_af_key, None) + + def __delete_vrf_neighbor(self, vrf, peer, data, is_peer_grp): + if is_peer_grp: + if vrf in self.bgp_peer_group and peer in self.bgp_peer_group[vrf]: + del(self.bgp_peer_group[vrf][peer]) + else: + if vrf in self.bgp_peer_group: + for _, peer_grp in self.bgp_peer_group[vrf].items(): + if peer in peer_grp.ref_nbrs: + peer_grp.ref_nbrs.remove(peer) + if not self.__peer_is_ip(peer) and vrf in self.bgp_intf_nbr and peer in self.bgp_intf_nbr[vrf]: + self.bgp_intf_nbr[vrf].remove(peer) + self.__cleanup_nbr_cache(vrf, peer) + for dkey, dval in data.items(): + # bypass cache update because cache entry was removed + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_NONE + + def __delete_pg_neighbors(self, vrf, pg_name): + syslog.syslog(syslog.LOG_DEBUG, + 'delete all associated neighbors of peer group %s of vrf %s from cache' % (pg_name, vrf)) + if vrf in self.bgp_peer_group and pg_name in self.bgp_peer_group[vrf]: + peer_grp = self.bgp_peer_group[vrf][pg_name] + for nbr in peer_grp.ref_nbrs: + if vrf in self.bgp_intf_nbr and nbr in self.bgp_intf_nbr[vrf]: + self.bgp_intf_nbr[vrf].remove(nbr) + self.__cleanup_nbr_cache(vrf, nbr) + peer_grp.ref_nbrs.clear() + + def __delete_route_map(self, map_name, seq_no, data): + if map_name in self.route_map and seq_no in self.route_map[map_name]: + del(self.route_map[map_name][seq_no]) + for dkey, dval in data.items(): + # force delete all neighbor attributes in cache + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_DELETE + + @staticmethod + def __vrf_based_table(table_name): + return table_name in BGPConfigDaemon.vrf_tables + + @staticmethod + def get_prefix_set_name(orig_name, table_name): + new_name = orig_name + if table_name == 'NEIGHBOR_SET': + new_name += '_neighbor' + elif table_name == 'NEXTHOP_SET': + new_name += '_nexthop' + return new_name + + def __apply_dep_vrf_table(self, vrf, table_name, *table_key, **extra_args): + if len(table_key) > 0: + new_key = (vrf,) + table_key + entry_list = {new_key: self.config_db.get_entry(table_name, new_key)} + else: + entry_list = self.config_db.get_table(table_name) + match_fn = extra_args.get('match', None) + for key, data in entry_list.items(): + if len(key) == 0 or key[0] != vrf: + continue + if match_fn is not None and not match_fn(data): + continue + syslog.syslog(syslog.LOG_DEBUG, 'attr re-apply for vrf {} table {} key {}'.format(vrf, table_name, key)) + upd_data = {} + for upd_key, upd_val in data.items(): + upd_data[upd_key] = CachedDataWithOp(upd_val, CachedDataWithOp.OP_ADD) + self.bgp_message.put((self.config_db.serialize_key(key), False, table_name, upd_data)) + + @staticmethod + def __nbr_impl_action(data, peer, is_pg): + if is_pg: + chk_attrs = ['asn'] + elif BGPConfigDaemon.__peer_is_ip(peer): + chk_attrs = ['asn', 'peer_group_name'] + else: + chk_attrs = ['peer_group_name'] + for attr in chk_attrs: + val = data.get(attr, None) + if val is not None: + if val.op == CachedDataWithOp.OP_ADD: + return 'apply' + elif val.op == CachedDataWithOp.OP_DELETE: + return 'delete' + return None + + def __apply_config_op_success(self, data, cfg_data={}): + op_list = [ CachedDataWithOp.OP_NONE, CachedDataWithOp.OP_ADD, + CachedDataWithOp.OP_DELETE, CachedDataWithOp.OP_UPDATE ] + if len(cfg_data) == 0: + for dkey, dval in data.items(): + dval.status = CachedDataWithOp.STAT_SUCC + else : + for dkey, dval in data.items(): + if dkey in cfg_data.keys(): + if cfg_data[dkey] not in op_list : + syslog.syslog(syslog.LOG_INFO, 'Invalid op {} received'.format(cfg_data[dkey])) + continue + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = cfg_data[dkey] + syslog.syslog(syslog.LOG_INFO, 'apply_config_op_success on {}.'.format(data)) + + def __apply_config_delete_success(self, data): + for dkey, dval in data.items(): + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_DELETE + + def __ospf_delete (self, data): + for dkey, dval in data.items(): + # force delete all peer attributes in cache + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_DELETE + + def __ospf_apply_config(self, data, rmapoper, metricoper, metrictypeoper, alwaysoper, acclistoper): + for dkey, dval in data.items(): + + if 'route-map' == dkey: + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = rmapoper + + if 'metric' == dkey: + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = metricoper + + if 'metric-type' == dkey: + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = metrictypeoper + + if 'always' == dkey: + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = alwaysoper + + if 'access-list' == dkey: + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = acclistoper + + def __delete_bfd_peer(self, data): + for dkey, dval in data.items(): + # force delete all peer attributes in cache + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_DELETE + + def __bfd_handle_delete (self, data): + cmd_suffix = "" + if 'desired-minimum-tx-interval' in data: + dval = data['desired-minimum-tx-interval'] + cmd_suffix = "transmit-interval 300" + elif 'required-minimum-receive' in data: + dval = data['required-minimum-receive'] + cmd_suffix = "receive-interval 300" + elif 'detection-multiplier' in data: + dval = data['detection-multiplier'] + cmd_suffix = "detect-multiplier 3" + elif 'desired-minimum-echo-receive' in data: + dval = data['desired-minimum-echo-receive'] + cmd_suffix = "echo-interval 300" + if cmd_suffix != "": + return cmd_suffix, dval.op + + return cmd_suffix, None + + def __update_bgp(self, data_list): + while not self.bgp_message.empty(): + key, del_table, table, data = self.bgp_message.get() + if table == 'STATIC_ROUTE' and len(key.split('|')) == 1: + key = self.DEFAULT_VRF + '|' + key + key_list = key.split('|', 1) + if table == 'BGP_NEIGHBOR' and len(key_list) == 1: + # bypass non-compatible neighbor table + continue + data_list.append((table, key, data)) + if len(key_list) > 1: + key = key_list[1] + else: + key = None + prefix = key_list[0] + syslog.syslog(syslog.LOG_INFO, 'value for table {} prefix {} key {} changed to {}'.format(table, prefix, key, data)) + if self.__vrf_based_table(table): + vrf = prefix + local_asn = self.__get_vrf_asn(vrf) + if local_asn is None and (table != 'BGP_GLOBALS' or 'local_asn' not in data): + syslog.syslog(syslog.LOG_DEBUG, 'ignore table {} update because local_asn for VRF {} was not configured'.\ + format(table, vrf)) + continue + if table in self.tbl_to_key_map: + tbl_key = None + if table == 'BGP_NEIGHBOR_AF' or table == 'BGP_PEER_GROUP_AF' and key is not None: + _, af_ip_type = key.split('|') + tbl_key, _ = af_ip_type.lower().split('_') + tbl_key = {'admin_status': tbl_key} + elif table == 'ROUTE_MAP': + tbl_key = {} + for attr_name, table_name in {'match_prefix_set': 'PREFIX', 'match_next_hop_set': 'PREFIX'}.items(): + if attr_name in data: + pfx_set_name = self.get_prefix_set_name(data[attr_name].data, table_name) + if pfx_set_name in self.prefix_set_list: + af_mode = self.prefix_set_list[pfx_set_name].af + tbl_key[attr_name] = 'ipv4' if af_mode == socket.AF_INET else 'ipv6' + elif table == 'STATIC_ROUTE': + af_id, new_key = IpNextHopSet.get_af_norm_prefix(key) + if new_key is not None: + key = new_key + tbl_key = {'ip_prefix': ('ipv4' if af_id == socket.AF_INET else 'ipv6')} + key_map = BGPKeyMapList(self.tbl_to_key_map[table], table, tbl_key) + else: + key_map = None + if table == 'BGP_GLOBALS': + if not del_table: + if 'local_asn' in data: + dval = data['local_asn'] + if dval.op == CachedDataWithOp.OP_DELETE: + # delete local_asn will delete whole VRF instance + self.__delete_vrf_asn(vrf, table, data) + continue + prog_asn = True + if dval.op == CachedDataWithOp.OP_UPDATE: + syslog.syslog(syslog.LOG_ERR, 'local_asn could not be modified') + prog_asn = False + if dval.op == CachedDataWithOp.OP_NONE: + prog_asn = False + if prog_asn: + command = "vtysh -c 'configure terminal' -c 'router bgp {} vrf {}' -c 'no bgp default ipv4-unicast'".format(dval.data, vrf) + if self.__run_command(table, command): + syslog.syslog(syslog.LOG_DEBUG, 'set local_asn %s to VRF %s, re-apply all VRF related tables' % (dval.data, vrf)) + self.bgp_asn[vrf] = dval.data + self.__apply_dep_vrf_table(vrf, 'ROUTE_REDISTRIBUTE') + dval.status = CachedDataWithOp.STAT_SUCC + else: + syslog.syslog(syslog.LOG_ERR, 'failed to set local_asn %s to VRF %s' % (dval.data, vrf)) + else: + dval.status = CachedDataWithOp.STAT_SUCC + if 'confed_peers' in data: + self.upd_confed_peers = copy.copy(self.bgp_confed_peers.get(vrf, set())) + local_asn = self.__get_vrf_asn(vrf) + if local_asn is None: + syslog.syslog(syslog.LOG_ERR, 'local ASN for VRF %s was not configured' % vrf) + continue + cmd_prefix = ['configure terminal', 'router bgp {} vrf {}'.format(local_asn, vrf)] + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP global config command') + continue + if 'confed_peers' in data: + self.bgp_confed_peers[vrf] = copy.copy(self.upd_confed_peers) + else: + self.__delete_vrf_asn(vrf, table, data) + elif table == 'BGP_GLOBALS_AF': + af, ip_type = key.lower().split('_') + #this is to temporarily make table cache key accessible to key_map handler function + self.tmp_cache_key = 'BGP_GLOBALS_AF&&{}|{}'.format(vrf, key.lower()) + syslog.syslog(syslog.LOG_INFO, 'Set address family global to {} {} cache-key to {}'.format(af, ip_type, self.tmp_cache_key)) + cmd_prefix = ['configure terminal', + 'router bgp {} vrf {}'.format(local_asn, vrf), + 'address-family {} {}'.format(af, ip_type)] + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP global AF config command') + continue + self.tmp_cache_key = '' + elif table == 'BGP_GLOBALS_LISTEN_PREFIX': + syslog.syslog(syslog.LOG_INFO, 'Set BGP listen prefix {}'.format(key)) + cmd_prefix = ['configure terminal', + 'router bgp {} vrf {}'.format(local_asn, vrf)] + if not key_map.run_command(self, table, data, cmd_prefix, key): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP global listen prefix config command') + continue + elif table == 'BGP_NEIGHBOR' or table == 'BGP_PEER_GROUP': + is_peer_group = table == 'BGP_PEER_GROUP' + if not del_table: + if is_peer_group: + # if peer group is not created, create it before setting other attributes + if key not in self.bgp_peer_group.setdefault(vrf, {}): + command = "vtysh -c 'configure terminal' -c 'router bgp {} vrf {}' ".format(local_asn, vrf) + command += "-c 'neighbor {} peer-group'".format(key) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create peer-group %s for VRF %s' % (key, vrf)) + continue + self.bgp_peer_group[vrf][key] = BGPPeerGroup(vrf) + elif not self.__peer_is_ip(key): + if key not in self.bgp_intf_nbr.setdefault(vrf, set()): + command = "vtysh -c 'configure terminal' -c 'router bgp {} vrf {}' ".format(local_asn, vrf) + command += "-c 'neighbor {} interface'".format(key) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create neighbor of interface %s for VRF %s' % (key, vrf)) + continue + self.bgp_intf_nbr[vrf].add(key) + bfd_val = data.get('bfd', None) + if (bfd_val is not None and (bfd_val.op == CachedDataWithOp.OP_ADD or bfd_val.op == CachedDataWithOp.OP_UPDATE) and + bfd_val.data == 'true'): + cp_chk_val = data.get('bfd_check_ctrl_plane_failure', None) + if cp_chk_val is not None and cp_chk_val.op == CachedDataWithOp.OP_NONE and cp_chk_val.data == 'true': + cp_chk_val.op = CachedDataWithOp.OP_ADD + cmd_prefix = ['configure terminal', 'router bgp {} vrf {}'.format(local_asn, vrf)] + if not key_map.run_command(self, table, data, cmd_prefix, key): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP neighbor config command') + continue + if ('peer_group_name' in data and + (data['peer_group_name'].op == CachedDataWithOp.OP_ADD or + data['peer_group_name'].op == CachedDataWithOp.OP_DELETE)): + dval = data['peer_group_name'] + if vrf not in self.bgp_peer_group or dval.data not in self.bgp_peer_group[vrf]: + # should not happen because vtysh command will fail if peer_group not exists + syslog.syslog(syslog.LOG_ERR, 'invalid peer-group %s was referenced' % dval.data) + continue + peer_grp = self.bgp_peer_group[vrf][dval.data] + if dval.op == CachedDataWithOp.OP_ADD: + peer_grp.ref_nbrs.add(key) + else: + peer_grp.ref_nbrs.discard(key) + nbr_action = self.__nbr_impl_action(data, key, is_peer_group) + if nbr_action == 'delete': + if not is_peer_group and self.__peer_is_ip(key): + # delete asn or peer_group will delete all neighbor + self.__delete_vrf_neighbor(vrf, key, data, False) + elif is_peer_group: + # clear associated neighbor list in cache + self.__delete_pg_neighbors(vrf, key) + elif nbr_action == 'apply': + if is_peer_group: + syslog.syslog(syslog.LOG_DEBUG, 'apply attributes to FRR for vrf %s peer_group %s' % (vrf, key)) + match_pg = lambda data: data.get('peer_group', None) == key + self.__apply_dep_vrf_table(vrf, 'BGP_GLOBALS_LISTEN_PREFIX', match = match_pg) + match_nbr = lambda data: data.get('peer_group_name', None) == key + self.__apply_dep_vrf_table(vrf, 'BGP_NEIGHBOR', match = match_nbr) + else: + for af in ['ipv4_unicast', 'ipv6_unicast']: + syslog.syslog(syslog.LOG_DEBUG, 'apply attributes to FRR for vrf %s neighbor %s af %s' % (vrf, key, af)) + self.__apply_dep_vrf_table(vrf, 'BGP_NEIGHBOR_AF', key, af) + else: + # Neighbor is deleted + if is_peer_group: + # clear associated neighbor list in cache + self.__delete_pg_neighbors(vrf, key) + command = "vtysh -c 'configure terminal' -c 'router bgp {} vrf {}' -c 'no neighbor {}'".\ + format(local_asn, vrf, key) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete VRF %s bgp neigbor %s' % (vrf, key)) + self.__delete_vrf_neighbor(vrf, key, data, is_peer_group) + elif table == 'BGP_NEIGHBOR_AF' or table == 'BGP_PEER_GROUP_AF': + nbr, af_type = key.split('|') + af, ip_type = af_type.lower().split('_') + syslog.syslog(syslog.LOG_INFO, 'Set address family for neighbor {} to {} {}'.format(nbr, af, ip_type)) + cmd_prefix = ['configure terminal', + 'router bgp {} vrf {}'.format(local_asn, vrf), + 'address-family {} {}'.format(af, ip_type)] + if not key_map.run_command(self, table, data, cmd_prefix, nbr): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP neighbor AF config command') + continue + elif table == 'COMMUNITY_SET' or table == 'EXTENDED_COMMUNITY_SET': + comm_set_name = prefix + syslog.syslog(syslog.LOG_INFO, 'Set community set {} for table {}'.format(comm_set_name, table)) + cmd_prefix = ['configure terminal'] + if not key_map.run_command(self, table, data, cmd_prefix, comm_set_name): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP community config command') + continue + extended = (table != 'COMMUNITY_SET') + comm_set = (self.comm_set_list if not extended else self.extcomm_set_list).setdefault(comm_set_name, + CommunityList(comm_set_name, extended)) + if del_table: + del((self.comm_set_list if not extended else self.extcomm_set_list)[comm_set_name]) + else: + for dkey, dval in data.items(): + if dval.op == CachedDataWithOp.OP_DELETE: + upd_val = None + else: + upd_val = dval.data + comm_set.db_data_to_attr(dkey, upd_val) + elif table == 'PREFIX_SET': + pfx_set_name = prefix + if not del_table: + if pfx_set_name in self.prefix_set_list: + syslog.syslog(syslog.LOG_DEBUG, 'prefix-set %s exists with af %d' % + (pfx_set_name, self.prefix_set_list[pfx_set_name].af)) + continue + if 'mode' not in data: + syslog.syslog(syslog.LOG_ERR, 'no mode given for prefix-set %s' % pfx_set_name) + continue + set_mode = data['mode'].data.lower() + self.prefix_set_list[pfx_set_name] = MatchPrefixList(set_mode) + else: + if pfx_set_name in self.prefix_set_list: + del(self.prefix_set_list[pfx_set_name]) + for _, dval in data.items(): + dval.status = CachedDataWithOp.STAT_SUCC + elif table == 'PREFIX' or table == 'NEIGHBOR_SET' or table == 'NEXTHOP_SET': + pfx_set_name = self.get_prefix_set_name(prefix, table) + if table == 'PREFIX': + if pfx_set_name not in self.prefix_set_list: + syslog.syslog(syslog.LOG_ERR, 'could not find prefix-set %s from cache' % pfx_set_name) + continue + ip_pfx, len_range = key.split('|') + if len_range == 'exact': + len_range = None + pfx_action = data.get('action', None) + if pfx_action is None or pfx_action.op == CachedDataWithOp.OP_NONE: + continue + af = self.prefix_set_list[pfx_set_name].af + if af == socket.AF_INET: + # use table daemons setting + daemons = None + else: + daemons = ['bgpd', 'zebra'] + if pfx_action.op == CachedDataWithOp.OP_DELETE or pfx_action.op == CachedDataWithOp.OP_UPDATE: + del_pfx, pfx_idx = self.prefix_set_list[pfx_set_name].get_prefix(ip_pfx, len_range) + if del_pfx is None: + syslog.syslog(syslog.LOG_ERR, 'prefix of {} with range {} not found from prefix-set {}'.\ + format(ip_pfx, len_range, pfx_set_name)) + continue + command = "vtysh -c 'configure terminal' -c 'no {} prefix-list {} {}'".\ + format(('ip' if af == socket.AF_INET else 'ipv6'), pfx_set_name, str(del_pfx)) + if not self.__run_command(table, command, daemons): + syslog.syslog(syslog.LOG_ERR, 'failed to delete prefix %s with range %s from set %s' % + (ip_pfx, len_range, pfx_set_name)) + continue + del(self.prefix_set_list[pfx_set_name][pfx_idx]) + if pfx_action.op == CachedDataWithOp.OP_ADD or pfx_action.op == CachedDataWithOp.OP_UPDATE: + try: + add_pfx = self.prefix_set_list[pfx_set_name].add_prefix(ip_pfx, len_range, pfx_action.data) + except ValueError: + syslog.syslog(syslog.LOG_ERR, 'failed to update prefix-set %s in cache with prefix %s range %s' % + (pfx_set_name, ip_pfx, len_range)) + continue + command = "vtysh -c 'configure terminal' -c '{} prefix-list {} {}'".\ + format(('ip' if af == socket.AF_INET else 'ipv6'), pfx_set_name, str(add_pfx)) + if not self.__run_command(table, command, daemons): + syslog.syslog(syslog.LOG_ERR, 'failed to add prefix %s with range %s to set %s' % + (ip_pfx, len_range, pfx_set_name)) + # revert cached update on failure + del_pfx, pfx_idx = self.prefix_set_list[pfx_set_name].get_prefix(ip_pfx, len_range) + if del_pfx is not None: + del(self.prefix_set_list[pfx_set_name][pfx_idx]) + continue + else: + if 'address' not in data or data['address'].op == CachedDataWithOp.OP_NONE: + continue + ip_addr_list = data['address'].data + if pfx_set_name in self.prefix_set_list: + af = self.prefix_set_list[pfx_set_name].af + command = "vtysh -c 'configure terminal' -c 'no {} prefix-list {}'".\ + format(('ip' if af == socket.AF_INET else 'ipv6'), pfx_set_name) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete existing prefix-set {}'.format(pfx_set_name)) + continue + del(self.prefix_set_list[pfx_set_name]) + if not del_table: + prefix_set = MatchPrefixList() + for ip_addr in ip_addr_list: + try: + prefix_set.add_prefix(ip_addr) + except ValueError: + continue + for prefix in prefix_set: + command = "vtysh -c 'configure terminal' -c '{} prefix-list {} {}'".\ + format(('ip' if prefix_set.af == socket.AF_INET else 'ipv6'), pfx_set_name, str(prefix)) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete existing prefix-set {}'.format(pfx_set_name)) + continue + self.prefix_set_list[pfx_set_name] = prefix_set + for _, dval in data.items(): + dval.status = CachedDataWithOp.STAT_SUCC + elif table == 'AS_PATH_SET': + as_set_name = prefix + syslog.syslog(syslog.LOG_INFO, 'Set AS path set {} for table {}'.format(as_set_name, table)) + cmd_prefix = ['configure terminal'] + if not key_map.run_command(self, table, data, cmd_prefix, as_set_name): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP AS path set config command') + continue + as_set_data = data.get('as_path_set_member', None) + if as_set_data is not None and (as_set_data.op == CachedDataWithOp.OP_DELETE or len(as_set_data.data) == 0): + del_table = True + if del_table: + self.as_path_set_list.pop(as_set_name, None) + elif as_set_data is not None: + self.as_path_set_list[as_set_name] = as_set_data.data[:] + elif table == 'TAG_SET': + tag_set_name = prefix + if not del_table and 'tag_value' not in data: + continue + tag_set_data = data.get('tag_value', None) + if tag_set_data is not None and (tag_set_data.op == CachedDataWithOp.OP_DELETE or len(tag_set_data.data) == 0): + del_table = True + if not del_table: + self.tag_set_list[tag_set_name] = set(tag_set_data.data) + else: + self.tag_set_list.pop(tag_set_name, None) + for _, dval in data.items(): + dval.status = CachedDataWithOp.STAT_SUCC + elif table == 'BGP_GLOBALS_EVPN_VNI': + af_type, vni = key.split('|') + af, ip_type = af_type.lower().split('_') + #this is to temporarily make table cache key accessible to key_map handler function + self.tmp_cache_key = 'BGP_GLOBALS_EVPN_VNI&&{}|{}|{}'.format(vrf, af_type, vni) + syslog.syslog(syslog.LOG_INFO, 'Set address family for VNI {} to {} {} cache-key to {}'.format(vni, af, ip_type, self.tmp_cache_key)) + cmd_prefix = ['configure terminal', + 'router bgp {} vrf {}'.format(local_asn, vrf), + 'address-family {} {}'.format(af, ip_type), + 'vni {}'.format(vni)] + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP L2VPN_EVPN VNI config command') + continue + self.tmp_cache_key = '' + if del_table: + cmd = "vtysh -c 'configure terminal'" + cmd += " -c 'router bgp {} vrf {}'".format(local_asn, vrf) + cmd += " -c 'address-family {} {}'".format(af, ip_type) + cmd += " -c 'no vni {}'".format(vni) + if not self.__run_command(table, cmd): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP L2VPN_EVPN VNI unconfig command') + continue + else: + if not data: + cmd = "vtysh -c 'configure terminal'" + cmd += " -c 'router bgp {} vrf {}'".format(local_asn, vrf) + cmd += " -c 'address-family {} {}'".format(af, ip_type) + cmd += " -c 'vni {}'".format(vni) + if not self.__run_command(table, cmd): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP L2VPN_EVPN VNI config command') + continue + elif table == 'BGP_GLOBALS_EVPN_RT': + af_type, rt = key.split('|') + af, ip_type = af_type.lower().split('_') + nostr = "no " if del_table else "" + syslog.syslog(syslog.LOG_INFO, 'Set address family for RT {} to {} {}'.format(rt, af, ip_type)) + cmd = "vtysh -c 'configure terminal'" + cmd += " -c 'router bgp {} vrf {}'".format(local_asn, vrf) + cmd += " -c 'address-family {} {}'".format(af, ip_type) + cmd += " -c '{}route-target {} {}'".format(nostr,data['route-target-type'].data, rt) + cache_tbl_key = 'BGP_GLOBALS_EVPN_RT&&{}|L2VPN_EVPN|{}'.format(vrf, rt) + if not del_table and cache_tbl_key in self.table_data_cache.keys(): + new_rttype = data['route-target-type'].data + cache_tbl_data = self.table_data_cache[cache_tbl_key] + if 'route-target-type' in cache_tbl_data: + old_rttype = cache_tbl_data['route-target-type'] + if new_rttype == "export": + if old_rttype == "import" or old_rttype == "both": + cmd += " -c 'no route-target import {}'".format(rt) + if new_rttype == "import": + if old_rttype == "export" or old_rttype == "both": + cmd += " -c 'no route-target export {}'".format(rt) + if not self.__run_command(table, cmd): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP L2VPN_EVPN RT config command') + continue + else: + data['route-target-type'].status = CachedDataWithOp.STAT_SUCC + elif table == 'BGP_GLOBALS_EVPN_VNI_RT': + af_type, vni, rt = key.split('|') + af, ip_type = af_type.lower().split('_') + nostr = "no " if del_table else "" + syslog.syslog(syslog.LOG_INFO, 'Set address family for VNI {} RT {} to {} {}'.format(vni, rt, af, ip_type)) + cmd = "vtysh -c 'configure terminal'" + cmd += " -c 'router bgp {} vrf {}'".format(local_asn, vrf) + cmd += " -c 'address-family {} {}'".format(af, ip_type) + cmd += " -c 'vni {}'".format(vni) + cmd += " -c '{}route-target {} {}'".format(nostr,data['route-target-type'].data, rt) + cache_tbl_key = 'BGP_GLOBALS_EVPN_VNI_RT&&{}|L2VPN_EVPN|{}|{}'.format(vrf, vni, rt) + if not del_table and cache_tbl_key in self.table_data_cache.keys(): + new_rttype = data['route-target-type'].data + cache_tbl_data = self.table_data_cache[cache_tbl_key] + if 'route-target-type' in cache_tbl_data: + old_rttype = cache_tbl_data['route-target-type'] + if new_rttype == "export": + if old_rttype == "import" or old_rttype == "both": + cmd += " -c 'no route-target import {}'".format(rt) + if new_rttype == "import": + if old_rttype == "export" or old_rttype == "both": + cmd += " -c 'no route-target export {}'".format(rt) + if not self.__run_command(table, cmd): + syslog.syslog(syslog.LOG_ERR, 'failed running BGP L2VPN_EVPN VNI RT config command') + continue + else: + data['route-target-type'].status = CachedDataWithOp.STAT_SUCC + elif table == 'ROUTE_MAP': + map_name = prefix + seq_no = key + if not del_table: + if 'route_operation' in data: + dval = data['route_operation'] + if dval.op != CachedDataWithOp.OP_NONE: + enable = (dval.op != CachedDataWithOp.OP_DELETE) + no_arg = CommandArgument(self, enable) + command = "vtysh -c 'configure terminal' -c '{:no-prefix}route-map {} {} {}'".\ + format(no_arg, map_name, dval.data, seq_no) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to configure route-map {} seq {}'.format(map_name, seq_no)) + continue + if dval.op == CachedDataWithOp.OP_DELETE: + self.__delete_route_map(map_name, seq_no, data) + continue + self.route_map.setdefault(map_name, {})[seq_no] = dval.data + for k, v in data.items(): + if v.op == CachedDataWithOp.OP_NONE: + v.op = CachedDataWithOp.OP_UPDATE + dval.status = CachedDataWithOp.STAT_SUCC + if map_name not in self.route_map or seq_no not in self.route_map[map_name]: + syslog.syslog(syslog.LOG_ERR, 'route-map {} seq {} not found for update'.format(map_name, seq_no)) + continue + cmd_prefix = ['configure terminal', + 'route-map {} {} {}'.format(map_name, self.route_map[map_name][seq_no], seq_no)] + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running route-map config command') + continue + else: + if map_name not in self.route_map or seq_no not in self.route_map[map_name]: + syslog.syslog(syslog.LOG_ERR, 'route-map {} seq {} not found for delete'.format(map_name, seq_no)) + continue + command = "vtysh -c 'configure terminal' -c 'no route-map {} {} {}'".\ + format(map_name, self.route_map[map_name][seq_no], seq_no) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed running route-map delete command') + continue + self.__delete_route_map(map_name, seq_no, data) + elif table == 'ROUTE_REDISTRIBUTE': + src_proto, dst_proto, af = key.split('|') + if af == 'ipv6' and src_proto == 'ospf3': + src_proto = 'ospf6' + ip_type = 'unicast' + syslog.syslog(syslog.LOG_INFO, 'Set route distribute for src_proto {} dst_proto {} {}'.\ + format(src_proto, dst_proto, af, ip_type)) + if dst_proto != 'bgp': + syslog.syslog(syslog.LOG_ERR, 'only bgp could be used as dst protocol, but {} was given'.format(dst_proto)) + continue + op = CachedDataWithOp.OP_DELETE if del_table else CachedDataWithOp.OP_UPDATE + data['protocol'] = CachedDataWithOp(src_proto, op) + cmd_prefix = ['configure terminal', + 'router bgp {} vrf {}'.format(local_asn, vrf), + 'address-family {} {}'.format(af, ip_type)] + ret_val = key_map.run_command(self, table, data, cmd_prefix) + del(data['protocol']) + if not ret_val: + syslog.syslog(syslog.LOG_ERR, 'failed running BGP route redistribute config command') + continue + elif table == 'BGP_GLOBALS_AF_AGGREGATE_ADDR' or table == 'BGP_GLOBALS_AF_NETWORK': + af_type, ip_prefix = key.split('|') + af, ip_type = af_type.lower().split('_') + norm_ip_prefix = MatchPrefix.normalize_ip_prefix((socket.AF_INET if af == 'ipv4' else socket.AF_INET6), ip_prefix) + if norm_ip_prefix is None: + syslog.syslog(syslog.LOG_ERR, 'invalid IP prefix format %s for af %s' % (ip_prefix, af)) + continue + syslog.syslog(syslog.LOG_INFO, 'Set address family for IP prefix {} to {} {}'.format(norm_ip_prefix, af, ip_type)) + op = CachedDataWithOp.OP_DELETE if del_table else CachedDataWithOp.OP_UPDATE + data['ip_prefix'] = CachedDataWithOp(norm_ip_prefix, op) + cmd_prefix = ['configure terminal', + 'router bgp {} vrf {}'.format(local_asn, vrf), + 'address-family {} {}'.format(af, ip_type)] + ret_val = key_map.run_command(self, table, data, cmd_prefix, vrf, af) + del(data['ip_prefix']) + if not ret_val: + syslog.syslog(syslog.LOG_ERR, 'failed running BGP IP prefix AF config command') + continue + if table == 'BGP_GLOBALS_AF_AGGREGATE_ADDR': + if not del_table: + aggr_obj = AggregateAddr() + for attr in ['as_set', 'summary_only']: + if attr in data and data[attr].op != CachedDataWithOp.OP_DELETE and data[attr].data == 'true': + setattr(aggr_obj, attr, True) + self.af_aggr_list.setdefault(vrf, {})[norm_ip_prefix] = aggr_obj + else: + if vrf in self.af_aggr_list: + self.af_aggr_list[vrf].pop(norm_ip_prefix, None) + + elif table == 'BFD_PEER_SINGLE_HOP': + key = prefix + '|' + key + remoteaddr, interface, vrf, localaddr = key.split('|') + if not del_table: + if not 'null' in localaddr: + syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {} {}'.format(remoteaddr, vrf, interface, localaddr)) + + suffix_cmd, oper = self.__bfd_handle_delete (data) + if suffix_cmd and oper == CachedDataWithOp.OP_DELETE: + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'peer {} local-address {} vrf {} interface {}' -c '{}'".\ + format(remoteaddr, localaddr, vrf, interface, suffix_cmd) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) + continue + else: + cmd_prefix = ['configure terminal', + 'bfd', + 'peer {} local-address {} vrf {} interface {}'.format(remoteaddr, localaddr, vrf, interface)] + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running BFD single-hop config command') + continue + + else: + syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {}'.format(remoteaddr, vrf, interface)) + + suffix_cmd, oper = self.__bfd_handle_delete (data) + + if suffix_cmd and oper == CachedDataWithOp.OP_DELETE: + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'peer {} vrf {} interface {}' -c '{}'".\ + format(remoteaddr, vrf, interface, suffix_cmd) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) + continue + else: + syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {}'.format(remoteaddr, vrf, interface)) + cmd_prefix = ['configure terminal', + 'bfd', + 'peer {} vrf {} interface {}'.format(remoteaddr, vrf, interface)] + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running BFD single-hop config command') + continue + else: + if 'local-address' in data: + dval = data['local-address'] + localaddr = dval.data + syslog.syslog(syslog.LOG_INFO, 'Delete BFD single hop to {} {} {}'.format(remoteaddr, vrf, interface, localaddr)) + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} local-address {} vrf {} interface {}'".\ + format(remoteaddr, localaddr, vrf, interface) + else: + syslog.syslog(syslog.LOG_INFO, 'Delete BFD single hop to {} {} {}'.format(remoteaddr, vrf, interface)) + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} vrf {} interface {}'".\ + format(remoteaddr, vrf, interface) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) + continue + self.__delete_bfd_peer(data) + elif table == 'BFD_PEER_MULTI_HOP': + key = prefix + '|' + key + remoteaddr, interface, vrf, localaddr = key.split('|') + if not del_table: + syslog.syslog(syslog.LOG_INFO, 'Set BFD multi hop to {} {} {} {}'.format(remoteaddr, interface, vrf, localaddr)) + suffix_cmd, oper = self.__bfd_handle_delete (data) + if suffix_cmd and oper == CachedDataWithOp.OP_DELETE: + if not 'null' in interface: + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'peer {} local-address {} vrf {} interface {}' -c '{}'".\ + format(remoteaddr, localaddr, vrf, interface, suffix_cmd) + else: + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'peer {} local-address {} vrf {}' -c '{}'".\ + format(remoteaddr, localaddr, vrf, suffix_cmd) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) + continue + else: + if not 'null' in interface: + cmd_prefix = ['configure terminal', + 'bfd', + 'peer {} vrf {} multihop local-address {} interface {}'.format(remoteaddr, vrf, localaddr, interface)] + else: + cmd_prefix = ['configure terminal', + 'bfd', + 'peer {} vrf {} multihop local-address {}'.format(remoteaddr, vrf, localaddr)] + + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running BFD multi-hop config command') + continue + else: + syslog.syslog(syslog.LOG_INFO, 'Delete BFD multi hop to {} {} {} {}'.format(remoteaddr, vrf, localaddr, interface)) + if not 'null' in interface: + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} vrf {} multihop local-address {} interface {}'".\ + format(remoteaddr, vrf, localaddr, interface) + else: + command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} vrf {} multihop local-address {}'".\ + format(remoteaddr, vrf, localaddr) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete multihop peer {}'.format(key)) + continue + self.__delete_bfd_peer(data) + elif table == 'IP_SLA': + sla_id = prefix + icmp_config = False + tcp_config = False + cmd_prefix = ['configure terminal'] + ipsla_table = self.config_db.get_table('IP_SLA') + syslog.syslog(syslog.LOG_INFO, 'Config ip sla data {}'.format(data)) + found_in_configdb = False + for key, entry in ipsla_table.items(): + ipsla_id = key + if sla_id == ipsla_id: + found_in_configdb = True + break + syslog.syslog(syslog.LOG_INFO, 'Config ip sla found_in_configdb {}'.format(found_in_configdb)) + if 'icmp_source_interface' in data or 'icmp_source_ip' in data or 'icmp_size' in data or 'icmp_dst_ip' in data or 'icmp_vrf' in data or 'icmp_ttl' in data or 'icmp_tos' in data: + cmd_prefix = ['configure terminal','ip sla {}'.format(sla_id)] + icmp_config = True + for key, entry in ipsla_table.items(): + ipsla_id = key + if sla_id == ipsla_id: + if 'icmp_dst_ip' in entry: + icmp_cmd = ("icmp", "echo") + icmp_cmd_str = "-".join(icmp_cmd) + icmp_cmd_mode = icmp_cmd_str + " " + entry['icmp_dst_ip'] + syslog.syslog(syslog.LOG_INFO, 'Data: icmp_cmd_str %s icmp_cmd_mode %s' % (icmp_cmd_str, icmp_cmd_mode)) + + cmd_prefix = ['configure terminal','ip sla {}'.format(sla_id), icmp_cmd_mode] + chk_icmp_attrs = ['icmp_source_interface', 'icmp_source_ip', 'icmp_size', 'icmp_vrf', 'icmp_tos', 'icmp_ttl'] + chk_icmp_attrs_dict = {'icmp_source_interface':'source-interface ', 'icmp_source_ip':'source-address ', 'icmp_size':'request-data-size ', 'icmp_vrf':'source-vrf ', 'icmp_tos':'tos ', 'icmp_ttl':'ttl '} + for attr in chk_icmp_attrs: + if attr in data and data[attr].op != CachedDataWithOp.OP_DELETE: + command = "vtysh -c 'configure terminal' -c 'ip sla {}' -c '{}' -c '{} {}'".\ + format(sla_id, icmp_cmd_mode, chk_icmp_attrs_dict[attr], data[attr].data) + syslog.syslog(syslog.LOG_INFO, 'Execute Icmp Cmd {}'.format(command)) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to add icmp config for ip sla {}'.format(sla_id)) + continue + + syslog.syslog(syslog.LOG_INFO, 'Done with Icmp {}'.format(sla_id)) + if not key_map.run_command(self, table, data, cmd_prefix, sla_id): + syslog.syslog(syslog.LOG_ERR, 'failed running ip sla command') + continue + if 'tcp_source_interface' in data or 'tcp_source_port' in data or 'tcp_source_ip' in data or 'tcp_dst_ip' in data or 'tcp_dst_port' in data or 'tcp_vrf' in data or 'tcp_ttl' in data or 'tcp_tos' in data: + cmd_prefix = ['configure terminal','ip sla {}'.format(sla_id)] + tcp_config = True + for key, entry in ipsla_table.items(): + ipsla_id = key + if sla_id == ipsla_id: + if 'tcp_dst_ip' in entry and 'tcp_dst_port' in entry: + tcp_cmd = ("tcp", "connect") + tcp_cmd_str = "-".join(tcp_cmd) + tcp_cmd_mode = tcp_cmd_str + " " + entry['tcp_dst_ip'] + " port " + entry['tcp_dst_port'] + syslog.syslog(syslog.LOG_INFO, 'Init Config DB Data: tcp_cmd_str %s tcp_cmd_mode %s' % (tcp_cmd_str, tcp_cmd_mode)) + cmd_prefix = ['configure terminal','ip sla {}'.format(sla_id), tcp_cmd_mode] + chk_tcp_attrs = ['tcp_source_interface', 'tcp_source_ip', 'tcp_source_port', 'tcp_vrf', 'tcp_tos', 'tcp_ttl'] + chk_tcp_attrs_dict = {'tcp_source_interface':'source-interface ', 'tcp_source_ip':'source-address ', 'tcp_source_port':'source-port ', 'tcp_vrf':'source-vrf ', 'tcp_tos':'tos ', 'tcp_ttl':'ttl '} + for attr in chk_tcp_attrs: + if attr in data and data[attr].op != CachedDataWithOp.OP_DELETE: + command = "vtysh -c 'configure terminal' -c 'ip sla {}' -c '{}' -c '{} {}'".\ + format(sla_id, tcp_cmd_mode, chk_tcp_attrs_dict[attr], data[attr].data) + syslog.syslog(syslog.LOG_INFO, 'Execute Tcp Cmd {}'.format(command)) + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to add Tcp config for ip sla {}'.format(sla_id)) + continue + + syslog.syslog(syslog.LOG_INFO, 'Done with Tcp {}'.format(sla_id)) + if not key_map.run_command(self, table, data, cmd_prefix, sla_id): + syslog.syslog(syslog.LOG_ERR, 'failed running ip sla command') + continue + if 'frequency' in data or 'threshold' in data or 'timeout' in data: + syslog.syslog(syslog.LOG_INFO, 'ip sla mode Configure freq/thresh/timeout for sla {}'.format(sla_id)) + cmd_prefix = ['configure terminal','ip sla {}'.format(sla_id)] + if not key_map.run_command(self, table, data, cmd_prefix, sla_id): + syslog.syslog(syslog.LOG_ERR, 'failed running ip sla command') + continue + + elif icmp_config == False or tcp_config == False: + syslog.syslog(syslog.LOG_INFO, 'Basic mode Configure for ip sla {}'.format(sla_id)) + cmd_prefix = ['configure terminal'] + + # Always delete ip sla if it is not found in configdb + if not found_in_configdb: + command = "vtysh -c 'configure terminal' -c 'no ip sla {}'".format(sla_id) + syslog.syslog(syslog.LOG_ERR, 'Entry deleted in ip sla config db') + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete router ip sla {}'.format(sla_id)) + continue + elif not key_map.run_command(self, table, data, cmd_prefix, sla_id): + syslog.syslog(syslog.LOG_ERR, 'failed running ip sla command') + continue + + elif table == 'OSPFV2_ROUTER': + vrf = prefix + if not del_table: + syslog.syslog(syslog.LOG_INFO, 'Create router ospf vrf {}'.format(vrf)) + + cmd_prefix = ['configure terminal', + 'router ospf vrf {}'.format(vrf)] + + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running ospf config command') + continue + else: + command = "vtysh -c 'configure terminal' -c 'no router ospf vrf {}'".format(vrf) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete router ospf vrf {}'.format(vrf)) + continue + else: + self.__ospf_delete(data) + + elif table == 'OSPFV2_ROUTER_AREA': + vrf = prefix + syslog.syslog(syslog.LOG_INFO, 'Create router ospf vrf {}'.format(vrf)) + + cmd_prefix = ['configure terminal', + 'router ospf vrf {}'.format(vrf)] + + if not key_map.run_command(self, table, data, cmd_prefix, key): + syslog.syslog(syslog.LOG_ERR, 'failed running ospf config command') + continue + elif table == 'OSPFV2_ROUTER_AREA_VIRTUAL_LINK': + vrf = prefix + + keyvals = key.split('|') + area = keyvals[0] + vlinkid = keyvals[1] + + syslog.syslog(syslog.LOG_INFO, 'Create router ospf vrf {}, Vlink: {}, tableop {}'.format(vrf, data, del_table)) + + if data == {}: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no area {} virtual-link {}'".\ + format(vrf, area, vlinkid) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete vlink {} {}'.format(area, vlinkid)) + continue + else: + self.__ospf_delete(data) + else: + cmd_prefix = ['configure terminal', + 'router ospf vrf {}'.format(vrf)] + + if not key_map.run_command(self, table, data, cmd_prefix, area, vlinkid): + syslog.syslog(syslog.LOG_ERR, 'failed running ospf config command') + continue + + if del_table: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no area {} virtual-link {}'".\ + format(vrf, area, vlinkid) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete vlink {} {}'.format(area, vlinkid)) + continue + else: + self.__ospf_delete(data) + + elif table == 'OSPFV2_ROUTER_AREA_NETWORK': + vrf = prefix + syslog.syslog(syslog.LOG_INFO, 'Create router ospf vrf {}'.format(vrf)) + + keyvals = key.split('|') + area = keyvals[0] + network = keyvals[1] + + if not del_table: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'network {} area {}'".\ + format(vrf, network, area) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create network {} {}'.format(area, network)) + continue + else: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no network {} area {}'".\ + format(vrf, network, area) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete network {} {}'.format(area, network)) + continue + else: + self.__ospf_delete(data) + + elif table == 'OSPFV2_ROUTER_AREA_POLICY_ADDRESS_RANGE': + vrf = prefix + + keyvals = key.split('|') + area = keyvals[0] + range = keyvals[1] + + syslog.syslog(syslog.LOG_INFO, 'Create router ospf vrf {}'.format(vrf)) + + if data == {}: + if not del_table: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'area {} range {}'".\ + format(vrf, area, range) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create range {} {}'.format(area, range)) + continue + else: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no area {} range {}'".\ + format(vrf, area, range) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete range {} {}'.format(area, range)) + continue + else: + self.__ospf_delete(data) + else: + cmd_prefix = ['configure terminal', + 'router ospf vrf {}'.format(vrf)] + + if not key_map.run_command(self, table, data, cmd_prefix, area, range): + syslog.syslog(syslog.LOG_ERR, 'failed running ospf config command') + continue + + elif table == 'OSPFV2_ROUTER_DISTRIBUTE_ROUTE': + vrf = prefix + + keyvals = key.split('|') + protocol = keyvals[0] + direction = keyvals[1] + + if (protocol == "DIRECTLY_CONNECTED"): + protocol = "CONNECTED" + + syslog.syslog(syslog.LOG_INFO, 'Create redistribute-list {} {}'.format(protocol, direction)) + + cmd_suffix = "" + del_cmd_suffix = "" + cmd_oper = "" + rmapcmd = "" + metriccmd = "" + metrictypecmd = "" + alwayscmd = "" + mapname = "" + acclistname = "" + rmapoper = "" + metricoper = "" + metrictypeoper = "" + alwaysoper = "" + acclistoper = "" + + if 'route-map' in data: + dval = data['route-map'] + rmapoper = dval.op + mapname = dval.data + rmapcmd = " route-map {}".format(dval.data) + + if 'access-list' in data: + dval = data['access-list'] + acclistoper = dval.op + acclistname = dval.data + + if 'metric' in data: + dval = data['metric'] + metricoper = dval.op + metriccmd = " metric {}".format(dval.data) + + if 'metric-type' in data: + dval = data['metric-type'] + metrictypeoper = dval.op + + if dval.data == "TYPE_1": + metrictypecmd = " metric-type 1" + else: + metrictypecmd = " metric-type 2" + + if 'always' in data: + dval = data['always'] + alwaysoper = dval.op + alwayscmd = " always" + + if not del_table: + + if ((rmapoper == CachedDataWithOp.OP_DELETE) or + (metricoper == CachedDataWithOp.OP_DELETE) or + (metrictypeoper == CachedDataWithOp.OP_DELETE) or + (alwaysoper == CachedDataWithOp.OP_DELETE) or + (acclistoper == CachedDataWithOp.OP_DELETE)): + + cmd_oper = "no" + + if (alwaysoper == CachedDataWithOp.OP_DELETE): + del_cmd_suffix = alwayscmd + if (rmapoper == CachedDataWithOp.OP_DELETE): + del_cmd_suffix = rmapcmd + if (metricoper == CachedDataWithOp.OP_DELETE): + del_cmd_suffix = metriccmd + if (metrictypeoper == CachedDataWithOp.OP_DELETE): + del_cmd_suffix = metrictypecmd + + if (direction == "EXPORT"): + if (cmd_oper != "no"): + cmd_suffix = "distribute-list {} out {}".format(acclistname, protocol.lower()) + else: + cmd_suffix = "no distribute-list {} out {}".format(acclistname, protocol.lower()) + + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c '{}'".\ + format(vrf, cmd_suffix) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create distribute-list {} {}'.format(protocol, direction)) + continue + else: + self.__ospf_apply_config(data, rmapoper, metricoper, metrictypeoper, alwaysoper, acclistoper) + elif (direction == "IMPORT"): + if (cmd_oper != "no"): + if (protocol == "DEFAULT_ROUTE"): + cmd_suffix = cmd_suffix + "default-information originate" + alwayscmd + rmapcmd + metriccmd + metrictypecmd + else: + cmd_suffix = cmd_suffix + "redistribute {}".format(protocol.lower()) + rmapcmd + metriccmd + metrictypecmd + else: + if (protocol == "DEFAULT_ROUTE"): + cmd_suffix = "no default-information originate" + del_cmd_suffix + else: + cmd_suffix = "no redistribute {}".format(protocol.lower()) + del_cmd_suffix + + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c '{}'".\ + format(vrf, cmd_suffix) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create default-info/redistribute {} {}'.format(protocol, direction)) + continue + else: + self.__ospf_apply_config(data, rmapoper, metricoper, metrictypeoper, alwaysoper, acclistoper) + else: + if (direction == "IMPORT"): + command = "" + if (protocol == "DEFAULT_ROUTE"): + cmd_suffix = "no default-information originate" + cmd_suffix + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no default-information originate'".\ + format(vrf) + else: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no redistribute {}'".\ + format(vrf, protocol.lower()) + + if (command != ""): + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete default-info/redistribute {}'.format(protocol.lower())) + continue + else: + self.__ospf_delete(data) + else: + if (acclistname != ""): + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no distribute-list {} out {}'".\ + format(vrf, acclistname, protocol.lower()) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete distribute-list {} {}'.format(protocol, direction)) + continue + + self.__ospf_delete(data) + + elif table == 'OSPFV2_INTERFACE': + + key = prefix + '|' + key + if_name, if_addr = key.split('|') + + vrf = "" + if 'vrf_name' in data : + vrf = 'vrf {}'.format(data['vrf_name'].data) + + cmd_prefix = ['configure terminal', + 'interface {} {}'.format(if_name, vrf) ] + + if del_table and len(data) == 0: + syslog.syslog(syslog.LOG_INFO, 'Delete table {} {} data {}'.format(key, vrf, data)) + + cmd_data = {} + cache_tbl_key = 'OSPFV2_INTERFACE&&{}|{}'.format(if_name, if_addr) + syslog.syslog(syslog.LOG_INFO, 'Row delete key {}'.format(cache_tbl_key)) + + if cache_tbl_key in self.table_data_cache.keys(): + cache_tbl_data = self.table_data_cache[cache_tbl_key] + syslog.syslog(syslog.LOG_INFO, 'Row delete cached data {} '.format(cache_tbl_data)) + + for key, data in cache_tbl_data.items() : + cached_op_data = CachedDataWithOp(data, CachedDataWithOp.OP_DELETE) + cmd_data.update({ key : cached_op_data } ) + + syslog.syslog(syslog.LOG_INFO, 'Row delete cmd data {} '.format(cmd_data)) + + if len(cmd_data) : + if not key_map.run_command(self, table, cmd_data, cmd_prefix, if_name, if_addr): + syslog.syslog(syslog.LOG_INFO, 'failed running interface no ip ospf config command') + self.__apply_config_delete_success(cmd_data) + continue + else : + self.__apply_config_delete_success(cmd_data) + + else : + syslog.syslog(syslog.LOG_INFO, 'Create/update ospf {} interface {} in {}'.format(key, if_name, vrf)) + + #Work arround for router area config fail, update area every time + if 'area-id' in data.keys(): + dval = data['area-id'] + if dval.op == CachedDataWithOp.OP_NONE : + dval.op = CachedDataWithOp.OP_ADD + + if not key_map.run_command(self, table, data, cmd_prefix, if_name, if_addr): + syslog.syslog(syslog.LOG_ERR, 'failed running interface ip ospf config command') + if 'area-id' in data.keys(): + dval = data['area-id'] + if dval.op == CachedDataWithOp.OP_DELETE: + #Work arround for router area config delete fail + self.__apply_config_op_success(data, {'area-id': dval.op } ) + syslog.syslog(syslog.LOG_INFO, 'area-id delete enforced') + continue + else : + self.__apply_config_op_success(data) + + elif table == 'OSPFV2_ROUTER_PASSIVE_INTERFACE': + syslog.syslog(syslog.LOG_INFO, 'Create passive interface') + + vrf = prefix + + keyvals = key.split('|') + if_name = keyvals[0] + if_addr = keyvals[1] + + syslog.syslog(syslog.LOG_INFO, 'Create passive interface vrf {}'.format(vrf)) + + if (if_addr == "0.0.0.0"): + if_addr = "" + + if data == {}: + if not del_table: + + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'passive-interface {} {}'".\ + format(vrf, if_name, if_addr) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to create passive interface {} {}'.format(if_name, if_addr)) + continue + else: + command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no passive-interface {} {}'".\ + format(vrf, if_name, if_addr) + + if not self.__run_command(table, command): + syslog.syslog(syslog.LOG_ERR, 'failed to delete passive interface {} {}'.format(if_name, if_addr)) + continue + + elif table == 'STATIC_ROUTE': + vrf = prefix + syslog.syslog(syslog.LOG_INFO, 'Set static IP route for vrf {} prefix {}'.format(vrf, key)) + op = CachedDataWithOp.OP_DELETE if del_table else CachedDataWithOp.OP_UPDATE + data['ip_prefix'] = CachedDataWithOp(key, op) + cmd_prefix = ['configure terminal', 'vrf {}'.format(vrf)] + ret_val = key_map.run_command(self, table, data, cmd_prefix, vrf) + del(data['ip_prefix']) + if not ret_val: + syslog.syslog(syslog.LOG_ERR, 'failed running static route config command') + continue + self.static_route_list.setdefault(vrf, {})[key] = self.upd_nh_set + elif table == 'PIM_INTERFACE': + + vrf = prefix + af, if_name = key.split('|') + syslog.syslog(syslog.LOG_INFO, + 'PIM interface update for vrf {}, af: {}, interface {}'.format(vrf, af, if_name)) + cmd_prefix = ['configure terminal', + 'interface {}'.format(if_name)] + syslog.syslog(syslog.LOG_INFO, + 'Create/update PIM interface: key {} interface {} in {}'.format(key, if_name, vrf)) + + # If sparse-mode has been disabled, clear other interface + # entries in cache so that they will be re-programmed in FRR + # on re-enabling of sparse-mode. + + if 'mode' in data: + modeval = data['mode'] + modeval_pim_mode = modeval.data + modeval_op = modeval.op + if (modeval_op == CachedDataWithOp.OP_DELETE): + syslog.syslog(syslog.LOG_INFO, + "Flushing PIM interface cache for deletion " + "of PIM sparse-mode") + for dkey, dval in data.items(): + dval.status = CachedDataWithOp.STAT_SUCC + dval.op = CachedDataWithOp.OP_DELETE + + # Only send the VTYSH command to FRR if the PIM interface mode + # is present in the update. + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running PIM config command') + continue + + elif table == 'PIM_GLOBALS': + + vrf = prefix + + af = key.split('|') + syslog.syslog(syslog.LOG_INFO, + 'PIM global update for vrf {}, af: {}'.format(vrf, af)) + + cmd_prefix = ['configure terminal', + 'vrf {}'.format(vrf)] + + syslog.syslog(syslog.LOG_INFO, + 'Create/update PIM global {} af {} in {}'.format(key, af, vrf)) + + # if not key_map.run_command(self, table, data, cmd_prefix, vrf, af): + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running PIM config command') + continue + + elif table == 'IGMP_INTERFACE': + ifname = prefix + + syslog.syslog(syslog.LOG_INFO, 'IGMP Interface MCast Grp ifname {} prefix {}'.format(ifname, key)) + + keyvals = key.split('|') + mcast_grp = keyvals[0] + source_ip = keyvals[1] + + syslog.syslog(syslog.LOG_INFO, 'Configure ip igmp join interface {}, mcast_grp {}, source_ip {}'.format(ifname, mcast_grp, source_ip)) + + cmd_prefix = ['configure terminal', + 'interface {}'.format(ifname)] + + if not key_map.run_command(self, table, data, cmd_prefix, mcast_grp, source_ip): + syslog.syslog(syslog.LOG_ERR, 'failed running ip igmp join config command') + continue + + + elif table == 'IGMP_INTERFACE_QUERY': + ifname = prefix + + syslog.syslog(syslog.LOG_INFO, 'IGMP Interface {} Config prefix {}'.format(ifname, key)) + + cmd_prefix = ['configure terminal', + 'interface {}'.format(ifname)] + + if not key_map.run_command(self, table, data, cmd_prefix): + syslog.syslog(syslog.LOG_ERR, 'failed running ip igmp interface config command') + continue + + + def __add_op_to_data(self, table_key, data, comb_attr_list): + cached_data = self.table_data_cache.setdefault(table_key, {}) + for key in cached_data: + if key in data: + # both in cache and data, update/none + data[key] = (CachedDataWithOp(data[key], CachedDataWithOp.OP_NONE) if data[key] == cached_data[key] else + CachedDataWithOp(data[key], CachedDataWithOp.OP_UPDATE)) + else: + # in cache but not in data, delete + data[key] = CachedDataWithOp(cached_data[key], CachedDataWithOp.OP_DELETE) + for key in data: + if not isinstance(data[key], CachedDataWithOp): + # in data but not in cache, add + data[key] = CachedDataWithOp(data[key], CachedDataWithOp.OP_ADD) + # combo attributes handling + op_list = [CachedDataWithOp.OP_DELETE, CachedDataWithOp.OP_ADD, CachedDataWithOp.OP_UPDATE, CachedDataWithOp.OP_NONE] + for key_set in comb_attr_list: + all_in = True + op_idx = len(op_list) - 1 + for key in key_set: + if key not in data: + all_in = False + break + idx = op_list.index(data[key].op) + if idx >= 0 and idx < op_idx: + op_idx = idx + if all_in: + for key in key_set: + data[key].op = op_list[op_idx] + else: + # if one key doesn't exist, clean the whole key set + for key in key_set: + data.pop(key, None) + + def __update_cache_data(self, table_key, data): + cached_data = self.table_data_cache.setdefault(table_key, {}) + for key, val in data.items(): + if not isinstance(val, CachedDataWithOp) or val.op == CachedDataWithOp.OP_NONE or val.status == CachedDataWithOp.STAT_FAIL: + syslog.syslog(syslog.LOG_DEBUG, 'ignore cache update for %s because of %s%s%s' % + (key, ('' if isinstance(val, CachedDataWithOp) else 'INV_DATA '), + ('NO_OP ' if isinstance(val, CachedDataWithOp) and val.op == CachedDataWithOp.OP_NONE else ''), + ('STAT_FAIL ' if isinstance(val, CachedDataWithOp) and val.status == CachedDataWithOp.STAT_FAIL else ''))) + continue + if val.op == CachedDataWithOp.OP_ADD or val.op == CachedDataWithOp.OP_UPDATE: + cached_data[key] = val.data + syslog.syslog(syslog.LOG_INFO, 'Add {} data {} to cache'.format(key, cached_data[key])) + elif val.op == CachedDataWithOp.OP_DELETE: + syslog.syslog(syslog.LOG_INFO, 'delete {} data {} from cache'.format(key, cached_data.get(key, ''))) + cached_data.pop(key, None) + if len(cached_data) == 0: + syslog.syslog(syslog.LOG_INFO, 'delete table row {} from cache'.format(table_key)) + del(self.table_data_cache[table_key]) + + + def bgp_table_handler_common(self, table, key, data, comb_attr_list = []): + syslog.syslog(syslog.LOG_DEBUG, '----------------------------------') + syslog.syslog(syslog.LOG_DEBUG, ' BGP table handling') + syslog.syslog(syslog.LOG_DEBUG, '----------------------------------') + syslog.syslog(syslog.LOG_DEBUG, 'table : %s' % table) + syslog.syslog(syslog.LOG_DEBUG, 'key : %s' % key) + op_str = ('DELETE' if data is None else 'SET') + del_table = False + if data is None: + data = {} + del_table = True + syslog.syslog(syslog.LOG_DEBUG, 'op : %s' % op_str) + syslog.syslog(syslog.LOG_DEBUG, 'data :') + for dkey, dval in data.items(): + syslog.syslog(syslog.LOG_DEBUG, ' %-10s - %s' % (dkey, dval)) + syslog.syslog(syslog.LOG_DEBUG, '') + table_key = ExtConfigDBConnector.get_table_key(table, key) + self.__add_op_to_data(table_key, data, comb_attr_list) + self.bgp_message.put((key, del_table, table, data)) + upd_data_list = [] + self.__update_bgp(upd_data_list) + for table, key, data in upd_data_list: + table_key = ExtConfigDBConnector.get_table_key(table, key) + self.__update_cache_data(table_key, data) + + def bgp_global_handler(self, table, key, data): + self.bgp_table_handler_common(table, key, data, [{'keepalive', 'holdtime'}]) + + def bgp_af_handler(self, table, key, data): + self.bgp_table_handler_common(table, key, data, [{'ebgp_route_distance', 'ibgp_route_distance', 'local_route_distance'}, + {'route_flap_dampen_reuse_threshold', 'route_flap_dampen_suppress_threshold', 'route_flap_dampen_max_suppress'}]) + + def bgp_neighbor_handler(self, table, key, data): + self.bgp_table_handler_common(table, key, data, [{'keepalive', 'holdtime'}]) + + def comm_set_handler(self, table, key, data): + self.bgp_table_handler_common(table, key, data, [{'set_type', 'match_action', 'community_member'}]) + + def bfd_shop_handler(self, table, key, data): + self.bgp_table_handler_common(table, key, data, [{'remote-address', 'vrf', 'interface'}, + {'remote-address', 'vrf', 'interface', 'local-address'}]) + def bfd_mhop_handler(self, table, key, data): + self.bgp_table_handler_common(table, key, data, [{'remote-address', 'vrf', 'local-address'}]) + + def start(self): + self.subscribe_all() + self.config_db.listen() + def stop(self): + self.config_db.sub_thread.stop() + if self.config_db.sub_thread.is_alive(): + self.config_db.sub_thread.join() + +main_loop = True + +def sig_handler(signum, frame): + global main_loop + syslog.syslog(syslog.LOG_DEBUG, 'entering signal handler') + main_loop = False + +def main(): + global bgpd_client + for sig_num in [signal.SIGTERM, signal.SIGINT]: + signal.signal(sig_num, sig_handler) + syslog.syslog(syslog.LOG_DEBUG, 'entering BGP configuration daemon') + bgpd_client = BgpdClientMgr() + bgpd_client.start() + daemon = BGPConfigDaemon() + daemon.start() + while main_loop: + signal.pause() + syslog.syslog(syslog.LOG_DEBUG, 'leaving BGP configuration daemon') + bgpd_client.shutdown() + daemon.stop() + +if __name__ == "__main__": + main() From 154ec12f19225138d21b0ab55e4fb2581052948f Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Mon, 10 Aug 2020 16:14:34 -0700 Subject: [PATCH 02/24] Reomved not needed config file --- .../docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 deleted file mode 100644 index c3dc50449d35..000000000000 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.peer.conf.j2 +++ /dev/null @@ -1,38 +0,0 @@ -{% block bgp_peer %} - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{# set the bgp neighbor timers if they have not default values #} -{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) - or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} - neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} -{% endif %} -{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} - neighbor {{ neighbor_addr }} shutdown -{% endif %} -{% if neighbor_addr | ipv4 %} - address-family ipv4 - neighbor {{ neighbor_addr }} peer-group PEER_V4 -{% elif neighbor_addr | ipv6 %} - address-family ipv6 -{% if bgp_session['asn'] != DEVICE_METADATA['localhost']['bgp_asn'] %} - neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in -{% endif %} - neighbor {{ neighbor_addr }} peer-group PEER_V6 -{% endif %} -{% if bgp_session['rrclient'] | int != 0 %} - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} -{% if bgp_session['nhopself'] | int != 0 %} - neighbor {{ neighbor_addr }} next-hop-self -{% endif %} -{% if bgp_session["asn"] == DEVICE_METADATA['localhost']['bgp_asn'] - and DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" - and (not bgp_session.has_key("local_addr") or bgp_session["local_addr"] not in interfaces_in_vnets) %} - address-family l2vpn evpn - neighbor {{ neighbor_addr }} activate - advertise-all-vni - exit-address-family -{% endif %} - neighbor {{ neighbor_addr }} activate - exit-address-family -{% endblock bgp_peer %} From 288986ce5a8b2e98e84fabca7f82042360b3b8d0 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Fri, 14 Aug 2020 11:13:03 -0700 Subject: [PATCH 03/24] Added update on setup.py --- src/sonic-bgpcfgd/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-bgpcfgd/setup.py b/src/sonic-bgpcfgd/setup.py index fae1c313850e..07fac08a86e0 100755 --- a/src/sonic-bgpcfgd/setup.py +++ b/src/sonic-bgpcfgd/setup.py @@ -9,7 +9,7 @@ author_email='pavelsh@microsoft.com', url='https://github.com/Azure/sonic-buildimage', packages=setuptools.find_packages(), - scripts=['bgpcfgd'], + scripts=['bgpcfgd', 'bgpcfgd_no_template'], install_requires=['jinja2>=2.10', 'netaddr', 'pyyaml'], setup_requires=['pytest-runner', 'pytest'], ) From e942575ba60edd8f96364a00ca63dc55f1eb5ff9 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Mon, 24 Aug 2020 19:52:49 -0700 Subject: [PATCH 04/24] Fixed for erasing LGTM alert and other minor issues --- dockers/docker-fpm-frr/docker_init.sh | 2 +- .../docker-fpm-frr/frr/ospfd/ospfd.conf.j2 | 2 + src/sonic-bgpcfgd/bgpcfgd_no_template | 37 +++++++++++++------ .../tests/sample_output/staticd_frr.conf | 1 + 4 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.j2 diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 072b17391089..cfbf0f816626 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -18,7 +18,7 @@ CFGGEN_PARAMS=" \ " if [ -n "$TEMPL_CONFIG" ] && [ "$TEMPL_CONFIG" == "false" ]; then CFGGEN_PARAMS+=" \ - -t /usr/share/sonic/templates/bgdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ + -t /usr/share/sonic/templates/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ -t /usr/share/sonic/templates/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ " fi diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.j2 new file mode 100644 index 000000000000..b31926919ce4 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.j2 @@ -0,0 +1,2 @@ +{% include "ospfd.conf.db.comm_list.j2" %} +{% include "ospfd.conf.db.interface.j2" %} diff --git a/src/sonic-bgpcfgd/bgpcfgd_no_template b/src/sonic-bgpcfgd/bgpcfgd_no_template index 37d684c723e0..9e8194deaf0e 100755 --- a/src/sonic-bgpcfgd/bgpcfgd_no_template +++ b/src/sonic-bgpcfgd/bgpcfgd_no_template @@ -8,7 +8,6 @@ import os from swsssdk import ConfigDBConnector import socket import threading -import pty import Queue import signal import re @@ -82,7 +81,6 @@ class BgpdClientMgr(threading.Thread): 'BGP_GLOBALS': ['bgpd'], 'BGP_GLOBALS_AF': ['bgpd'], 'PREFIX_SET': ['bgpd'], - 'PREFIX': ['bgpd'], 'COMMUNITY_SET': ['bgpd'], 'EXTENDED_COMMUNITY_SET': ['bgpd'], 'ROUTE_MAP': ['zebra', 'bgpd', 'ospfd'], @@ -498,6 +496,10 @@ class BGPKeyMapInfo: else: self.hdl_func = hdlr self.data = data + def __eq__(self, other): + return set(self.daemons) == set(other.daemons) and self.run_cmd == other.run_cmd + def __ne__(self, other): + return set(self.daemons) != set(other.daemons) or self.run_cmd != other.run_cmd def get_command(self, daemon, op, st_idx, *vals): return self.hdl_func(daemon, self.run_cmd, op, st_idx, vals, self.data) def __str__(self): @@ -544,6 +546,10 @@ class BGPKeyMapList(list): except ValueError: pass super(BGPKeyMapList, self).append((db_field, BGPKeyMapInfo(cmd_str, hdl_func, hdl_data))) + def __eq__(self, other): + return super(BGPKeyMapList, self).__eq__(other) and self.table_name == other.table_name and self.table_key == self.table_key + def __ne__(self, other): + return super(BGPKeyMapList, self).__ne__(other) or self.table_name != other.table_name or self.table_key != self.table_key @staticmethod def get_map_field_key(field): if type(field) is str: @@ -1177,7 +1183,6 @@ def handle_ospf_if_mtu_ignore(daemon, cmd_str, op, st_idx, args, data): def handle_ospf_if_nwtype(daemon, cmd_str, op, st_idx, args, data): cmd_list = [] - if_addr = "" if args[1] == '0.0.0.0' else args[1] no_op = 'no ' if op == CachedDataWithOp.OP_DELETE else '' nwtype = '' @@ -1234,7 +1239,6 @@ def handle_igmp_if_enable(daemon, cmd_str, op, st_idx, args, data): def handle_ip_sla_common(daemon, cmd_str, op, st_idx, args, data): cmd_list = [] - param_value = args[0] syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla cmd_str {} op {} st_idx {} args {} data {}'.format( cmd_str, op, st_idx, args, data)) @@ -1248,7 +1252,6 @@ def handle_ip_sla_common(daemon, cmd_str, op, st_idx, args, data): def handle_ip_sla_tcp_connect(daemon, cmd_str, op, st_idx, args, data): cmd_list = [] - param_value = args[0] syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla_tcp_connect cmd_str {} op {} st_idx {} args {} data {}'.format( cmd_str, op, st_idx, args, data)) @@ -1265,7 +1268,6 @@ def handle_ip_sla_tcp_connect(daemon, cmd_str, op, st_idx, args, data): def handle_ip_sla_icmp_echo(daemon, cmd_str, op, st_idx, args, data): cmd_list = [] - param_value = args[0] syslog.syslog(syslog.LOG_INFO, 'handle_ip_sla_icmp_echo cmd_str {} op {} st_idx {} args {} data {}'.format( cmd_str, op, st_idx, args, data)) @@ -1543,6 +1545,8 @@ class MatchPrefix: else: self.min_len = self.max_len = None self.action = action + def __hash__(self): + return hash((self.ip_prefix, self.min_len, self.max_len)) def __str__(self): ret_str = '%s %s' % (self.action.lower(), self.ip_prefix) if self.min_len is not None: @@ -1554,6 +1558,10 @@ class MatchPrefix: return (self.ip_prefix == other.ip_prefix and self.min_len == other.min_len and self.max_len == other.max_len) + def __ne__(self, other): + return (self.ip_prefix != other.ip_prefix or + self.min_len != other.min_len or + self.max_len != other.max_len) class MatchPrefixList(list): def __init__(self, af_mode = None): @@ -1562,6 +1570,10 @@ class MatchPrefixList(list): self.af = None else: self.af = socket.AF_INET if af_mode == 'ipv4' else socket.AF_INET6 + def __eq__(self, other): + return super(MatchPrefixList, self).__eq__(other) and self.af == other.af + def __ne__(self, other): + return super(MatchPrefixList, self).__ne__(other) or self.af != other.af @staticmethod def __get_ip_af(ip_pfx): ip_pfx = ip_pfx.split('/') @@ -1616,9 +1628,13 @@ class IpNextHop: syslog.syslog(syslog.LOG_ERR, 'Mandatory attribute not found for nexthop') raise ValueError def __eq__(self, other): - return (self.af == other.af and self.blackhole == other.blackhole and + return (self.af == other.af and self.blackhole == other.blackhole and self.ip == other.ip and self.track == other.track and self.interface == other.interface and self.tag == other.tag and self.distance == other.distance and self.nh_vrf == other.nh_vrf) + def __ne__(self, other): + return (self.af != other.af or self.blackhole != other.blackhole or + self.ip != other.ip or self.track != other.track or self.interface != other.interface or + self.tag != other.tag or self.distance != other.distance or self.nh_vrf != other.nh_vrf) def __hash__(self): return hash((self.af, self.blackhole, self.ip, self.track, self.interface, self.tag, self.distance, self.nh_vrf)) def __str__(self): @@ -3334,7 +3350,6 @@ class BGPConfigDaemon: metriccmd = "" metrictypecmd = "" alwayscmd = "" - mapname = "" acclistname = "" rmapoper = "" metricoper = "" @@ -3345,7 +3360,6 @@ class BGPConfigDaemon: if 'route-map' in data: dval = data['route-map'] rmapoper = dval.op - mapname = dval.data rmapcmd = " route-map {}".format(dval.data) if 'access-list' in data: @@ -3398,7 +3412,7 @@ class BGPConfigDaemon: cmd_suffix = "no distribute-list {} out {}".format(acclistname, protocol.lower()) command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c '{}'".\ - format(vrf, cmd_suffix) + format(vrf, cmd_suffix) if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to create distribute-list {} {}'.format(protocol, direction)) @@ -3418,7 +3432,7 @@ class BGPConfigDaemon: cmd_suffix = "no redistribute {}".format(protocol.lower()) + del_cmd_suffix command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c '{}'".\ - format(vrf, cmd_suffix) + format(vrf, cmd_suffix) if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to create default-info/redistribute {} {}'.format(protocol, direction)) @@ -3429,7 +3443,6 @@ class BGPConfigDaemon: if (direction == "IMPORT"): command = "" if (protocol == "DEFAULT_ROUTE"): - cmd_suffix = "no default-information originate" + cmd_suffix command = "vtysh -c 'configure terminal' -c 'router ospf vrf {}' -c 'no default-information originate'".\ format(vrf) else: diff --git a/src/sonic-config-engine/tests/sample_output/staticd_frr.conf b/src/sonic-config-engine/tests/sample_output/staticd_frr.conf index 31a11d8578aa..75cbbd6df164 100644 --- a/src/sonic-config-engine/tests/sample_output/staticd_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/staticd_frr.conf @@ -18,3 +18,4 @@ log facility local4 ! set static default route to mgmt gateway as a backup to learned default ip route 0.0.0.0/0 10.0.0.1 200 !! +! From 9c94d03c6ec192e748b06a9eeda84fb2257cd74a Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Tue, 25 Aug 2020 11:19:16 -0700 Subject: [PATCH 05/24] Changed to erase new lgtm alerts --- src/sonic-bgpcfgd/bgpcfgd_no_template | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sonic-bgpcfgd/bgpcfgd_no_template b/src/sonic-bgpcfgd/bgpcfgd_no_template index 9e8194deaf0e..23a009bc32dd 100755 --- a/src/sonic-bgpcfgd/bgpcfgd_no_template +++ b/src/sonic-bgpcfgd/bgpcfgd_no_template @@ -500,6 +500,8 @@ class BGPKeyMapInfo: return set(self.daemons) == set(other.daemons) and self.run_cmd == other.run_cmd def __ne__(self, other): return set(self.daemons) != set(other.daemons) or self.run_cmd != other.run_cmd + def __hash__(self): + return hash(self.run_cmd) def get_command(self, daemon, op, st_idx, *vals): return self.hdl_func(daemon, self.run_cmd, op, st_idx, vals, self.data) def __str__(self): @@ -547,9 +549,9 @@ class BGPKeyMapList(list): pass super(BGPKeyMapList, self).append((db_field, BGPKeyMapInfo(cmd_str, hdl_func, hdl_data))) def __eq__(self, other): - return super(BGPKeyMapList, self).__eq__(other) and self.table_name == other.table_name and self.table_key == self.table_key + return super(BGPKeyMapList, self).__eq__(other) and self.table_name == other.table_name and self.table_key == other.table_key def __ne__(self, other): - return super(BGPKeyMapList, self).__ne__(other) or self.table_name != other.table_name or self.table_key != self.table_key + return super(BGPKeyMapList, self).__ne__(other) or self.table_name != other.table_name or self.table_key != other.table_key @staticmethod def get_map_field_key(field): if type(field) is str: From 26375661af024dae87656e067af162465b2fc10e Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Sun, 27 Dec 2020 23:41:32 -0800 Subject: [PATCH 06/24] Added new package for FRR configuration daemon --- dockers/docker-fpm-frr/critical_processes | 1 + dockers/docker-fpm-frr/docker_init.sh | 4 +- .../frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 | 32 +++---- .../frr/bgpd/bgpd.conf.db.addr_family.j2 | 34 ++++---- .../frr/bgpd/bgpd.conf.db.comm_list.j2 | 4 +- .../docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 | 84 +++++++++---------- .../frr/bgpd/bgpd.conf.db.nbr_af.j2 | 70 ++++++++-------- .../frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 | 54 ++++++------ .../frr/bgpd/bgpd.conf.db.pref_list.j2 | 2 +- .../frr/bgpd/bgpd.conf.db.route_map.j2 | 58 ++++++------- dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 | 2 +- .../frr/ospfd/ospfd.conf.db.area.j2 | 18 ++-- .../frr/ospfd/ospfd.conf.db.comm_list.j2 | 40 ++++----- .../ospfd/ospfd.conf.db.distributeroute.j2 | 16 ++-- .../frr/ospfd/ospfd.conf.db.interface.j2 | 30 +++---- .../frr/ospfd/ospfd.conf.db.policyrange.j2 | 6 +- .../frr/ospfd/ospfd.conf.db.vlink.j2 | 14 ++-- .../frr/staticd/staticd.conf.j2 | 11 +++ .../frr/staticd/staticd.db.conf.j2 | 14 ++-- .../frr/supervisord/supervisord.conf.j2 | 7 +- rules/docker-fpm-frr.mk | 2 +- rules/sonic-frr-mgmt-framework.dep | 8 ++ rules/sonic-frr-mgmt-framework.mk | 13 +++ .../tests/sample_output/py2/staticd_frr.conf | 1 - src/sonic-frr-mgmt-framework/.gitignore | 12 +++ .../frrcfgd/__init__.py | 0 .../frrcfgd/frrcfgd} | 0 src/sonic-frr-mgmt-framework/pytest.ini | 2 + src/sonic-frr-mgmt-framework/setup.cfg | 5 ++ src/sonic-frr-mgmt-framework/setup.py | 29 +++++++ .../tests/__init__.py | 0 .../tests/test_config.py | 2 + 32 files changed, 329 insertions(+), 246 deletions(-) create mode 100644 rules/sonic-frr-mgmt-framework.dep create mode 100644 rules/sonic-frr-mgmt-framework.mk create mode 100644 src/sonic-frr-mgmt-framework/.gitignore create mode 100644 src/sonic-frr-mgmt-framework/frrcfgd/__init__.py rename src/{sonic-bgpcfgd/bgpcfgd_no_template => sonic-frr-mgmt-framework/frrcfgd/frrcfgd} (100%) create mode 100644 src/sonic-frr-mgmt-framework/pytest.ini create mode 100644 src/sonic-frr-mgmt-framework/setup.cfg create mode 100755 src/sonic-frr-mgmt-framework/setup.py create mode 100644 src/sonic-frr-mgmt-framework/tests/__init__.py create mode 100644 src/sonic-frr-mgmt-framework/tests/test_config.py diff --git a/dockers/docker-fpm-frr/critical_processes b/dockers/docker-fpm-frr/critical_processes index 2631fee15e66..a166f5c97a3c 100644 --- a/dockers/docker-fpm-frr/critical_processes +++ b/dockers/docker-fpm-frr/critical_processes @@ -3,3 +3,4 @@ program:staticd program:bgpd program:fpmsyncd program:bgpcfgd +program:frrcfgd diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 5bbd374d7a30..170ef7fb96ff 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -3,7 +3,7 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d -TEMPL_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["bgp_template_config"]'` +MGMT_FRAMEWORK_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]'` CFGGEN_PARAMS=" \ -d \ -y /etc/sonic/constants.yml \ @@ -16,7 +16,7 @@ CFGGEN_PARAMS=" \ -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ " -if [ -n "$TEMPL_CONFIG" ] && [ "$TEMPL_CONFIG" == "false" ]; then +if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then CFGGEN_PARAMS+=" \ -t /usr/share/sonic/templates/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ -t /usr/share/sonic/templates/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 index c130ac3cc616..4178180a6d6d 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 @@ -1,39 +1,39 @@ -{% if af_val.has_key('advertise-all-vni') and af_val['advertise-all-vni'] == 'true' %} +{% if 'advertise-all-vni' in af_val and af_val['advertise-all-vni'] == 'true' %} advertise-all-vni {% endif %} -{% if af_val.has_key('autort') %} +{% if 'autort' in af_val %} autort {{af_val['autort']}} {% endif %} -{% if af_val.has_key('advertise-default-gw') and af_val['advertise-default-gw'] == 'true' %} +{% if 'advertise-default-gw' in af_val and af_val['advertise-default-gw'] == 'true' %} advertise-default-gw {% endif %} -{% if af_val.has_key('dad-enabled') and af_val.has_key('dad-max-moves') and af_val.has_key('dad-time') %} +{% if 'dad-enabled' in af_val and 'dad-max-moves' in af_val and 'dad-time' in af_val %} dup-addr-detection max-moves {{af_val['dad-max-moves']}} time {{af_val['dad-time']}} {% endif %} -{% if af_val.has_key('dad-freeze') %} +{% if 'dad-freeze' in af_val %} dup-addr-detection freeze {{af_val['dad-freeze']}} {% endif %} -{% if af_val.has_key('advertise-ipv4-unicast') and af_val['advertise-ipv4-unicast'] == 'true' %} +{% if 'advertise-ipv4-unicast' in af_val and af_val['advertise-ipv4-unicast'] == 'true' %} advertise ipv4 unicast {% endif %} -{% if af_val.has_key('advertise-ipv6-unicast') and af_val['advertise-ipv6-unicast'] == 'true' %} +{% if 'advertise-ipv6-unicast' in af_val and af_val['advertise-ipv6-unicast'] == 'true' %} advertise ipv6 unicast {% endif %} -{% if af_val.has_key('default-originate-ipv4') and af_val['default-originate-ipv4'] == 'true' %} +{% if 'default-originate-ipv4' in af_val and af_val['default-originate-ipv4'] == 'true' %} default-originate ipv4 {% endif %} -{% if af_val.has_key('default-originate-ipv6') and af_val['default-originate-ipv6'] == 'true' %} +{% if 'default-originate-ipv6' in af_val and af_val['default-originate-ipv6'] == 'true' %} default-originate ipv6 {% endif %} -{% if af_val.has_key('route-distinguisher') %} +{% if 'route-distinguisher' in af_val %} rd {{af_val['route-distinguisher']}} {% endif %} -{% if af_val.has_key('import-rts') %} +{% if 'import-rts' in af_val %} {% for irt in af_val['import-rts'] %} route-target import {{irt}} {% endfor %} {% endif %} -{% if af_val.has_key('export-rts') %} +{% if 'export-rts' in af_val %} {% for irt in af_val['export-rts'] %} route-target export {{irt}} {% endfor %} @@ -49,15 +49,15 @@ {% for vni_key, vni_val in BGP_GLOBALS_EVPN_VNI.iteritems() %} {% if vrf == vni_key[0] %} vni {{vni_key[2]}} -{% if vni_val.has_key('route-distinguisher') %} +{% if 'route-distinguisher' in vni_val %} rd {{vni_val['route-distinguisher']}} {% endif %} -{% if vni_val.has_key('import-rts') %} +{% if 'import-rts' in vni_val %} {% for irt in vni_val['import-rts'] %} route-target import {{irt}} {% endfor %} {% endif %} -{% if vni_val.has_key('export-rts') %} +{% if 'export-rts' in vni_val %} {% for irt in vni_val['export-rts'] %} route-target export {{irt}} {% endfor %} @@ -69,7 +69,7 @@ {% endif %} {% endfor %} {% endif %} -{% if vni_val.has_key('advertise-default-gw') and vni_val['advertise-default-gw'] == 'true' %} +{% if 'advertise-default-gw' in vni_val and vni_val['advertise-default-gw'] == 'true' %} advertise-default-gw {% endif %} exit-vni diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 index 220db779ac91..a0a98d5f6339 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 @@ -16,13 +16,13 @@ {% if BGP_GLOBALS_AF is defined and BGP_GLOBALS_AF|length > 0 %} {% for af_key, af_val in BGP_GLOBALS_AF.iteritems() %} {% if vrf == af_key[0] and af == af_key[1] %} -{% if af_val.has_key('ebgp_route_distance') and af_val.has_key('ibgp_route_distance') and af_val.has_key('local_route_distance') %} +{% if 'ebgp_route_distance' in af_val and 'ibgp_route_distance' in af_val and 'local_route_distance' in af_val %} distance bgp {{af_val['ebgp_route_distance']}} {{af_val['ibgp_route_distance']}} {{af_val['local_route_distance']}} {% endif %} -{% if af_val.has_key('import_vrf') %} +{% if 'import_vrf' in af_val %} import vrf {{af_val['import_vrf']}} {% endif %} -{% if af_val.has_key('import_vrf_route_map') %} +{% if 'import_vrf_route_map' in af_val %} import vrf route-map {{af_val['import_vrf_route_map']}} {% endif %} {% endif %} @@ -33,10 +33,10 @@ {% for af_nw_key, af_nw_val in BGP_GLOBALS_AF_NETWORK.iteritems() %} {% if vrf == af_nw_key[0] and af == af_nw_key[1] %} {% set af_nw_ns = namespace(nw_end = '') %} -{% if af_nw_val.has_key('backdoor') and af_nw_val['backdoor'] == 'true' %} +{% if 'backdoor' in af_nw_val and af_nw_val['backdoor'] == 'true' %} {% set af_nw_ns.nw_end = 'backdoor ' %} {% endif %} -{% if af_nw_val.has_key('policy') %} +{% if 'policy' in af_nw_val %} {% set af_nw_ns.nw_end = af_nw_ns.nw_end + 'route-map ' + af_nw_val['policy'] %} {% endif %} network {{af_nw_key[2]}} {{af_nw_ns.nw_end}} @@ -49,10 +49,10 @@ {% for af_ag_key, af_ag_val in BGP_GLOBALS_AF_AGGREGATE_ADDR.iteritems() %} {% set af_ag_ns = namespace(ag_end = '') %} {% if vrf == af_ag_key[0] and af == af_ag_key[1] %} -{% if af_ag_val.has_key('as_set') and af_ag_val['as_set'] == 'true' %} +{% if 'as_set' in af_ag_val and af_ag_val['as_set'] == 'true' %} {% set af_ag_ns.ag_end = 'as-set ' %} {% endif %} -{% if af_ag_val.has_key('summary_only') and af_ag_val['summary_only'] == 'true' %} +{% if 'summary_only' in af_ag_val and af_ag_val['summary_only'] == 'true' %} {% set af_ag_ns.ag_end = af_ag_ns.ag_end + 'summary-only' %} {% endif %} aggregate-address {{af_ag_key[2]}} {{af_ag_ns.ag_end}} @@ -64,7 +64,7 @@ {% if ROUTE_REDISTRIBUTE is defined and ROUTE_REDISTRIBUTE|length > 0 %} {% for rr_key, rr_val in ROUTE_REDISTRIBUTE.items() %} {% if vrf == rr_key[0] and af_str == rr_key[3] %} -{% if rr_val.has_key('route_map') %} +{% if 'route_map' in rr_val %} {% for rmap in rr_val['route_map'] %} redistribute {{rr_key[1]}} route-map {{rmap}} {% endfor %} @@ -99,15 +99,15 @@ {% for af_key, af_val in BGP_GLOBALS_AF.items() %} {% if vrf == af_key[0] and af == af_key[1] %} {# -------bgp dampen - start--------------------------- #} -{% if af_val.has_key('route_flap_dampen') and af_val['route_flap_dampen'] == 'true' %} +{% if 'route_flap_dampen' in af_val and af_val['route_flap_dampen'] == 'true' %} {% set ns = namespace(route_dampen = '') %} -{% if af_val.has_key('route_flap_dampen_half_life') %} +{% if 'route_flap_dampen_half_life' in af_val %} {% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_half_life'] + ' ' %} -{% if af_val.has_key('route_flap_dampen_reuse_threshold') %} +{% if 'route_flap_dampen_reuse_threshold' in af_val %} {% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_reuse_threshold'] + ' ' %} -{% if af_val.has_key('route_flap_dampen_suppress_threshold') %} +{% if 'route_flap_dampen_suppress_threshold' in af_val %} {% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_suppress_threshold'] + ' ' %} -{% if af_val.has_key('route_flap_dampen_max_suppress') %} +{% if 'route_flap_dampen_max_suppress' in af_val %} {% set ns.route_dampen = ns.route_dampen + af_val['route_flap_dampen_max_suppress'] + ' ' %} {% endif %} {% endif %} @@ -116,17 +116,17 @@ bgp dampening {{ns.route_dampen}} {% endif %} {# -------bgp dampen - end --------------------------- #} -{% if af_val.has_key('max_ebgp_paths') %} +{% if 'max_ebgp_paths' in af_val %} maximum-paths {{af_val['max_ebgp_paths']}} {% endif %} -{% if af_val.has_key('max_ibgp_paths') %} +{% if 'max_ibgp_paths' in af_val %} {% set ns = namespace(max_ibgp = af_val['max_ibgp_paths']) %} -{% if af_val.has_key('ibgp_equal_cluster_length') and af_val['ibgp_equal_cluster_length'] == 'true' %} +{% if 'ibgp_equal_cluster_length' in af_val and af_val['ibgp_equal_cluster_length'] == 'true' %} {% set ns.max_ibgp = ns.max_ibgp + ' equal-cluster-length' %} {% endif %} maximum-paths ibgp {{ns.max_ibgp}} {% endif %} -{% if af_val.has_key('route_download_filter') %} +{% if 'route_download_filter' in af_val %} table-map {{af_val['route_download_filter']}} {% endif %} {# -------bgp evpn - start --------------------------- #} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 index e61b98c164b7..3fcce07ddc9c 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 @@ -6,7 +6,7 @@ {# ------------------------------------------------------------------------------------ #} {% if COMMUNITY_SET is defined and COMMUNITY_SET|length > 0 %} {% for cm_key, cm_val in COMMUNITY_SET.items() %} -{% if cm_val.has_key('set_type') and cm_val.has_key('match_action') and cm_val.has_key('community_member') %} +{% if 'set_type' in cm_val and 'match_action' in cm_val and 'community_member' in cm_val %} {% if cm_val['match_action']|lower == 'all' %} {% set ns = namespace(cm_list = '') %} {% for cm in cm_val['community_member'] %} @@ -24,7 +24,7 @@ bgp community-list {{cm_val['set_type']|lower}} {{cm_key}} permit {{cm}} {# ------------------------------------------------------------------------------------ #} {% if EXTENDED_COMMUNITY_SET is defined and EXTENDED_COMMUNITY_SET|length > 0 %} {% for cm_key, cm_val in EXTENDED_COMMUNITY_SET.items() %} -{% if cm_val.has_key('set_type') and cm_val.has_key('match_action') and cm_val.has_key('community_member') %} +{% if 'set_type' in cm_val and 'match_action' in cm_val and 'community_member' in cm_val %} {% if cm_val['match_action']|lower == 'all' %} {% set ns = namespace(cm_list = '') %} {% for cm in cm_val['community_member'] %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 index e081e9de6f3c..cd3af528a442 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 @@ -7,7 +7,7 @@ {% if AS_PATH_SET is defined and AS_PATH_SET|length > 0 %} ! {% for key, val in AS_PATH_SET.items() %} -{% if val.has_key('as_path_set_member') %} +{% if 'as_path_set_member' in val %} {% for path in val['as_path_set_member'] %} bgp as-path access-list {{key}} permit {{path}} {% endfor %} @@ -19,135 +19,135 @@ bgp as-path access-list {{key}} permit {{path}} {# ------------------------------------------------------------------------------------ #} {% if BGP_GLOBALS is defined and BGP_GLOBALS|length > 0 %} {% for vrf, bgp_sess in BGP_GLOBALS.items() %} -{% if bgp_sess.has_key('local_asn') %} +{% if 'local_asn' in bgp_sess %} ! {% if vrf == 'default' %} router bgp {{ bgp_sess['local_asn']}} {% else %} router bgp {{ bgp_sess['local_asn']}} vrf {{ vrf }} {% endif %} -{% if bgp_sess.has_key('fast_external_failover') and bgp_sess['fast_external_failover'] == 'false' %} +{% if 'fast_external_failover' in bgp_sess and bgp_sess['fast_external_failover'] == 'false' %} no bgp fast-external-failover {% endif %} -{% if bgp_sess.has_key('router_id') %} +{% if 'router_id' in bgp_sess %} bgp router-id {{bgp_sess['router_id']}} {% endif %} -{% if bgp_sess.has_key('log_nbr_state_changes') and bgp_sess['log_nbr_state_changes'] == 'true' %} +{% if 'log_nbr_state_changes' in bgp_sess and bgp_sess['log_nbr_state_changes'] == 'true' %} bgp log-neighbor-changes {% endif %} -{% if bgp_sess.has_key('always_compare_med') and bgp_sess['always_compare_med'] == 'true' %} +{% if 'always_compare_med' in bgp_sess and bgp_sess['always_compare_med'] == 'true' %} bgp always-compare-med {% endif %} {# --------------------------bgp default - start -------------------------------------- #} -{% if bgp_sess.has_key('default_ipv4_unicast') and bgp_sess['default_ipv4_unicast'] == 'true' %} +{% if 'default_ipv4_unicast' in bgp_sess and bgp_sess['default_ipv4_unicast'] == 'true' %} bgp default ipv4-unicast {% else %} no bgp default ipv4-unicast {% endif %} -{% if bgp_sess.has_key('default_local_preference') %} +{% if 'default_local_preference' in bgp_sess %} bgp default local-preference {{bgp_sess['default_local_preference']}} {% endif %} -{% if bgp_sess.has_key('default_show_hostname') and bgp_sess['default_show_hostname'] == 'true' %} +{% if 'default_show_hostname' in bgp_sess and bgp_sess['default_show_hostname'] == 'true' %} bgp default show-hostname {% endif %} -{% if bgp_sess.has_key('default_shutdown') and bgp_sess['default_shutdown'] == 'true' %} +{% if 'default_shutdown' in bgp_sess and bgp_sess['default_shutdown'] == 'true' %} bgp default shutdown {% endif %} -{% if bgp_sess.has_key('default_subgroup_pkt_queue_max') %} +{% if 'default_subgroup_pkt_queue_max' in bgp_sess %} bgp default subgroup-pkt-queue-max {{bgp_sess['default_subgroup_pkt_queue_max']}} {% endif %} {# --------------------------bgp default - end ---------------------------------------- #} -{% if bgp_sess.has_key('rr_clnt_to_clnt_reflection') and bgp_sess['rr_clnt_to_clnt_reflection'] == 'false' %} +{% if 'rr_clnt_to_clnt_reflection' in bgp_sess and bgp_sess['rr_clnt_to_clnt_reflection'] == 'false' %} no bgp client-to-client reflection {% endif %} -{% if bgp_sess.has_key('rr_cluster_id') %} +{% if 'rr_cluster_id' in bgp_sess %} bgp cluster-id {{bgp_sess['rr_cluster_id']}} {% endif %} -{% if bgp_sess.has_key('disable_ebgp_connected_rt_check') and bgp_sess['disable_ebgp_connected_rt_check'] == 'true' %} +{% if 'disable_ebgp_connected_rt_check' in bgp_sess and bgp_sess['disable_ebgp_connected_rt_check'] == 'true' %} bgp disable-ebgp-connected-route-check {% endif %} -{% if bgp_sess.has_key('deterministic_med') and bgp_sess['deterministic_med'] == 'true' %} +{% if 'deterministic_med' in bgp_sess and bgp_sess['deterministic_med'] == 'true' %} bgp deterministic-med {% endif %} -{% if bgp_sess.has_key('max_delay') %} +{% if 'max_delay' in bgp_sess %} {% set ns = namespace(max_delay = '') %} {% set ns.max_delay = ns.max_delay + bgp_sess['max_delay'] %} -{% if bgp_sess.has_key('establish_wait') %} +{% if 'establish_wait' in bgp_sess %} {% set ns.max_delay = ns.max_delay + ' ' + bgp_sess['establish_wait'] %} {% endif %} update-delay {{ns.max_delay}} {% endif %} -{% if bgp_sess.has_key('max_med_time') %} +{% if 'max_med_time' in bgp_sess %} {% set ns = namespace(max_med = '') %} {% set ns.max_med = ns.max_med + bgp_sess['max_med_time'] %} -{% if bgp_sess.has_key('max_med_val') %} +{% if 'max_med_val' in bgp_sess %} {% set ns.max_med = ns.max_med + ' ' + bgp_sess['max_med_val'] %} {% endif %} bgp max-med on-startup {{ns.max_med}} {% endif %} -{% if bgp_sess.has_key('max_med_admin') %} +{% if 'max_med_admin' in bgp_sess %} {% set adm_ns = namespace(admin_val = '') %} -{% if bgp_sess.has_key('max_med_admin_val') %} +{% if 'max_med_admin_val' in bgp_sess %} {% set adm_ns.admin_val = adm_ns.admin_val + ' ' + bgp_sess['max_med_admin_val'] %} {% endif %} bgp max-med administrative {{adm_ns.admin_val}} {% endif %} -{% if bgp_sess.has_key('read_quanta') %} +{% if 'read_quanta' in bgp_sess %} read-quanta {{bgp_sess['read_quanta']}} {% endif %} -{% if bgp_sess.has_key('write_quanta') %} +{% if 'write_quanta' in bgp_sess %} write-quanta {{bgp_sess['write_quanta']}} {% endif %} -{% if bgp_sess.has_key('coalesce_time') %} +{% if 'coalesce_time' in bgp_sess %} coalesce-time {{bgp_sess['coalesce_time']}} {% endif %} {# --------------------------bgp graceful-restart - start ----------------------------- #} -{% if bgp_sess.has_key('gr_stale_routes_time') %} +{% if 'gr_stale_routes_time' in bgp_sess %} bgp graceful-restart stalepath-time {{bgp_sess['gr_stale_routes_time']}} {% endif %} -{% if bgp_sess.has_key('gr_restart_time') %} +{% if 'gr_restart_time' in bgp_sess %} bgp graceful-restart restart-time {{bgp_sess['gr_restart_time']}} {% endif %} -{% if bgp_sess.has_key('graceful_restart_enable') and bgp_sess['graceful_restart_enable'] == 'true' %} +{% if 'graceful_restart_enable' in bgp_sess and bgp_sess['graceful_restart_enable'] == 'true' %} bgp graceful-restart {% endif %} -{% if bgp_sess.has_key('graceful_shutdown') and bgp_sess['graceful_shutdown'] == 'true' %} +{% if 'graceful_shutdown' in bgp_sess and bgp_sess['graceful_shutdown'] == 'true' %} bgp graceful-shutdown {% endif %} -{% if bgp_sess.has_key('gr_preserve_fw_state') and bgp_sess['gr_preserve_fw_state'] == 'true' %} +{% if 'gr_preserve_fw_state' in bgp_sess and bgp_sess['gr_preserve_fw_state'] == 'true' %} bgp graceful-restart preserve-fw-state {% endif %} {# --------------------------bgp graceful-restart - end ----------------------------- #} {# --------------------------bgp bestpath as-path - start ----------------------------- #} -{% if bgp_sess.has_key('ignore_as_path_length') %} +{% if 'ignore_as_path_length' in bgp_sess %} bgp bestpath as-path ignore {% endif %} -{% if bgp_sess.has_key('compare_confed_as_path') and bgp_sess['compare_confed_as_path'] == 'true' %} +{% if 'compare_confed_as_path' in bgp_sess and bgp_sess['compare_confed_as_path'] == 'true' %} bgp bestpath as-path confed {% endif %} -{% if bgp_sess.has_key('load_balance_mp_relax') and bgp_sess['load_balance_mp_relax'] == 'true' %} +{% if 'load_balance_mp_relax' in bgp_sess and bgp_sess['load_balance_mp_relax'] == 'true' %} {% set mp_ns = namespace(mp_val = '') %} -{% if bgp_sess.has_key('as_path_mp_as_set') and bgp_sess['as_path_mp_as_set'] == 'true' %} +{% if 'as_path_mp_as_set' in bgp_sess and bgp_sess['as_path_mp_as_set'] == 'true' %} {% set mp_ns.mp_val = mp_ns.mp_val + 'as-set' %} -{% elif bgp_sess.has_key('as_path_mp_as_set') and bgp_sess['as_path_mp_as_set'] == 'false' %} +{% elif 'as_path_mp_as_set' in bgp_sess and bgp_sess['as_path_mp_as_set'] == 'false' %} {% set mp_ns.mp_val = mp_ns.mp_val + 'no-as-set' %} {% endif %} bgp bestpath as-path multipath-relax {{mp_ns.mp_val}} {% endif %} {# --------------------------bgp bestpath as-path - end ----------------------------- #} -{% if bgp_sess.has_key('rr_allow_out_policy') and bgp_sess['rr_allow_out_policy'] == 'true' %} +{% if 'rr_allow_out_policy' in bgp_sess and bgp_sess['rr_allow_out_policy'] == 'true' %} bgp route-reflector allow-outbound-policy {% endif %} -{% if bgp_sess.has_key('external_compare_router_id') %} +{% if 'external_compare_router_id' in bgp_sess %} bgp bestpath compare-routerid {% endif %} -{% if bgp_sess.has_key('med_confed') and bgp_sess['med_confed'] == 'true' %} +{% if 'med_confed' in bgp_sess and bgp_sess['med_confed'] == 'true' %} bgp bestpath med confed {% endif %} -{% if bgp_sess.has_key('med_missing_as_worst') and bgp_sess['med_missing_as_worst'] == 'true' %} +{% if 'med_missing_as_worst' in bgp_sess and bgp_sess['med_missing_as_worst'] == 'true' %} bgp bestpath med confed missing-as-worst {% endif %} -{% if bgp_sess.has_key('network_import_check') and bgp_sess['network_import_check'] == 'true' %} +{% if 'network_import_check' in bgp_sess and bgp_sess['network_import_check'] == 'true' %} bgp network import-check {% endif %} {# -------globals end --------------------------- #} @@ -175,17 +175,17 @@ router bgp {{ bgp_sess['local_asn']}} vrf {{ vrf }} {% endfor %} {% endif %} {# -------neighbor end --------------------------- #} -{% if bgp_sess.has_key('max_dynamic_neighbors') %} +{% if 'max_dynamic_neighbors' in bgp_sess %} bgp listen limit {{bgp_sess['max_dynamic_neighbors']}} {% endif %} -{% if bgp_sess.has_key('route_map_process_delay') %} +{% if 'route_map_process_delay' in bgp_sess %} bgp route-map delay-timer {{bgp_sess['route_map_process_delay']}} {% endif %} {# -------listen-prefix --------------------------- #} {% if BGP_GLOBALS_LISTEN_PREFIX is defined and BGP_GLOBALS_LISTEN_PREFIX|length > 0 %} {% for lpfx, lpfx_val in BGP_GLOBALS_LISTEN_PREFIX.items() %} {% if vrf == lpfx[0] %} -{% if lpfx_val.has_key('peer_group') %} +{% if 'peer_group' in lpfx_val %} bgp listen range {{lpfx[1]}} peer-group {{lpfx_val['peer_group']}} {% endif %} {% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 index 41d309e4ef3e..8afb64e991cc 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 @@ -1,38 +1,38 @@ {# ------------------------------------------------------------ #} {# this is called with the "vrf" and "address-family matched #} {# ------------------------------------------------------------ #} -{% if n_af_val.has_key('admin_status') %} +{% if 'admin_status' in n_af_val %} {% if n_af_val['admin_status'] == 'true' %} neighbor {{nbr_name}} activate {% else %} no neighbor {{nbr_name}} activate {% endif %} {% endif %} -{% if n_af_val.has_key('tx_add_paths') %} +{% if 'tx_add_paths' in n_af_val %} {% if n_af_val['tx_add_paths'] == 'tx_all_paths' %} neighbor {{nbr_name}} addpath-tx-all-paths {% elif n_af_val['tx_add_paths'] == 'tx_best_path_per_as' %} neighbor {{nbr_name}} addpath-tx-bestpath-per-AS {% endif %} {% endif %} -{% if n_af_val.has_key('nhself') and n_af_val['nhself'] == 'true' %} -{% if n_af_val.has_key('nexthop_self_force') and n_af_val['nexthop_self_force'] == 'true' %} +{% if 'nhself' in n_af_val and n_af_val['nhself'] == 'true' %} +{% if 'nexthop_self_force' in n_af_val and n_af_val['nexthop_self_force'] == 'true' %} neighbor {{nbr_name}} next-hop-self force {% else %} neighbor {{nbr_name}} next-hop-self {% endif %} {% endif %} -{% if n_af_val.has_key('remove_private_as_enabled') and n_af_val['remove_private_as_enabled'] == 'true' %} +{% if 'remove_private_as_enabled' in n_af_val and n_af_val['remove_private_as_enabled'] == 'true' %} {% set ns = namespace(rpas_str='') %} -{% if n_af_val.has_key('remove_private_as_all') and n_af_val['remove_private_as_all'] == 'true' %} +{% if 'remove_private_as_all' in n_af_val and n_af_val['remove_private_as_all'] == 'true' %} {% set ns.rpas_str = ns.rpas_str + ' all' %} {% endif %} -{% if n_af_val.has_key('replace_private_as') and n_af_val['replace_private_as'] == 'true' %} +{% if 'replace_private_as' in n_af_val and n_af_val['replace_private_as'] == 'true' %} {% set ns.rpas_str = ns.rpas_str + ' replace-AS' %} {% endif %} neighbor {{nbr_name}} remove-private-AS{{ns.rpas_str}} {% endif %} -{% if n_af_val.has_key('send_community') %} +{% if 'send_community' in n_af_val %} {% if n_af_val['send_community'] == 'standard' %} no neighbor {{nbr_name}} send-community extended no neighbor {{nbr_name}} send-community large @@ -48,100 +48,100 @@ no neighbor {{nbr_name}} send-community all {% endif %} {% endif %} -{% if n_af_val.has_key('as_override') and n_af_val['as_override'] == 'true' %} +{% if 'as_override' in n_af_val and n_af_val['as_override'] == 'true' %} neighbor {{nbr_name}} as-override {% endif %} -{% if n_af_val.has_key('send_default_route') and n_af_val['send_default_route'] == 'true' %} -{% if n_af_val.has_key('default_rmap') %} +{% if 'send_default_route' in n_af_val and n_af_val['send_default_route'] == 'true' %} +{% if 'default_rmap' in n_af_val %} neighbor {{nbr_name}} default-originate route-map {{n_af_val['default_rmap']}} {% else %} neighbor {{nbr_name}} default-originate {% endif %} {% endif %} -{% if n_af_val.has_key('rrclient') and n_af_val['rrclient'] == 'true' %} +{% if 'rrclient' in n_af_val and n_af_val['rrclient'] == 'true' %} neighbor {{nbr_name}} route-reflector-client {% endif %} -{% if n_af_val.has_key('soft_reconfiguration_in') and n_af_val['soft_reconfiguration_in'] == 'true' %} +{% if 'soft_reconfiguration_in' in n_af_val and n_af_val['soft_reconfiguration_in'] == 'true' %} neighbor {{nbr_name}} soft-reconfiguration inbound {% endif %} {# ------- maximum-prefix --------------------------- #} -{% if n_af_val.has_key('max_prefix_limit') %} +{% if 'max_prefix_limit' in n_af_val %} {% set ns = namespace(mpfx_str='maximum-prefix ' + n_af_val['max_prefix_limit']) %} -{% if n_af_val.has_key('max_prefix_warning_threshold') %} +{% if 'max_prefix_warning_threshold' in n_af_val %} {% set ns.mpfx_str = ns.mpfx_str + ' ' + n_af_val['max_prefix_warning_threshold'] %} {% endif %} -{% if n_af_val.has_key('max_prefix_restart_interval') %} +{% if 'max_prefix_restart_interval' in n_af_val %} {% set ns.mpfx_str = ns.mpfx_str + ' restart ' + n_af_val['max_prefix_restart_interval'] %} -{% elif n_af_val.has_key('max_prefix_warning_only') and n_af_val['max_prefix_warning_only'] == 'true' %} +{% elif 'max_prefix_warning_only' in n_af_val and n_af_val['max_prefix_warning_only'] == 'true' %} {% set ns.mpfx_str = ns.mpfx_str + ' warning-only' %} {% endif %} neighbor {{nbr_name}} {{ns.mpfx_str}} {% endif %} {# ------- maximum-prefix end --------------------------- #} -{% if n_af_val.has_key('route_server_client') and n_af_val['route_server_client'] == 'true' %} +{% if 'route_server_client' in n_af_val and n_af_val['route_server_client'] == 'true' %} neighbor {{nbr_name}} route-server-client {% endif %} {# ------- allow-as --------------------------- #} -{% if n_af_val.has_key('allow_as_in') and n_af_val['allow_as_in'] == 'true' %} -{% if n_af_val.has_key('allow_as_origin') and n_af_val['allow_as_origin'] == 'true' %} +{% if 'allow_as_in' in n_af_val and n_af_val['allow_as_in'] == 'true' %} +{% if 'allow_as_origin' in n_af_val and n_af_val['allow_as_origin'] == 'true' %} neighbor {{nbr_name}} allowas-in origin -{% elif n_af_val.has_key('allow_as_count') %} +{% elif 'allow_as_count' in n_af_val %} neighbor {{nbr_name}} allowas-in {{n_af_val['allow_as_count']}} {% else %} neighbor {{nbr_name}} allowas-in {% endif %} {% endif %} {# ------- allow-as end --------------------------- #} -{% if n_af_val.has_key('add_path_tx_all') and n_af_val['add_path_tx_all'] == 'true' %} +{% if 'add_path_tx_all' in n_af_val and n_af_val['add_path_tx_all'] == 'true' %} neighbor {{nbr_name}} addpath-tx-all-paths {% endif %} -{% if n_af_val.has_key('add_path_tx_bestpath') and n_af_val['add_path_tx_bestpath'] == 'true' %} +{% if 'add_path_tx_bestpath' in n_af_val and n_af_val['add_path_tx_bestpath'] == 'true' %} neighbor {{nbr_name}} addpath-tx-bestpath-per-AS {% endif %} -{% if n_af_val.has_key('cap_orf') %} +{% if 'cap_orf' in n_af_val %} neighbor {{nbr_name}} capability orf prefix-list {{n_af_val['cap_orf']}} {% endif %} -{% if n_af_val.has_key('weight') %} +{% if 'weight' in n_af_val %} neighbor {{nbr_name}} weight {{n_af_val['weight']}} {% endif %} -{% if n_af_val.has_key('prefix_list_in') %} +{% if 'prefix_list_in' in n_af_val %} neighbor {{nbr_name}} prefix-list {{n_af_val['prefix_list_in']}} in {% endif %} -{% if n_af_val.has_key('prefix_list_out') %} +{% if 'prefix_list_out' in n_af_val %} neighbor {{nbr_name}} prefix-list {{n_af_val['prefix_list_out']}} out {% endif %} {# ------- route-map in --------------------------- #} -{% if n_af_val.has_key('route_map_in') %} +{% if 'route_map_in' in n_af_val %} {% for map in n_af_val['route_map_in'] %} neighbor {{nbr_name}} route-map {{map}} in {% endfor %} {% endif %} {# ------- route-map in end --------------------------- #} {# ------- route-map out --------------------------- #} -{% if n_af_val.has_key('route_map_out') %} +{% if 'route_map_out' in n_af_val %} {% for map in n_af_val['route_map_out'] %} neighbor {{nbr_name}} route-map {{map}} out {% endfor %} {% endif %} {# ------- route-map out end --------------------------- #} -{% if n_af_val.has_key('unsuppress_map_name') %} +{% if 'unsuppress_map_name' in n_af_val %} neighbor {{nbr_name}} unsuppress-map {{n_af_val['unsuppress_map_name']}} {% endif %} -{% if n_af_val.has_key('filter_list_in') %} +{% if 'filter_list_in' in n_af_val %} neighbor {{nbr_name}} filter-list {{n_af_val['filter_list_in']}} in {% endif %} -{% if n_af_val.has_key('filter_list_out') %} +{% if 'filter_list_out' in n_af_val %} neighbor {{nbr_name}} filter-list {{n_af_val['filter_list_out']}} out {% endif %} {# ------- attribute-unchanged --------------------------- #} {% set attr = '' %} -{% if n_af_val.has_key('unchanged_as_path') and n_af_val['unchanged_as_path'] == 'true' %} +{% if 'unchanged_as_path' in n_af_val and n_af_val['unchanged_as_path'] == 'true' %} {% set attr = 'as-path ' %} {% endif %} -{% if n_af_val.has_key('unchanged_med') and n_af_val['unchanged_med'] == 'true' %} +{% if 'unchanged_med' in n_af_val and n_af_val['unchanged_med'] == 'true' %} {% set attr = attr + 'med ' %} {% endif %} -{% if n_af_val.has_key('unchanged_nexthop') and n_af_val['unchanged_nexthop'] == 'true' %} +{% if 'unchanged_nexthop' in n_af_val and n_af_val['unchanged_nexthop'] == 'true' %} {% set attr = attr + 'next-hop' %} {% endif %} {% if attr != '' %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 index 1ecf4fa04135..8fc5e061ad56 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 @@ -12,92 +12,92 @@ {% endif %} {% endif %} {% set remote_as = '' %} -{% if nbr_or_peer.has_key('asn') %} +{% if 'asn' in nbr_or_peer %} {% set remote_as = nbr_or_peer['asn'] %} {% endif %} -{% if nbr_or_peer.has_key('peer_type') %} +{% if 'peer_type' in nbr_or_peer %} {% set remote_as = nbr_or_peer['peer_type'] %} {% endif %} {% if remote_as != '' %} neighbor {{name_or_ip}} {{ns_intf.intf_arg}}remote-as {{remote_as}} {% endif %} -{% if nbr_or_peer.has_key('peer_group_name') %} +{% if 'peer_group_name' in nbr_or_peer %} neighbor {{name_or_ip}} {{ns_intf.intf_arg}}peer-group {{nbr_or_peer['peer_group_name']}} {% endif %} -{% if nbr_or_peer.has_key('local_asn') %} +{% if 'local_asn' in nbr_or_peer %} neighbor {{name_or_ip}} local-as {{nbr_or_peer['local_asn']}} {% endif %} -{% if nbr_or_peer.has_key('name') %} +{% if 'name' in nbr_or_peer %} neighbor {{name_or_ip}} description {{nbr_or_peer['name']}} {% endif %} -{% if nbr_or_peer.has_key('admin_status') and nbr_or_peer['admin_status'] == 'false' %} -{% if nbr_or_peer.has_key('shutdown_message') %} +{% if 'admin_status' in nbr_or_peer and nbr_or_peer['admin_status'] == 'false' %} +{% if 'shutdown_message' in nbr_or_peer %} neighbor {{name_or_ip}} shutdown message {{nbr_or_peer['shutdown_message']}} {% else %} neighbor {{name_or_ip}} shutdown {% endif %} {% endif %} -{% if nbr_or_peer.has_key('bfd') and nbr_or_peer['bfd'] == 'true' %} +{% if 'bfd' in nbr_or_peer and nbr_or_peer['bfd'] == 'true' %} neighbor {{name_or_ip}} bfd {% endif %} -{% if nbr_or_peer.has_key('ttl_security_hops') %} +{% if 'ttl_security_hops' in nbr_or_peer %} neighbor {{name_or_ip}} ttl-security hops {{nbr_or_peer['ttl_security_hops']}} {% endif %} -{% if nbr_or_peer.has_key('auth_password') %} +{% if 'auth_password' in nbr_or_peer %} neighbor {{name_or_ip}} password {{nbr_or_peer['auth_password']}} encrypted {% endif %} -{% if nbr_or_peer.has_key('solo_peer') and nbr_or_peer['solo_peer'] == 'true' %} +{% if 'solo_peer' in nbr_or_peer and nbr_or_peer['solo_peer'] == 'true' %} neighbor {{name_or_ip}} solo {% endif %} -{% if nbr_or_peer.has_key('peer_port') %} +{% if 'peer_port' in nbr_or_peer %} neighbor {{name_or_ip}} port {{nbr_or_peer['peer_port']}} {% endif %} -{% if nbr_or_peer.has_key('passive_mode') and nbr_or_peer['passive_mode'] == 'true' %} +{% if 'passive_mode' in nbr_or_peer and nbr_or_peer['passive_mode'] == 'true' %} neighbor {{name_or_ip}} passive {% endif %} {% set mhop = '' %} -{% if nbr_or_peer.has_key('ebgp_multihop') and nbr_or_peer['ebgp_multihop'] == 'true' %} +{% if 'ebgp_multihop' in nbr_or_peer and nbr_or_peer['ebgp_multihop'] == 'true' %} {% set mhop = 255 %} {% endif %} -{% if nbr_or_peer.has_key('ebgp_multihop_ttl') %} +{% if 'ebgp_multihop_ttl' in nbr_or_peer %} {% set mhop = nbr_or_peer['ebgp_multihop_ttl'] %} {% endif %} {% if mhop != '' %} neighbor {{name_or_ip}} ebgp-multihop {{mhop}} {% endif %} -{% if nbr_or_peer.has_key('disable_ebgp_connected_route_check') and nbr_or_peer['disable_ebgp_connected_route_check'] == 'true' %} +{% if 'disable_ebgp_connected_route_check' in nbr_or_peer and nbr_or_peer['disable_ebgp_connected_route_check'] == 'true' %} neighbor {{name_or_ip}} disable-connected-check {% endif %} -{% if nbr_or_peer.has_key('enforce_first_as') and nbr_or_peer['enforce_first_as'] == 'true' %} +{% if 'enforce_first_as' in nbr_or_peer and nbr_or_peer['enforce_first_as'] == 'true' %} neighbor {{name_or_ip}} enforce-first-as {% endif %} -{% if nbr_or_peer.has_key('local_addr') %} +{% if 'local_addr' in nbr_or_peer %} neighbor {{name_or_ip}} update-source {{nbr_or_peer['local_addr']}} {% endif %} -{% if nbr_or_peer.has_key('strict_capability_match') and nbr_or_peer['strict_capability_match'] == true %} +{% if 'strict_capability_match' in nbr_or_peer and nbr_or_peer['strict_capability_match'] == true %} neighbor {{name_or_ip}} strict-capability-match {{nbr_or_peer['strict_capability_match']}} {% endif %} -{% if nbr_or_peer.has_key('min_adv_interval') %} +{% if 'min_adv_interval' in nbr_or_peer %} neighbor {{name_or_ip}} advertisement-interval {{nbr_or_peer['min_adv_interval']}} {% endif %} -{% if nbr_or_peer.has_key('keepalive') and nbr_or_peer.has_key('holdtime') %} +{% if 'keepalive' in nbr_or_peer and 'holdtime' in nbr_or_peer %} neighbor {{name_or_ip}} timers {{nbr_or_peer['keepalive']}} {{nbr_or_peer['holdtime']}} {% endif %} -{% if nbr_or_peer.has_key('conn_retry') %} +{% if 'conn_retry' in nbr_or_peer %} neighbor {{name_or_ip}} timers connect {{nbr_or_peer['conn_retry']}} {% endif %} -{% if nbr_or_peer.has_key('capability_dynamic') and nbr_or_peer['capability_dynamic'] == 'true' %} +{% if 'capability_dynamic' in nbr_or_peer and nbr_or_peer['capability_dynamic'] == 'true' %} neighbor {{name_or_ip}} capability dynamic {% endif %} -{% if nbr_or_peer.has_key('capability_ext_nexthop') and nbr_or_peer['capability_ext_nexthop'] == 'true' %} +{% if 'capability_ext_nexthop' in nbr_or_peer and nbr_or_peer['capability_ext_nexthop'] == 'true' %} neighbor {{name_or_ip}} capability extended-nexthop {% endif %} -{% if nbr_or_peer.has_key('dont_negotiate_capability') and nbr_or_peer['dont_negotiate_capability'] == 'true' %} +{% if 'dont_negotiate_capability' in nbr_or_peer and nbr_or_peer['dont_negotiate_capability'] == 'true' %} neighbor {{name_or_ip}} dont-capability-negotiate {% endif %} -{% if nbr_or_peer.has_key('enforce_multihop') and nbr_or_peer['enforce_multihop'] == 'true' %} +{% if 'enforce_multihop' in nbr_or_peer and nbr_or_peer['enforce_multihop'] == 'true' %} neighbor {{name_or_ip}} enforce-multihop {% endif %} -{% if nbr_or_peer.has_key('override_capability') and nbr_or_peer['override_capability'] == 'true' %} +{% if 'override_capability' in nbr_or_peer and nbr_or_peer['override_capability'] == 'true' %} neighbor {{name_or_ip}} override-capability {% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 index b13cf6f6189a..3409c51be06f 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 @@ -6,7 +6,7 @@ {% for md in modes %} ! {% for key, val in PREFIX_SET.items() %} -{% if val.has_key('mode') %} +{% if 'mode' in val %} {% for pf_key, pf_val in PREFIX.items() %} {% if pf_key[0] == key and md == val['mode'] %} {% if pf_key[2] == 'exact' %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 index a7a9cb1012e2..29a4817dc281 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 @@ -1,40 +1,40 @@ {% if ROUTE_MAP is defined and ROUTE_MAP|length > 0 %} {% for rm_key, rm_val in ROUTE_MAP.items() %} -{% if rm_val.has_key('route_operation') %} +{% if 'route_operation' in rm_val %} ! route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} -{% if rm_val.has_key('match_as_path') %} +{% if 'match_as_path' in rm_val %} match as-path {{rm_val['match_as_path']}} {% endif %} -{% if rm_val.has_key('call_route_map') %} +{% if 'call_route_map' in rm_val %} call {{rm_val['call_route_map']}} {% endif %} -{% if rm_val.has_key('match_community') %} +{% if 'match_community' in rm_val %} match community {{rm_val['match_community']}} {% endif %} -{% if rm_val.has_key('match_ext_community') %} +{% if 'match_ext_community' in rm_val %} match extcommunity {{rm_val['match_ext_community']}} {% endif %} -{% if rm_val.has_key('match_interface') %} +{% if 'match_interface' in rm_val %} match interface {{rm_val['match_interface']}} {% endif %} -{% if rm_val.has_key('match_tag') %} +{% if 'match_tag' in rm_val %} match tag {{rm_val['match_tag'][0]}} {% endif %} -{% if rm_val.has_key('match_src_vrf') %} +{% if 'match_src_vrf' in rm_val %} match source-vrf {{rm_val['match_src_vrf']}} {% endif %} {# ---------------match ip/ipv6-Start-------------------------- #} {% set ip_str = {'ipv4':'ip', 'ipv6':'ipv6' } %} {% if PREFIX_SET is defined and PREFIX_SET|length > 0 %} -{% if rm_val.has_key('match_prefix_set') %} +{% if 'match_prefix_set' in rm_val %} {% for pfx_key, pfx_val in PREFIX_SET.items() %} {% if rm_val['match_prefix_set'] == pfx_key %} match {{ip_str[pfx_val['mode']]}} address prefix-list {{rm_val['match_prefix_set']}} {% endif %} {% endfor %} {% endif %} -{% if rm_val.has_key('match_next_hop_set') %} +{% if 'match_next_hop_set' in rm_val %} {% for pfx_key, pfx_val in PREFIX_SET.items() %} {% if rm_val['match_next_hop_set'] == pfx_key %} match {{ip_str[pfx_val['mode']]}} next-hop prefix-list {{rm_val['match_next_hop_set']}} @@ -43,23 +43,23 @@ route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} {% endif %} {% endif %} {# ---------------match ip/ipv6- End-------------------------- #} -{% if rm_val.has_key('match_local_pref') %} +{% if 'match_local_pref' in rm_val %} match local-preference {{rm_val['match_local_pref']}} {% endif %} -{% if rm_val.has_key('match_med') %} +{% if 'match_med' in rm_val %} match metric {{rm_val['match_med']}} {% endif %} -{% if rm_val.has_key('match_origin') %} +{% if 'match_origin' in rm_val %} match origin {{rm_val['match_origin']|lower}} {% endif %} -{% if rm_val.has_key('match_neighbor') %} +{% if 'match_neighbor' in rm_val %} match peer {{rm_val['match_neighbor'][0]}} {% endif %} -{% if rm_val.has_key('match_protocol') %} +{% if 'match_protocol' in rm_val %} match source-protocol {{rm_val['match_protocol']}} {% endif %} {# ---------------set as-path prepend - Start ----------------- #} -{% if rm_val.has_key('set_asn') and rm_val.has_key('set_repeat_asn') %} +{% if 'set_asn' in rm_val and 'set_repeat_asn' in rm_val %} {% set ns = namespace(as_str='') %} {% if rm_val['set_repeat_asn'] > 0 %} {% for i in range(rm_val['set_repeat_asn']|int) %} @@ -72,7 +72,7 @@ route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} {% endif %} {# ---------------set as-path prepend - End ------------------- #} {# ---------------set community - Start------------------------ #} -{% if rm_val.has_key('set_community_inline') %} +{% if 'set_community_inline' in rm_val %} {% set ns = namespace(comms = '') %} {% for cm in rm_val['set_community_inline'] %} {% set ns.comms = ns.comms + ' ' + cm %} @@ -80,11 +80,11 @@ route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} set community{{ns.comms}} {% endif %} {# ---------------set community - End-------------------------- #} -{% if rm_val.has_key('set_community_ref') %} +{% if 'set_community_ref' in rm_val %} set community {{rm_val['set_community_ref']}} {% endif %} {# ---------------set extcommunity - Start--------------------- #} -{% if rm_val.has_key('set_ext_community_inline') %} +{% if 'set_ext_community_inline' in rm_val %} {% set ec_ns = namespace(rt_str='', soo_str='') %} {% for ext_comm in rm_val['set_ext_community_inline'] %} {% set comm = ext_comm.split(':') %} @@ -103,24 +103,24 @@ route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} {% endif %} {% endif %} {# ---------------set extcommunity - End----------------------- #} -{% if rm_val.has_key('set_ext_community_ref') %} +{% if 'set_ext_community_ref' in rm_val %} set extcommunity {{rm_val['set_ext_community_ref']}} {% endif %} -{% if rm_val.has_key('set_next_hop') %} +{% if 'set_next_hop' in rm_val %} set ip next-hop {{rm_val['set_next_hop']}} {% endif %} -{% if rm_val.has_key('set_ipv6_next_hop_global') %} +{% if 'set_ipv6_next_hop_global' in rm_val %} set ipv6 next-hop global {{rm_val['set_ipv6_next_hop_global']}} {% endif %} -{% if rm_val.has_key('set_ipv6_next_hop_prefer_global') and rm_val['set_ipv6_next_hop_prefer_global'] == 'true' %} +{% if 'set_ipv6_next_hop_prefer_global' in rm_val and rm_val['set_ipv6_next_hop_prefer_global'] == 'true' %} set ipv6 next-hop prefer-global {% endif %} -{% if rm_val.has_key('set_local_preference') %} +{% if 'set_local_preference' in rm_val %} set local-preference {{rm_val['set_local_preference']}} {% endif %} {# ---------------set metric and med - Start--------------------- #} -{% if rm_val.has_key('set_metric_action') %} -{% if rm_val.has_key('set_metric') %} +{% if 'set_metric_action' in rm_val %} +{% if 'set_metric' in rm_val %} {% if rm_val['set_metric_action'] == 'METRIC_SET_VALUE' %} set metric {{rm_val['set_metric']}} {% elif rm_val['set_metric_action'] == 'METRIC_ADD_VALUE' %} @@ -136,13 +136,13 @@ route-map {{rm_key[0]}} {{rm_val['route_operation']}} {{rm_key[1]}} {% elif rm_val['set_metric_action'] == 'METRIC_SUBTRACT_RTT' %} set metric -rtt {% endif %} -{% elif rm_val.has_key('set_med') %} +{% elif 'set_med' in rm_val %} set metric {{rm_val['set_med']}} -{% elif rm_val.has_key('set_metric') %} +{% elif 'set_metric' in rm_val %} set metric {{rm_val['set_metric']}} {% endif %} {# ---------------set metric and med - End--------------------- #} -{% if rm_val.has_key('set_origin') %} +{% if 'set_origin' in rm_val %} set origin {{rm_val['set_origin']|lower}} {% endif %} {% endif %} diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 index 13f2ce655115..cfa9cbdf6413 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 @@ -18,7 +18,7 @@ agentx {% include "bgpd.spine_chassis_frontend_router.conf.j2" %} {% endif %} ! -{% if DEVICE_METADATA['localhost'].has_key('bgp_template_config') and DEVICE_METADATA['localhost']['bgp_template_config'] == 'false' %} +{% if 'frr_mgmt_frameowrk_config' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['frr_mgmt_framework_config'] == 'true' %} {% include "bgpd.conf.db.j2" %} {% else %} {% include "bgpd.main.conf.j2" %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 index 11c1c0b5ca96..4dfaad02798a 100644 --- a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 @@ -1,37 +1,37 @@ {% set areaid = areakey[1] %} -{% if area_instance.has_key('authentication') %} +{% if 'authentication' in area_instance %} {% if area_instance['authentication'] == "MD5HMAC" %} area {{ areaid }} authentication message-digest {% else %} area {{ areaid }} authentication {% endif %} {% endif %} -{% if area_instance.has_key('stub-no-summary') %} +{% if 'stub-no-summary' in area_instance %} {% if area_instance['stub-no-summary'] == 'true' %} area {{ areaid }} stub no-summary {% endif %} {% else %} -{% if area_instance.has_key('stub') %} +{% if 'stub' in area_instance %} {% if area_instance['stub'] == 'true' %} area {{ areaid }} stub {% endif %} {% endif %} {% endif %} -{% if area_instance.has_key('stub-default-cost') %} +{% if 'stub-default-cost' in area_instance %} area {{ areaid }} default-cost {{ area_instance['stub-default-cost'] }} {% endif %} -{% if area_instance.has_key('import-list') %} +{% if 'import-list' in area_instance %} area {{ areaid }} import-list {{ area_instance['import-list'] }} {% endif %} -{% if area_instance.has_key('export-list') %} +{% if 'export-list' in area_instance %} area {{ areaid }} export-list {{ area_instance['export-list'] }} {% endif %} -{% if area_instance.has_key('filter-list-in') %} +{% if 'filter-list-in' in area_instance %} area {{ areaid }} filter-list prefix {{ area_instance['filter-list-in'] }} in {% endif %} -{% if area_instance.has_key('filter-list-out') %} +{% if 'filter-list-out' in area_instance %} area {{ areaid }} filter-list prefix {{ area_instance['filter-list-out'] }} out {% endif %} -{% if area_instance.has_key('shortcut') %} +{% if 'shortcut' in area_instance %} area {{ areaid }} shortcut {{ (area_instance['shortcut']).lower() }} {% endif %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 index 61237e9a1506..f6fcfe897fe8 100644 --- a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 @@ -4,72 +4,72 @@ {% for vrf, ospf_instance in OSPFV2_ROUTER.items() %} ! router ospf vrf {{ vrf }} -{% if ospf_instance.has_key('router-id') %} +{% if 'router-id' in ospf_instance %} ospf router-id {{ ospf_instance['router-id'] }} {% endif %} -{% if ospf_instance.has_key('abr-type') %} +{% if 'abr-type' in ospf_instance %} ospf abr-type {{ (ospf_instance['abr-type']).lower() }} {% endif %} -{% if ospf_instance.has_key('auto-cost-reference-bandwidth') %} +{% if 'auto-cost-reference-bandwidth' in ospf_instance %} auto-cost reference-bandwidth {{ (ospf_instance['auto-cost-reference-bandwidth']) }} {% endif %} -{% if ospf_instance.has_key('log-adjacency-changes') %} +{% if 'log-adjacency-changes' in ospf_instance %} {% if ospf_instance['log-adjacency-changes'] == 'DETAIL' %} log-adjacency-changes detail {% else %} log-adjacency-changes {% endif %} {% endif %} -{% if ospf_instance.has_key('default-metric') %} +{% if 'default-metric' in ospf_instance %} default-metric {{ ospf_instance['default-metric'] }} {% endif %} -{% if ospf_instance.has_key('ospf-rfc1583-compatible') %} +{% if 'ospf-rfc1583-compatible' in ospf_instance %} {% if ospf_instance['ospf-rfc1583-compatible'] == 'true' %} compatible rfc1583 {% endif %} {% endif %} -{% if ospf_instance.has_key('passive-interface-default') %} +{% if 'passive-interface-default' in ospf_instance %} passive-interface default {% endif %} -{% if ospf_instance.has_key('write-multiplier') %} +{% if 'write-multiplier' in ospf_instance %} write-multiplier {{ ospf_instance['write-multiplier'] }} {% endif %} -{% if ospf_instance.has_key('spf-throttle-delay') and ospf_instance.has_key('spf-initial-delay') and ospf_instance.has_key('spf-maximum-delay') %} +{% if 'spf-throttle-delay' in ospf_instance and 'spf-initial-delay' in ospf_instance and 'spf-maximum-delay' in ospf_instance %} timers throttle spf {{ ospf_instance['spf-throttle-delay'] }} {{ ospf_instance['spf-initial-delay'] }} {{ ospf_instance['spf-maximum-delay'] }} {% endif %} -{% if ospf_instance.has_key('lsa-min-interval-timer') %} +{% if 'lsa-min-interval-timer' in ospf_instance %} timers throttle lsa all {{ ospf_instance['lsa-min-interval-timer'] }} {% endif %} -{% if ospf_instance.has_key('lsa-min-arrival-timer') %} +{% if 'lsa-min-arrival-timer' in ospf_instance %} timers lsa min-arrival {{ ospf_instance['lsa-min-arrival-timer'] }} {% endif %} -{% if ospf_instance.has_key('lsa-refresh-timer') %} +{% if 'lsa-refresh-timer' in ospf_instance %} refresh timer {{ ospf_instance['lsa-refresh-timer'] }} {% endif %} -{% if ospf_instance.has_key('max-metric-administrative') %} +{% if 'max-metric-administrative' in ospf_instance %} {% if ospf_instance['max-metric-administrative'] == 'true' %} max-metric router-lsa administrative {% endif %} {% endif %} -{% if ospf_instance.has_key('max-metric-on-startup') %} +{% if 'max-metric-on-startup' in ospf_instance %} max-metric router-lsa on-startup {{ ospf_instance['max-metric-on-startup'] }} {% endif %} -{% if ospf_instance.has_key('max-metric-on-shutdown') %} +{% if 'max-metric-on-shutdown' in ospf_instance %} max-metric router-lsa on-shutdown {{ ospf_instance['max-metric-on-shutdown'] }} {% endif %} -{% if ospf_instance.has_key('distance-all') %} +{% if 'distance-all' in ospf_instance %} distance {{ ospf_instance['distance-all'] }} {% endif %} -{% if ospf_instance.has_key('distance-inter-area') or ospf_instance.has_key('distance-intra-area') or ospf_instance.has_key('distance-external')%} +{% if 'distance-inter-area' in ospf_instance or 'distance-intra-area' in ospf_instance or 'distance-external' in ospf_instance%} {% set distance_cmd = '' %} {% set distance_cmd = 'distance ospf' %} -{% if ospf_instance.has_key('distance-intra-area') %} +{% if 'distance-intra-area' in ospf_instance %} {% set distance_cmd = distance_cmd + ' intra-area ' + ospf_instance['distance-intra-area'] %} {% endif %} -{% if ospf_instance.has_key('distance-inter-area') %} +{% if 'distance-inter-area' in ospf_instance %} {% set distance_cmd = distance_cmd + ' inter-area ' + ospf_instance['distance-inter-area'] %} {% endif %} -{% if ospf_instance.has_key('distance-external') %} +{% if 'distance-external' in ospf_instance %} {% set distance_cmd = distance_cmd + ' external ' + ospf_instance['distance-external'] %} {% endif %} {{ distance_cmd }} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 index 49c58f35859a..d13ac7ada5b6 100644 --- a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 @@ -4,20 +4,20 @@ {% if routeproto == "DEFAULT_ROUTE" and routedirection == "IMPORT" %} {% set defaultinfo_cmd = '' %} {% set defaultinfo_cmd = 'default-information originate' %} -{% if route_instance.has_key('always') %} +{% if 'always' in route_instance %} {% if route_instance['always'] == 'true' %} {% set defaultinfo_cmd = defaultinfo_cmd + ' always' %} {% endif %} {% endif %} -{% if route_instance.has_key('metric') %} +{% if 'metric' in route_instance %} {% set defaultinfo_cmd = defaultinfo_cmd + ' metric ' + route_instance['metric'] %} {% endif %} -{% if route_instance.has_key('metric-type') %} +{% if 'metric-type' in route_instance %} {% if route_instance['metric-type'] == "TYPE_1"%} {% set defaultinfo_cmd = defaultinfo_cmd + ' metric-type ' + '1' %} {% endif %} {% endif %} -{% if route_instance.has_key('route-map') %} +{% if 'route-map' in route_instance %} {% set defaultinfo_cmd = defaultinfo_cmd + ' route-map ' + route_instance['route-map'] %} {% endif %} {{ defaultinfo_cmd }} @@ -28,20 +28,20 @@ {% else %} {% set redistribute_cmd = 'redistribute ' + routeproto.lower() %} {% endif %} -{% if route_instance.has_key('metric') %} +{% if 'metric' in route_instance %} {% set redistribute_cmd = redistribute_cmd + ' metric ' + route_instance['metric'] %} {% endif %} -{% if route_instance.has_key('metric-type') %} +{% if 'metric-type' in route_instance %} {% if route_instance['metric-type'] == "TYPE_1"%} {% set redistribute_cmd = redistribute_cmd + ' metric-type ' + '1' %} {% endif %} {% endif %} -{% if route_instance.has_key('route-map') %} +{% if 'route-map' in route_instance %} {% set redistribute_cmd = redistribute_cmd + ' route-map ' + route_instance['route-map'] %} {% endif %} {{ redistribute_cmd }} {% elif routedirection == "EXPORT" and routeproto in generic_protocols %} -{% if route_instance.has_key('route-map') %} +{% if 'route-map' in route_instance %} {% if routeproto == "DIRECTLY_CONNECTED" %} distribute-list {{ route_instance['route-map'] }} out connected {% else %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 index b8c86b2bb834..f5ea6c5c4785 100644 --- a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 @@ -9,10 +9,10 @@ {% set intfaddr = "" %} {% endif %} interface {{ intfname }} -{% if ospf_intf_instance.has_key('area-id') %} +{% if 'area-id' in ospf_intf_instance %} ip ospf area {{ ospf_intf_instance['area-id'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('network-type') %} +{% if 'network-type' in ospf_intf_instance %} {% if ospf_intf_instance['network-type'] == 'BROADCAST_NETWORK' %} ip ospf network broadcast {{ intfaddr }} {% endif %} @@ -20,23 +20,23 @@ interface {{ intfname }} ip ospf network point-to-point {{ intfaddr }} {% endif %} {% endif %} -{% if ospf_intf_instance.has_key('metric') %} +{% if 'metric' in ospf_intf_instance %} ip ospf cost {{ ospf_intf_instance['metric'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('priority') %} +{% if 'priority' in ospf_intf_instance %} ip ospf priority {{ ospf_intf_instance['priority'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('mtu-ignore') %} +{% if 'mtu-ignore' in ospf_intf_instance %} {% if ospf_intf_instance['mtu-ignore'] == 'true' %} ip ospf mtu-ignore {{ intfaddr }} {% endif %} {% endif %} -{% if ospf_intf_instance.has_key('bfd-enable') %} +{% if 'bfd-enable' in ospf_intf_instance %} {% if ospf_intf_instance['bfd-enable'] == 'true' %} ip ospf bfd {% endif %} {% endif %} -{% if ospf_intf_instance.has_key('authentication-type') %} +{% if 'authentication-type' in ospf_intf_instance %} {% if ospf_intf_instance['authentication-type'] == 'MD5HMAC' %} ip ospf authentication message-digest {{ intfaddr }} {% endif %} @@ -47,29 +47,29 @@ interface {{ intfname }} ip ospf authentication {{ intfaddr }} {% endif %} {% endif %} -{% if ospf_intf_instance.has_key('authentication-key') %} +{% if 'authentication-key' in ospf_intf_instance %} ip ospf authentication-key {{ ospf_intf_instance['authentication-key'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('authentication-key-id') and ospf_intf_instance.has_key('authentication-md5-key') %} +{% if 'authentication-key-id' in ospf_intf_instance and 'authentication-md5-key' in ospf_intf_instance %} ip ospf message-digest-key {{ ospf_intf_instance['authentication-key-id'] }} md5 {{ ospf_intf_instance['authentication-md5-key'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('dead-interval') %} +{% if 'dead-interval' in ospf_intf_instance %} ip ospf dead-interval {{ ospf_intf_instance['dead-interval'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('dead-interval-minimal') %} -{% if ospf_intf_instance.has_key('hello-multiplier') %} +{% if 'dead-interval-minimal' in ospf_intf_instance %} +{% if 'hello-multiplier' in ospf_intf_instance %} ip ospf dead-interval minimal hello-multiplier {{ ospf_intf_instance['hello-multiplier'] }} {{ intfaddr }} {% else %} ip ospf dead-interval minimal {{ intfaddr }} {% endif %} {% endif %} -{% if ospf_intf_instance.has_key('hello-interval') %} +{% if 'hello-interval' in ospf_intf_instance %} ip ospf hello-interval {{ ospf_intf_instance['hello-interval'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('retransmission-interval') %} +{% if 'retransmission-interval' in ospf_intf_instance %} ip ospf retransmit-interval {{ ospf_intf_instance['retransmission-interval'] }} {{ intfaddr }} {% endif %} -{% if ospf_intf_instance.has_key('transmit-delay') %} +{% if 'transmit-delay' in ospf_intf_instance %} ip ospf transmit-delay {{ ospf_intf_instance['transmit-delay'] }} {{ intfaddr }} {% endif %} {% endfor %} diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 index 6f1ef89cc3bf..8d82b41c0827 100644 --- a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 @@ -1,16 +1,16 @@ {% set rangeareaid = rangekey[1] %} {% set rangeid = rangekey[2] %} area {{ rangeareaid }} range {{ rangeid }} -{% if area_range_instance.has_key('advertise') %} +{% if 'advertise' in area_range_instance %} {% if area_range_instance['advertise'] == 'true' %} area {{ rangeareaid }} range {{ rangeid }} advertise {% else %} area {{ rangeareaid }} range {{ rangeid }} not-advertise {% endif %} {% endif %} -{% if area_range_instance.has_key('metric') %} +{% if 'metric' in area_range_instance %} area {{ rangeareaid }} range {{ rangeid }} advertise cost {{ area_range_instance['metric'] }} {% endif %} -{% if area_range_instance.has_key('substitue-prefix') %} +{% if 'substitue-prefix' in area_range_instance %} area {{ rangeareaid }} range {{ rangeid }} substitute {{ area_range_instance['substitue-prefix'] }} {% endif %} \ No newline at end of file diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 index e8af99abe299..653db9f5458b 100644 --- a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 +++ b/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 @@ -1,29 +1,29 @@ {% set vlinkareaid = vlinkkey[1] %} {% set vlinkid = vlinkkey[2] %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} -{% if vlink_instance.has_key('authentication') %} +{% if 'authentication' in vlink_instance %} {% if vlink_instance['authentication'] == 'MD5HMAC' %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} authentication message-digest {% else %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} null {% endif %} {% endif %} -{% if vlink_instance.has_key('authentication-key') %} +{% if 'authentication-key' in vlink_instance %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} authentication-key {{ vlink_instance['authentication-key'] }} {% endif %} -{% if vlink_instance.has_key('authentication-key-id') and vlink_instance.has_key('authentication-md5-key') %} +{% if 'authentication-key-id' in vlink_instance and 'authentication-md5-key' in vlink_instance %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} authentication message-digest message-digest-key {{ vlink_instance['authentication-key-id'] }} md5 {{ vlink_instance['authentication-md5-key'] }} {% endif %} -{% if vlink_instance.has_key('dead-interval') %} +{% if 'dead-interval' in vlink_instance %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} dead-interval {{ vlink_instance['dead-interval'] }} {% endif %} -{% if vlink_instance.has_key('hello-interval') %} +{% if 'hello-interval' in vlink_instance %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} hello-interval {{ vlink_instance['hello-interval'] }} {% endif %} -{% if vlink_instance.has_key('retransmission-interval') %} +{% if 'retransmission-interval' in vlink_instance %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} retransmit-interval {{ vlink_instance['retransmission-interval'] }} {% endif %} -{% if vlink_instance.has_key('transmit-delay') %} +{% if 'transmit-delay' in vlink_instance %} area {{ vlinkareaid }} virtual-link {{ vlinkid }} transmit-delay {{ vlink_instance['transmit-delay'] }} {% endif %} diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 index 9509ba61d21c..5a58dae24b1c 100644 --- a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 @@ -8,7 +8,18 @@ ! {% include "common/daemons.common.conf.j2" %} ! +{% if 'frr_mgmt_frameowrk_config' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['frr_mgmt_framework_config'] == 'true' %} +{% if MGMT_VRF_CONFIG %} +{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} {% include "staticd.default_route.conf.j2" %} +{% endif %} +{% else %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} ! {% include "staticd.db.conf.j2" %} ! +{% else %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +! diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 index 58ee06bc8592..8ac8e42a4733 100644 --- a/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 @@ -54,7 +54,7 @@ {#- ------------------------------ parse nh - start ------------------------------ #} {%- set nh = namespace(blackhole = False, ip = None, intf = None, dist = None, tag = None, vrf = None) %} {#- ------------------------------ nexthop blackhole ------------------------------ #} - {%- if nh_attr.has_key('blackhole') %} + {%- if 'blackhole' in nh_attr %} {%- set nh.blackhole = nh_attr['blackhole'][nh_idx] %} {%- if nh.blackhole == 'true' %} {%- set nh.blackhole = True %} @@ -63,28 +63,28 @@ {%- endif %} {%- endif %} {#- ------------------------------ nexthop IP ------------------------------ #} - {%- if nh_attr.has_key('nexthop') %} + {%- if 'nexthop' in nh_attr %} {%- set nh.ip = nh_attr['nexthop'][nh_idx] %} {%- if nh.ip == '0.0.0.0' or nh.ip == '::' %} {%- set nh.ip = None %} {%- endif %} {%- endif %} {#- ------------------------------ nexthop interface ------------------------------ #} - {%- if nh_attr.has_key('ifname') %} + {%- if 'ifname' in nh_attr %} {%- set nh.intf = nh_attr['ifname'][nh_idx] %} {%- if nh.intf == '' %} {%- set nh.intf = None %} {%- endif %} {%- endif %} {#- ------------------------------ nexthop distance ------------------------------ #} - {%- if nh_attr.has_key('distance') %} + {%- if 'distance' in nh_attr %} {%- set nh.dist = nh_attr['distance'][nh_idx] %} {%- if nh.dist == '0' %} {%- set nh.dist = None %} {%- endif %} {%- endif %} {#- ------------------------------ nexthop tag ------------------------------ #} - {%- if nh_attr.has_key('tag') %} + {%- if 'tag' in nh_attr %} {%- set nh.tag = nh_attr['tag'][nh_idx] %} {%- if nh.tag == '0' %} {%- set nh.tag = None %} @@ -94,7 +94,7 @@ {%- endif %} {%- endif %} {#- ------------------------------ nexthop VRF ------------------------------ #} - {%- if nh_attr.has_key('nexthop-vrf') %} + {%- if 'nexthop-vrf' in nh_attr %} {%- set nh.vrf = nh_attr['nexthop-vrf'][nh_idx] %} {%- if nh.vrf == '' %} {%- set nh.vrf = None %} @@ -110,7 +110,7 @@ {%- endif %} {%- endfor %} {#- ------------------------------ for each route - end ------------------------------ #} - {%- if not vrf_rt_list.has_key(rt.vrf) %} + {%- if not rt.vrf in vrf_rt_list %} {%- if vrf_rt_list.update({rt.vrf: []}) %} {%- endif %} {%- endif %} diff --git a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 index 7aed6a5773a6..cad1c0d77e76 100644 --- a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 +++ b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 @@ -109,10 +109,11 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=bgpd:running -[program:bgpcfgd] -{% if DEVICE_METADATA.localhost.bgp_template_config is defined and DEVICE_METADATA.localhost.bgp_template_config == "false" %} -command=/usr/local/bin/bgpcfgd_no_template +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +[program:frrcfgd] +command=/usr/local/bin/frrcfgd {% else %} +[program:bgpcfgd] command=/usr/local/bin/bgpcfgd {% endif %} priority=6 diff --git a/rules/docker-fpm-frr.mk b/rules/docker-fpm-frr.mk index 833d510245ea..4b489bff3d0b 100644 --- a/rules/docker-fpm-frr.mk +++ b/rules/docker-fpm-frr.mk @@ -5,7 +5,7 @@ DOCKER_FPM_FRR = $(DOCKER_FPM_FRR_STEM).gz DOCKER_FPM_FRR_DBG = $(DOCKER_FPM_FRR_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_FPM_FRR)_PATH = $(DOCKERS_PATH)/$(DOCKER_FPM_FRR_STEM) -$(DOCKER_FPM_FRR)_PYTHON_WHEELS += $(SONIC_BGPCFGD) +$(DOCKER_FPM_FRR)_PYTHON_WHEELS += $(SONIC_BGPCFGD) $(SONIC_FRR_MGMT_FRAMEWORK) $(DOCKER_FPM_FRR)_DEPENDS += $(FRR) $(FRR_SNMP) $(SWSS) $(LIBYANG) $(DOCKER_FPM_FRR)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_DEPENDS) diff --git a/rules/sonic-frr-mgmt-framework.dep b/rules/sonic-frr-mgmt-framework.dep new file mode 100644 index 000000000000..318c4edd1da8 --- /dev/null +++ b/rules/sonic-frr-mgmt-framework.dep @@ -0,0 +1,8 @@ +SPATH := $($(SONIC_FRR_MGMT_FRAMEWORK)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-frr-mgmt-framework.mk rules/sonic-frr-mgmt-framework.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(SPATH)) + +$(SONIC_FRR_MGMT_FRAMEWORK)_CACHE_MODE := GIT_CONTENT_SHA +$(SONIC_FRR_MGMT_FRAMEWORK)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(SONIC_FRR_MGMT_FRAMEWORK)_DEP_FILES := $(DEP_FILES) diff --git a/rules/sonic-frr-mgmt-framework.mk b/rules/sonic-frr-mgmt-framework.mk new file mode 100644 index 000000000000..6970071a7a52 --- /dev/null +++ b/rules/sonic-frr-mgmt-framework.mk @@ -0,0 +1,13 @@ +# sonic-frr-mgmt-framework package + +SONIC_FRR_MGMT_FRAMEWORK = sonic_frr_mgmt_framework-1.0-py2-none-any.whl +$(SONIC_FRR_MGMT_FRAMEWORK)_SRC_PATH = $(SRC_PATH)/sonic-frr-mgmt-framework +# These dependencies are only needed because they are dependencies +# of sonic-config-engine and frrcfgd explicitly calls sonic-cfggen +# as part of its unit tests. +# TODO: Refactor unit tests so that these dependencies are not needed + +$(SONIC_FRR_MGMT_FRAMEWORK)_DEPENDS += $(SONIC_CONFIG_ENGINE_PY2) +$(SONIC_FRR_MGMT_FRAMEWORK)_DEBS_DEPENDS += $(PYTHON_SWSSCOMMON) +$(SONIC_FRR_MGMT_FRAMEWORK)_PYTHON_VERSION = 2 +SONIC_PYTHON_WHEELS += $(SONIC_FRR_MGMT_FRAMEWORK) diff --git a/src/sonic-config-engine/tests/sample_output/py2/staticd_frr.conf b/src/sonic-config-engine/tests/sample_output/py2/staticd_frr.conf index 75cbbd6df164..31a11d8578aa 100644 --- a/src/sonic-config-engine/tests/sample_output/py2/staticd_frr.conf +++ b/src/sonic-config-engine/tests/sample_output/py2/staticd_frr.conf @@ -18,4 +18,3 @@ log facility local4 ! set static default route to mgmt gateway as a backup to learned default ip route 0.0.0.0/0 10.0.0.1 200 !! -! diff --git a/src/sonic-frr-mgmt-framework/.gitignore b/src/sonic-frr-mgmt-framework/.gitignore new file mode 100644 index 000000000000..f6411e4ee01e --- /dev/null +++ b/src/sonic-frr-mgmt-framework/.gitignore @@ -0,0 +1,12 @@ +.eggs/ +build/ +dist/ +*.egg-info/ +frrcfgd/*.pyc +tests/*.pyc +tests/__pycache__/ +.idea +.coverage +frrcfgd/__pycache__/ +venv +tests/.coverage* diff --git a/src/sonic-frr-mgmt-framework/frrcfgd/__init__.py b/src/sonic-frr-mgmt-framework/frrcfgd/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/sonic-bgpcfgd/bgpcfgd_no_template b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd similarity index 100% rename from src/sonic-bgpcfgd/bgpcfgd_no_template rename to src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd diff --git a/src/sonic-frr-mgmt-framework/pytest.ini b/src/sonic-frr-mgmt-framework/pytest.ini new file mode 100644 index 000000000000..a49b58e45f0f --- /dev/null +++ b/src/sonic-frr-mgmt-framework/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --cov=bgpcfgd --cov-report term diff --git a/src/sonic-frr-mgmt-framework/setup.cfg b/src/sonic-frr-mgmt-framework/setup.cfg new file mode 100644 index 000000000000..00ed5efbcbad --- /dev/null +++ b/src/sonic-frr-mgmt-framework/setup.cfg @@ -0,0 +1,5 @@ +[aliases] +test=pytest +[tool:pytest] +addopts = --verbose +python_files = tests/*.py diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py new file mode 100755 index 000000000000..fb1ead11986b --- /dev/null +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -0,0 +1,29 @@ +import setuptools + +setuptools.setup( + name = 'sonic-frr-mgmt-framework', + version = '1.0', + description = 'Utility to dynamically configuration FRR based on database update', + url = 'https://github.com/Azure/sonic-buildimage', + packages = setuptools.find_packages(), + entry_points = { + 'console_scripts': [ + 'frrcfgd = frrcfgd.frrcfgd:main', + ] + }, + install_requires = [ + 'jinja2>=2.10', + 'netaddr==0.8.0', + 'pyyaml==5.3.1', + 'zipp==1.2.0', # importlib-resources needs zipp and seems to have a bug where it will try to import too new of a version for Python 2 + ], + setup_requires = [ + 'pytest-runner', + 'wheel' + ], + tests_require = [ + 'pytest', + 'pytest-cov', + 'sonic-config-engine' + ] +) diff --git a/src/sonic-frr-mgmt-framework/tests/__init__.py b/src/sonic-frr-mgmt-framework/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/sonic-frr-mgmt-framework/tests/test_config.py b/src/sonic-frr-mgmt-framework/tests/test_config.py new file mode 100644 index 000000000000..d2987ad1f000 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/tests/test_config.py @@ -0,0 +1,2 @@ +def test_contructor(): + assert(True) From a41d8dd2a85006b6fd23dc790ddb957a0465746a Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Tue, 29 Dec 2020 06:54:49 +0000 Subject: [PATCH 07/24] Put template files into frrcfgd package --- dockers/docker-fpm-frr/docker_init.sh | 41 +++-- dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 | 4 - .../frr/staticd/staticd.conf.j2 | 13 -- .../frr/supervisord/supervisord.conf.j2 | 41 ----- rules/sonic-frr-mgmt-framework.mk | 6 +- .../frrcfgd/{frrcfgd => frrcfgd.py} | 88 ++++++----- src/sonic-frr-mgmt-framework/pytest.ini | 2 +- src/sonic-frr-mgmt-framework/setup.py | 25 +++ .../templates}/bfdd/bfdd.conf.j2 | 0 .../templates/bgpd/.bgpd.conf.j2.swp | Bin 0 -> 12288 bytes .../bgpd/bgpd.conf.db.addr_family.evpn.j2 | 0 .../bgpd/bgpd.conf.db.addr_family.j2 | 0 .../templates}/bgpd/bgpd.conf.db.comm_list.j2 | 0 .../templates}/bgpd/bgpd.conf.db.j2 | 0 .../templates}/bgpd/bgpd.conf.db.nbr_af.j2 | 0 .../bgpd/bgpd.conf.db.nbr_or_peer.j2 | 0 .../templates}/bgpd/bgpd.conf.db.pref_list.j2 | 0 .../templates}/bgpd/bgpd.conf.db.route_map.j2 | 0 .../templates/bgpd/bgpd.conf.j2 | 22 +++ .../templates/bgpd/bgpd.main.conf.j2 | 116 ++++++++++++++ ...bgpd.spine_chassis_frontend_router.conf.j2 | 63 ++++++++ .../templates/common/daemons.common.conf.j2 | 14 ++ .../templates}/ospfd/ospfd.conf.db.area.j2 | 0 .../ospfd/ospfd.conf.db.comm_list.j2 | 0 .../ospfd/ospfd.conf.db.distributeroute.j2 | 0 .../ospfd/ospfd.conf.db.interface.j2 | 0 .../ospfd/ospfd.conf.db.policyrange.j2 | 0 .../templates}/ospfd/ospfd.conf.db.vlink.j2 | 0 .../templates}/ospfd/ospfd.conf.j2 | 0 .../templates/staticd/.staticd.conf.j2.swp | Bin 0 -> 12288 bytes .../templates/staticd/staticd.conf.j2 | 20 +++ .../templates}/staticd/staticd.db.conf.j2 | 0 .../staticd/staticd.default_route.conf.j2 | 10 ++ .../supervisord/.supervisord.conf.j2.swp | Bin 0 -> 16384 bytes .../templates/supervisord/supervisord.conf.j2 | 148 ++++++++++++++++++ 35 files changed, 493 insertions(+), 120 deletions(-) rename src/sonic-frr-mgmt-framework/frrcfgd/{frrcfgd => frrcfgd.py} (98%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bfdd/bfdd.conf.j2 (100%) create mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/.bgpd.conf.j2.swp rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.addr_family.evpn.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.addr_family.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.comm_list.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.nbr_af.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.nbr_or_peer.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.pref_list.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/bgpd/bgpd.conf.db.route_map.j2 (100%) create mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.db.area.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.db.comm_list.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.db.distributeroute.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.db.interface.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.db.policyrange.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.db.vlink.j2 (100%) rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/ospfd/ospfd.conf.j2 (100%) create mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/.staticd.conf.j2.swp create mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 rename {dockers/docker-fpm-frr/frr => src/sonic-frr-mgmt-framework/templates}/staticd/staticd.db.conf.j2 (100%) create mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/supervisord/.supervisord.conf.j2.swp create mode 100644 src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 170ef7fb96ff..bc59b075ce24 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -4,22 +4,33 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d MGMT_FRAMEWORK_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]'` -CFGGEN_PARAMS=" \ - -d \ - -y /etc/sonic/constants.yml \ - -t /usr/share/sonic/templates/supervisord/frr_vars.j2 \ - -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ - -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ - -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ - -t /usr/share/sonic/templates/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ - -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ - -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ - -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ -" if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then - CFGGEN_PARAMS+=" \ - -t /usr/share/sonic/templates/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ - -t /usr/share/sonic/templates/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ + CFGGEN_PARAMS=" \ + -d \ + -y /etc/sonic/constants.yml \ + -t /usr/share/sonic/templates/frr_vars.j2 \ + -t /usr/local/frr/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ + -t /usr/local/frr/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ + -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ + -t /usr/local/frr/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ + -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ + -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ + -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ + -t /usr/local/frr/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ + -t /usr/local/frr/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ + " +else + CFGGEN_PARAMS=" \ + -d \ + -y /etc/sonic/constants.yml \ + -t /usr/share/sonic/templates/supervisord/frr_vars.j2 \ + -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ + -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ + -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ + -t /usr/share/sonic/templates/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ + -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ + -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ + -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ " fi CONFIG_TYPE=$(sonic-cfggen $CFGGEN_PARAMS) diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 index cfa9cbdf6413..85182e5430e8 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 @@ -18,11 +18,7 @@ agentx {% include "bgpd.spine_chassis_frontend_router.conf.j2" %} {% endif %} ! -{% if 'frr_mgmt_frameowrk_config' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['frr_mgmt_framework_config'] == 'true' %} -{% include "bgpd.conf.db.j2" %} -{% else %} {% include "bgpd.main.conf.j2" %} -{% endif %} ! ! end of template: bgpd/bgpd.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 index 5a58dae24b1c..932871dfce4b 100644 --- a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 @@ -8,18 +8,5 @@ ! {% include "common/daemons.common.conf.j2" %} ! -{% if 'frr_mgmt_frameowrk_config' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['frr_mgmt_framework_config'] == 'true' %} -{% if MGMT_VRF_CONFIG %} -{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} {% include "staticd.default_route.conf.j2" %} -{% endif %} -{% else %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -! -{% include "staticd.db.conf.j2" %} -! -{% else %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} ! diff --git a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 index cad1c0d77e76..205b57e5f616 100644 --- a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 +++ b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 @@ -50,18 +50,6 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=zebra:running -[program:bfdd] -command=/usr/lib/frr/bfdd -A 127.0.0.1 -priority=4 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - [program:bgpd] command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp priority=5 @@ -74,30 +62,6 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=zebra:running -[program:ospfd] -command=/usr/lib/frr/ospfd -A 127.0.0.1 -M snmp -priority=5 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - -[program:pimd] -command=/usr/lib/frr/pimd -A 127.0.0.1 -priority=5 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - [program:fpmsyncd] command=fpmsyncd priority=6 @@ -109,13 +73,8 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=bgpd:running -{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} -[program:frrcfgd] -command=/usr/local/bin/frrcfgd -{% else %} [program:bgpcfgd] command=/usr/local/bin/bgpcfgd -{% endif %} priority=6 autostart=false autorestart=false diff --git a/rules/sonic-frr-mgmt-framework.mk b/rules/sonic-frr-mgmt-framework.mk index 6970071a7a52..dfe981b440a9 100644 --- a/rules/sonic-frr-mgmt-framework.mk +++ b/rules/sonic-frr-mgmt-framework.mk @@ -1,13 +1,13 @@ # sonic-frr-mgmt-framework package -SONIC_FRR_MGMT_FRAMEWORK = sonic_frr_mgmt_framework-1.0-py2-none-any.whl +SONIC_FRR_MGMT_FRAMEWORK = sonic_frr_mgmt_framework-1.0-py3-none-any.whl $(SONIC_FRR_MGMT_FRAMEWORK)_SRC_PATH = $(SRC_PATH)/sonic-frr-mgmt-framework # These dependencies are only needed because they are dependencies # of sonic-config-engine and frrcfgd explicitly calls sonic-cfggen # as part of its unit tests. # TODO: Refactor unit tests so that these dependencies are not needed -$(SONIC_FRR_MGMT_FRAMEWORK)_DEPENDS += $(SONIC_CONFIG_ENGINE_PY2) +$(SONIC_FRR_MGMT_FRAMEWORK)_DEPENDS += $(SONIC_CONFIG_ENGINE_PY3) $(SONIC_FRR_MGMT_FRAMEWORK)_DEBS_DEPENDS += $(PYTHON_SWSSCOMMON) -$(SONIC_FRR_MGMT_FRAMEWORK)_PYTHON_VERSION = 2 +$(SONIC_FRR_MGMT_FRAMEWORK)_PYTHON_VERSION = 3 SONIC_PYTHON_WHEELS += $(SONIC_FRR_MGMT_FRAMEWORK) diff --git a/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py similarity index 98% rename from src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd rename to src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py index 23a009bc32dd..f083a672b5fe 100755 --- a/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd +++ b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py @@ -8,12 +8,12 @@ from swsssdk import ConfigDBConnector import socket import threading -import Queue +import queue import signal import re import logging import netaddr -import cStringIO +import io import struct class CachedDataWithOp: @@ -148,11 +148,11 @@ def __create_proxy_socket(): def __get_reply(sock): reply_msg = None ret_code = None - msg_buf = cStringIO.StringIO() + msg_buf = io.StringIO() while True: try: rd_msg = sock.recv(16384) - msg_buf.write(rd_msg) + msg_buf.write(rd_msg.decode()) except socket.timeout: syslog.syslog(syslog.LOG_ERR, 'socket reading timeout') break @@ -161,8 +161,10 @@ def __get_reply(sock): if len(rd_msg) < 4: continue msg_tail = rd_msg[-4:] - if msg_tail[0] == '\0' and msg_tail[1] == '\0' and msg_tail[2] == '\0': - ret_code = ord(msg_tail[3]) + if isinstance(msg_tail, str): + msg_tail = bytes(msg_tail, 'utf-8') + if msg_tail[0] == 0 and msg_tail[1] == 0 and msg_tail[2] == 0: + ret_code = msg_tail[3] reply_msg = msg_buf.getvalue()[:-4] break msg_buf.close() @@ -177,7 +179,7 @@ def __create_frr_client(self): try: sock.connect(serv_addr) break - except socket.error, msg: + except socket.error as msg: syslog.syslog(syslog.LOG_ERR, 'failed to connect to frr daemon %s: %s' % (daemon, msg)) retry_cnt += 1 if retry_cnt > 100 or not main_loop: @@ -192,13 +194,13 @@ def __create_frr_client(self): for daemon, sock in self.client_socks.items(): syslog.syslog(syslog.LOG_DEBUG, 'send initial enable command to %s' % daemon) try: - sock.sendall('enable\0') - except socket.error, msg: + sock.sendall(bytes('enable\0', 'utf-8')) + except socket.error as msg: syslog.syslog(syslog.LOG_ERR, 'failed to send initial enable command to %s' % daemon) return False ret_code, reply = self.__get_reply(sock) if ret_code is None: - syslog.syslog(syslog.LOG_ERR, 'failed to command response for enable command') + syslog.syslog(syslog.LOG_ERR, 'failed to get command response for enable command from %s' % daemon) return False if ret_code != 0: syslog.syslog(syslog.LOG_ERR, 'enable command failed: ret_code=%d' % ret_code) @@ -249,7 +251,7 @@ def __proc_command(self, command, daemons): continue try: sock.sendall(command + '\0') - except socket.error, msg: + except socket.error as msg: syslog.syslog(syslog.LOG_ERR, 'failed to send command to frr daemon: %s' % msg) return (False, None) ret_code, reply = self.__get_reply(sock) @@ -288,7 +290,7 @@ def run_vtysh_command(self, table, command, daemons): return ret_val @staticmethod def __read_all(sock, data_len): - in_buf = cStringIO.StringIO() + in_buf = io.StringIO() left_len = data_len while left_len > 0: data = sock.recv(left_len) @@ -342,7 +344,7 @@ def run(self): syslog.syslog(syslog.LOG_ERR, 'read data of length %d is not expected length %d' % (data_len, len(in_cmd))) else: syslog.syslog(syslog.LOG_ERR, 'invalid data length %d' % len(data)) - except socket.error, msg: + except socket.error as msg: syslog.syslog(syslog.LOG_ERR, 'socket writing failed: %s' % msg) finally: syslog.syslog(syslog.LOG_DEBUG, 'closing data socket from client') @@ -1435,10 +1437,10 @@ class ExtConfigDBConnector(ConfigDBConnector): def __init__(self, ns_attrs = None): super(ExtConfigDBConnector, self).__init__() self.nosort_attrs = ns_attrs if ns_attrs is not None else {} - def __raw_to_typed(self, table, raw_data): + def raw_to_typed(self, table, raw_data): if len(raw_data) == 0: raw_data = None - data = super(ExtConfigDBConnector, self)._ConfigDBConnector__raw_to_typed(raw_data) + data = super(ExtConfigDBConnector, self).raw_to_typed(raw_data) if data is None: return None for key, val in data.items(): @@ -1450,9 +1452,9 @@ def sub_msg_handler(self, msg_item): key = msg_item['channel'].split(':', 1)[1] try: (table, row) = key.split(self.TABLE_NAME_SEPARATOR, 1) - if self.handlers.has_key(table): + if table in self.handlers: client = self.get_redis_client(self.db_name) - data = self.__raw_to_typed(table, client.hgetall(key)) + data = self.raw_to_typed(table, client.hgetall(key)) super(ExtConfigDBConnector, self)._ConfigDBConnector__fire(table, row, data) except ValueError: pass #Ignore non table-formated redis entries @@ -2217,7 +2219,7 @@ def __init__(self): ('IGMP_INTERFACE', self.bgp_table_handler_common), ('IGMP_INTERFACE_QUERY', self.bgp_table_handler_common) ] - self.bgp_message = Queue.Queue(0) + self.bgp_message = queue.Queue(0) self.table_data_cache = self.config_db.get_table_data([tbl for tbl, _ in self.table_handler_list]) syslog.syslog(syslog.LOG_DEBUG, 'Init Cached DB data') for key, entry in self.table_data_cache.items(): @@ -2261,7 +2263,7 @@ def bfd_handler(self, table, key, data): cmd = 'peer {}'.format(key_params[0]) if len(key_params) == 4 and key_params[3] == 'multihop': cmd = cmd + ' multihop ' - if key_params[1] != 'null': + if key_params[1] != 'null': cmd = cmd + ' local-address ' + key_params[1] if key_params[2] != 'null': cmd = cmd + ' interface ' + key_params[2] @@ -3017,29 +3019,29 @@ def __update_bgp(self, data_list): self.af_aggr_list[vrf].pop(norm_ip_prefix, None) elif table == 'BFD_PEER_SINGLE_HOP': - key = prefix + '|' + key + key = prefix + '|' + key remoteaddr, interface, vrf, localaddr = key.split('|') - if not del_table: - if not 'null' in localaddr: + if not del_table: + if not 'null' in localaddr: syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {} {}'.format(remoteaddr, vrf, interface, localaddr)) suffix_cmd, oper = self.__bfd_handle_delete (data) if suffix_cmd and oper == CachedDataWithOp.OP_DELETE: command = "vtysh -c 'configure terminal' -c 'bfd' -c 'peer {} local-address {} vrf {} interface {}' -c '{}'".\ format(remoteaddr, localaddr, vrf, interface, suffix_cmd) - + if not self.__run_command(table, command): - syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) - continue + syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) + continue else: cmd_prefix = ['configure terminal', 'bfd', 'peer {} local-address {} vrf {} interface {}'.format(remoteaddr, localaddr, vrf, interface)] if not key_map.run_command(self, table, data, cmd_prefix): - syslog.syslog(syslog.LOG_ERR, 'failed running BFD single-hop config command') - continue + syslog.syslog(syslog.LOG_ERR, 'failed running BFD single-hop config command') + continue - else: + else: syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {}'.format(remoteaddr, vrf, interface)) suffix_cmd, oper = self.__bfd_handle_delete (data) @@ -3051,22 +3053,22 @@ def __update_bgp(self, data_list): if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) continue - else: - syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {}'.format(remoteaddr, vrf, interface)) + else: + syslog.syslog(syslog.LOG_INFO, 'Set BFD single hop peer {} {} {}'.format(remoteaddr, vrf, interface)) cmd_prefix = ['configure terminal', 'bfd', 'peer {} vrf {} interface {}'.format(remoteaddr, vrf, interface)] if not key_map.run_command(self, table, data, cmd_prefix): syslog.syslog(syslog.LOG_ERR, 'failed running BFD single-hop config command') continue - else: - if 'local-address' in data: + else: + if 'local-address' in data: dval = data['local-address'] localaddr = dval.data - syslog.syslog(syslog.LOG_INFO, 'Delete BFD single hop to {} {} {}'.format(remoteaddr, vrf, interface, localaddr)) + syslog.syslog(syslog.LOG_INFO, 'Delete BFD single hop to {} {} {}'.format(remoteaddr, vrf, interface, localaddr)) command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} local-address {} vrf {} interface {}'".\ format(remoteaddr, localaddr, vrf, interface) - else: + else: syslog.syslog(syslog.LOG_INFO, 'Delete BFD single hop to {} {} {}'.format(remoteaddr, vrf, interface)) command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} vrf {} interface {}'".\ format(remoteaddr, vrf, interface) @@ -3075,13 +3077,13 @@ def __update_bgp(self, data_list): continue self.__delete_bfd_peer(data) elif table == 'BFD_PEER_MULTI_HOP': - key = prefix + '|' + key + key = prefix + '|' + key remoteaddr, interface, vrf, localaddr = key.split('|') if not del_table: - syslog.syslog(syslog.LOG_INFO, 'Set BFD multi hop to {} {} {} {}'.format(remoteaddr, interface, vrf, localaddr)) + syslog.syslog(syslog.LOG_INFO, 'Set BFD multi hop to {} {} {} {}'.format(remoteaddr, interface, vrf, localaddr)) suffix_cmd, oper = self.__bfd_handle_delete (data) if suffix_cmd and oper == CachedDataWithOp.OP_DELETE: - if not 'null' in interface: + if not 'null' in interface: command = "vtysh -c 'configure terminal' -c 'bfd' -c 'peer {} local-address {} vrf {} interface {}' -c '{}'".\ format(remoteaddr, localaddr, vrf, interface, suffix_cmd) else: @@ -3091,11 +3093,11 @@ def __update_bgp(self, data_list): if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to delete single-hop peer {}'.format(key)) continue - else: + else: if not 'null' in interface: cmd_prefix = ['configure terminal', 'bfd', - 'peer {} vrf {} multihop local-address {} interface {}'.format(remoteaddr, vrf, localaddr, interface)] + 'peer {} vrf {} multihop local-address {} interface {}'.format(remoteaddr, vrf, localaddr, interface)] else: cmd_prefix = ['configure terminal', 'bfd', @@ -3104,7 +3106,7 @@ def __update_bgp(self, data_list): if not key_map.run_command(self, table, data, cmd_prefix): syslog.syslog(syslog.LOG_ERR, 'failed running BFD multi-hop config command') continue - else: + else: syslog.syslog(syslog.LOG_INFO, 'Delete BFD multi hop to {} {} {} {}'.format(remoteaddr, vrf, localaddr, interface)) if not 'null' in interface: command = "vtysh -c 'configure terminal' -c 'bfd' -c 'no peer {} vrf {} multihop local-address {} interface {}'".\ @@ -3116,7 +3118,7 @@ def __update_bgp(self, data_list): if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to delete multihop peer {}'.format(key)) continue - self.__delete_bfd_peer(data) + self.__delete_bfd_peer(data) elif table == 'IP_SLA': sla_id = prefix icmp_config = False @@ -3454,7 +3456,7 @@ def __update_bgp(self, data_list): if (command != ""): if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to delete default-info/redistribute {}'.format(protocol.lower())) - continue + continue else: self.__ospf_delete(data) else: @@ -3464,7 +3466,7 @@ def __update_bgp(self, data_list): if not self.__run_command(table, command): syslog.syslog(syslog.LOG_ERR, 'failed to delete distribute-list {} {}'.format(protocol, direction)) - continue + continue self.__ospf_delete(data) diff --git a/src/sonic-frr-mgmt-framework/pytest.ini b/src/sonic-frr-mgmt-framework/pytest.ini index a49b58e45f0f..c857ef5cd502 100644 --- a/src/sonic-frr-mgmt-framework/pytest.ini +++ b/src/sonic-frr-mgmt-framework/pytest.ini @@ -1,2 +1,2 @@ [pytest] -addopts = --cov=bgpcfgd --cov-report term +addopts = --cov=frrcfgd --cov-report term diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index fb1ead11986b..16642b37113b 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -25,5 +25,30 @@ 'pytest', 'pytest-cov', 'sonic-config-engine' + ], + data_files = [('frr/common', ['templates/common/daemons.common.conf.j2']), + ('frr/bgpd', ['templates/bgpd/bgpd.conf.db.j2', + 'templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2', + 'templates/bgpd/bgpd.main.conf.j2', + 'templates/bgpd/bgpd.conf.j2', + 'templates/bgpd/bgpd.conf.db.route_map.j2', + 'templates/bgpd/bgpd.conf.db.pref_list.j2', + 'templates/bgpd/bgpd.conf.db.nbr_or_peer.j2', + 'templates/bgpd/bgpd.conf.db.nbr_af.j2', + 'templates/bgpd/bgpd.conf.db.comm_list.j2', + 'templates/bgpd/bgpd.conf.db.addr_family.j2', + 'templates/bgpd/bgpd.conf.db.addr_family.evpn.j2']), + ('frr/bfdd', ['templates/bfdd/bfdd.conf.j2']), + ('frr/ospfd', ['templates/ospfd/ospfd.conf.j2', + 'templates/ospfd/ospfd.conf.db.area.j2', + 'templates/ospfd/ospfd.conf.db.comm_list.j2', + 'templates/ospfd/ospfd.conf.db.distributeroute.j2', + 'templates/ospfd/ospfd.conf.db.interface.j2', + 'templates/ospfd/ospfd.conf.db.policyrange.j2', + 'templates/ospfd/ospfd.conf.db.vlink.j2']), + ('frr/staticd', ['templates/staticd/staticd.conf.j2', + 'templates/staticd/staticd.db.conf.j2', + 'templates/staticd/staticd.default_route.conf.j2']), + ('frr/supervisord', ['templates/supervisord/supervisord.conf.j2']) ] ) diff --git a/dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bfdd/bfdd.conf.j2 rename to src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/.bgpd.conf.j2.swp b/src/sonic-frr-mgmt-framework/templates/bgpd/.bgpd.conf.j2.swp new file mode 100644 index 0000000000000000000000000000000000000000..56eddb90ceeaeb76cd63177396bf8fb5987745e3 GIT binary patch literal 12288 zcmeI2&x_MQ6vt=1YF$zAARZ=_(u1T~E66HVsM`uF)CH}3S=KN~CTVt)Nu8PO+KTSY z|Hgm7vx?$Xy!qoMconbWOPa3zVbO~R@eO=Cll0}iH=m@3lCQI}x!$3xwG{&61R-B{ zzSuACJtt3(5;7e2SdyLp&G7b=G8LD5T$=Sui-RBM2`x5ECAa-V?pi7lp=&y67ptqnWpqrp;psS#>pfjLvMUBrezW_Z0nV|Ea*T)EX1;T*@kN^@u z0!RP}AOR$R1dsp{_#*-aF(?-vO?*1`316Y}K4F7AtYmSaPb-hIbtv2@^*AkOv9*|m zV(cj{7ZE&CJX=DAzg}amq1@l>Ibd-fw*#G5!5nQ*G&8YWu=mM`$#vnVUPx-1&P+3N zEN5VsCzV{7Y4L-oq9|& zNYMB>Xom@CI!`q+#k+n01!!x7-rDF=?uDAhOr$J|22)oa=E(N?tHu{R5xHyLAU^<8 CP)%_F literal 0 HcmV?d00001 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.evpn.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.addr_family.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.comm_list.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.comm_list.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.comm_list.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.nbr_af.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_af.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.nbr_af.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.nbr_or_peer.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.nbr_or_peer.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.nbr_or_peer.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.pref_list.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.pref_list.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.pref_list.j2 diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.route_map.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.db.route_map.j2 rename to src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.route_map.j2 diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 new file mode 100644 index 000000000000..006108dbf78a --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 @@ -0,0 +1,22 @@ +! +! template: bgpd/bgpd.conf.j2 +! +{% block banner %} +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/quagga/bgpd.conf.j2 with config DB data +! file: bgpd.conf +! +{% endblock banner %} +! +{% include "common/daemons.common.conf.j2" %} +! +agentx +! +{% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} +{% include "bgpd.spine_chassis_frontend_router.conf.j2" %} +{% endif %} +! +{% include "bgpd.conf.db.j2" %} +! +! end of template: bgpd/bgpd.conf.j2 +! diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 new file mode 100644 index 000000000000..eab4a2702191 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 @@ -0,0 +1,116 @@ +{% from "common/functions.conf.j2" import get_ipv4_loopback_address, get_ipv6_loopback_address, get_vnet_interfaces %} +! +! template: bgpd/bgpd.main.conf.j2 +! +! bgp multiple-instance +! +! BGP configuration +! +! TSA configuration +! +ip prefix-list PL_LoopbackV4 permit {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }}/32 +! +{% if get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") != 'None' %} +ipv6 prefix-list PL_LoopbackV6 permit {{ get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | replace('/128', '/64') | ip_network }}/64 +{% endif %} +! +{% if VLAN_INTERFACE is defined %} +{% set vnet_intfs = get_vnet_interfaces(VLAN_INTERFACE) %} +{% endif %} +{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} +{% if prefix | ipv4 and name not in vnet_intfs %} +ip prefix-list LOCAL_VLAN_IPV4_PREFIX seq {{ loop.index * 5 }} permit {{ prefix | ip_network }}/{{ prefix | prefixlen }} +! +{% endif %} +{% endfor %} +{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} +{% if prefix | ipv6 and name not in vnet_intfs %} +ipv6 prefix-list LOCAL_VLAN_IPV6_PREFIX seq {{ loop.index * 5 }} permit {{ prefix | ip_network }}/{{ prefix | prefixlen }} +! +{% endif %} +{% endfor %} +! +{% if DEVICE_METADATA['localhost']['sub_role'] == 'FrontEnd' or DEVICE_METADATA['localhost']['sub_role'] == 'BackEnd' %} +route-map HIDE_INTERNAL permit 10 + set community local-AS +! +{% endif %} +! +router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} +! +{% block bgp_init %} + bgp log-neighbor-changes + no bgp default ipv4-unicast +! +{% if constants.bgp.multipath_relax.enabled is defined and constants.bgp.multipath_relax.enabled %} + bgp bestpath as-path multipath-relax +{% endif %} +! +{% if constants.bgp.graceful_restart.enabled is defined and constants.bgp.graceful_restart.enabled %} + bgp graceful-restart restart-time {{ constants.bgp.graceful_restart.restart_time | default(240) }} + bgp graceful-restart + bgp graceful-restart preserve-fw-state +{% endif %} +! +{# set router-id #} +{% if multi_asic() %} + bgp router-id {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") | ip }} +{% else %} + bgp router-id {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }} +{% endif %} +! +{# advertise loopback #} + network {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }}/32 +{% if multi_asic() %} + network {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") | ip }}/32 route-map HIDE_INTERNAL +{% endif %} +! +{% if get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") != 'None' %} + address-family ipv6 + network {{ get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }}/64 + exit-address-family +{% endif %} +{% if multi_asic() %} +{% if get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") != 'None' %} + address-family ipv6 + network {{ get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") | ip }}/64 route-map HIDE_INTERNAL + exit-address-family +{% endif %} +{% endif %} +{% endblock bgp_init %} +! +{% block vlan_advertisement %} +{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} +{% if prefix | ipv4 and name not in vnet_intfs %} + network {{ prefix }} +{% elif prefix | ipv6 and name not in vnet_intfs %} + address-family ipv6 + network {{ prefix }} + exit-address-family +{% endif %} +{% endfor %} +{% endblock vlan_advertisement %} +! +! +{% if DEVICE_METADATA['localhost']['sub_role'] == 'FrontEnd' %} + address-family ipv4 + redistribute connected route-map HIDE_INTERNAL + exit-address-family + address-family ipv6 + redistribute connected route-map HIDE_INTERNAL + exit-address-family +{% endif %} +! +{% if constants.bgp.maximum_paths.enabled is defined and constants.bgp.maximum_paths.enabled %} +{% block maximum_paths %} + address-family ipv4 + maximum-paths {{ constants.bgp.maximum_paths.ipv4 | default(64) }} + exit-address-family + address-family ipv6 + maximum-paths {{ constants.bgp.maximum_paths.ipv6 | default(64) }} + exit-address-family +{% endblock maximum_paths %} +{% endif %} +! +! end of template: bgpd/bgpd.main.conf.j2 +! diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 new file mode 100644 index 000000000000..94dacbc3af78 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 @@ -0,0 +1,63 @@ +! +{# VNET BGP Instance #} +! Vnet BGP instance +{% set interfaces_in_vnets = [] %} +{% block vnet_bgp_instance %} +{% for vnet_name, vnet_metadata in VNET.items() %} +router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }} + no bgp default ipv4-unicast + bgp log-neighbor-changes + bgp bestpath as-path multipath-relax + no bgp default ipv4-unicast + bgp graceful-restart restart-time 240 + bgp graceful-restart +{# Router ID #} +{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %} +{% if prefix | ipv4 and name == 'Loopback0' %} + bgp router-id {{ prefix | ip }} +{% endif %} +{% endfor %} +{# Got interfaces that belong this vnet #} +{% set interfaces_in_vnet = [] %} +{% for (key, metadata) in INTERFACE.items() %} +{% if "vnet_name" in metadata and metadata["vnet_name"] == vnet_name %} +{% for (name_prefix_pair, metadata) in INTERFACE.items() %} +{% if key == name_prefix_pair[0] %} +{% if interfaces_in_vnet.append( name_prefix_pair[1] | ip ) %} +{% endif %} +{% if interfaces_in_vnets.append( name_prefix_pair[1] | ip ) %} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +{# Each bgp neighbors #} +{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.items() %} +{% if "local_addr" in bgp_session and bgp_session["local_addr"] in interfaces_in_vnet %} +{% if bgp_session['asn'] | int != 0 %} + neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} +{# set the bgp neighbor timers if they have not default values #} +{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) + or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} + neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} +{% endif %} +{% if 'admin_status' in bgp_session and bgp_session['admin_status'] == 'down' or 'admin_status' not in bgp_session and 'default_bgp_status' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} + neighbor {{ neighbor_addr }} shutdown +{% endif %} +{% if neighbor_addr | ipv4 %} + address-family ipv4 unicast + neighbor {{ neighbor_addr }} activate + neighbor {{ neighbor_addr }} soft-reconfiguration inbound + maximum-paths 64 + exit-address-family +{% endif %} + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family +{% endif %} +{% endif %} +{% endfor %} +{% endfor %} +{% endblock vnet_bgp_instance %} +! diff --git a/src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 b/src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 new file mode 100644 index 000000000000..1c3efdfa72fb --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 @@ -0,0 +1,14 @@ +! template: common/daemons.common.conf.j2 +! +{% block sys_init %} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} +password zebra +enable password zebra +{% endblock sys_init %} +! +{% block logging %} +log syslog informational +log facility local4 +{% endblock logging %} +! +! end of template: common/daemons.common.conf.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.area.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.area.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.area.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.comm_list.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.comm_list.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.comm_list.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.distributeroute.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.distributeroute.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.distributeroute.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.interface.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.interface.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.interface.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.policyrange.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.policyrange.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.policyrange.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.vlink.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.db.vlink.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.vlink.j2 diff --git a/dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/ospfd/ospfd.conf.j2 rename to src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/.staticd.conf.j2.swp b/src/sonic-frr-mgmt-framework/templates/staticd/.staticd.conf.j2.swp new file mode 100644 index 0000000000000000000000000000000000000000..226c790e578ac144480448f7130be3eb9f7d6f03 GIT binary patch literal 12288 zcmeI2L2DC16o99CwJPdOgtw8h6y2mokRs%utt~yI0jW_aCCu*3tlQ4cmf77%BPw|G zCy0N-f8o#YtXC055Z|V|Nz)MYSjijsn9OG8&6{s`429@QwZ6izU1scj@}>7N z_{82`U~DjW&XeN$Uz+Hrsh3LIm)2|En?3pUFkpiZaw~f(u?LMbF;U?8d89=Y^H4TY z8fDDiUGC&5%z<+3f3&!3pGWH!Q{{OFj|Np+k*jMB|@(fu+9w4`n zW#rdI#(pB7kq?MLeB>#zjNCx3BR|U6->?r6g-GN!;vm$>02v?yWPl8i0Wv@a$N(82 z182v8!(J|dG$K;tPq6f=xEh&2=R!iQtVga3sd%olo=x)X#B9fL*l;+#z^`hTYemcx zYyM#eIkC3LQm3*^ZJ6+kG|yBr6V9ei6e(zLws(5n#~Z!1&i2OE=C0efsu$|S=i1%d zb&DGDu2qi=_q7!69<*BEDvl=H>iAPJMyf~mBS_*nF%7{bb}4!-h7)?LTjT2_H~^m; zBkge<2UMixeW)ISq8Oby5K5eZ)#?KLBN&&iV_o~{vUSMQ$b?X=i$Yj`2!dxEBecd1 q+T37${4myW(R`pn+yT}*u-(}KDWVKwZgQ^m(ZtG8jN*ZvPW}()z%mX1 literal 0 HcmV?d00001 diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 new file mode 100644 index 000000000000..fea2be47be8f --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 @@ -0,0 +1,20 @@ +! +{% block banner %} +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/frr/staticd.conf.j2 using config DB data +! file: staticd.conf +! +{% endblock banner %} +! +{% include "common/daemons.common.conf.j2" %} +! +{% if MGMT_VRF_CONFIG %} +{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +{% else %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +! +{% include "staticd.db.conf.j2" %} +! diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.conf.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/staticd/staticd.db.conf.j2 rename to src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.conf.j2 diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 new file mode 100644 index 000000000000..22d61ebbd0ff --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 @@ -0,0 +1,10 @@ +! +{% block default_route %} +! set static default route to mgmt gateway as a backup to learned default +{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} +{% if prefix | ipv4 %} +ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 +{% endif %} +{% endfor %} +{% endblock default_route %} +! diff --git a/src/sonic-frr-mgmt-framework/templates/supervisord/.supervisord.conf.j2.swp b/src/sonic-frr-mgmt-framework/templates/supervisord/.supervisord.conf.j2.swp new file mode 100644 index 0000000000000000000000000000000000000000..4ceb8540be17bbd4e94d173a59c70f9fa8a3b9d6 GIT binary patch literal 16384 zcmeI&YiJxr00;1C)!JCAwkm$9bX%=Z>)z$rmn`LM??Y&>(d61n)3EIA&R)jcKA71} zbJ3S*xujJQk~DMS z$3Am2^WWLK*}W~a?(WWM8&j+)UmGYi#f zm4He>C7=>e38(~A0xAKOz&uSL3Kx=tX#2uS`wvy73nopksVpz4OixVOURhKVm4He> zC7=>e38(~A0xAKOfJ#6mpb}6Cs03zV0+vI_pSak+|5{WIzyDXS|1aH4$OSkH@4(w| z0vPOtt3 z5Ej8tHxlwCoQ7xMI6MJ+p$E2r4y#}Z{E8bDU&EX52D|`cAi#z`$UqmYgci7T10f&5 zhwv6W2?rqn6LOG&b#OcU)k4U5_#Do_Q8)x;V6X?aLl>-s#c**k>II*`DR>SJ!vPoq z6S|=TR>05Kqh4?k&cSJT9ZteAI0y`S;a*q^cffCp2>B5%z*%?~UW6m?804W3&Rj>x zYw#=_h66AJCUipwtbkw8KfZ_WU>C^#@-l7;ZNhXJ{DJvz;T(Jbufj<<4kNG+3|I#m z9LEi(W7V5ZP3J{_$b%xD``BD4h9(VIYO1Hp7Qi5>=8io;tJL zqEidGvSI+=W^<_5xS=P?zFpsr%9_hJWRw=THFN!6L_sK6(YH#*_U;`!$i(^3)p$OX zSRsuAlMb2ZXnIC#Yu}J+#a~+2^WiwfsD8IKs`1 zmb=W&Hg`_ls|&8v*yh>+mYZgETPM!gY1)QwyNKD-HLtSu@-5`!U%0d3YkHbSCZD2{ zdacklwT{1J560(nb4O18ZK}5af5VR0rz0V?BkD{)_GoMDl|l|as+nuLujy=O&(3VE zPgb{~=Jg|-DT_+RPjnbVFJU~`+p{&>*Jol7pU;}vhr9FHZH-0Cl50$oPcbvnW# zy~IRBeabam$6zM1F!txVkH^F{d>D}aq=4!^n=ktgsB|HAU5t(d8>L29E19ZxM3!n} zyo6!geH|F;VNl0u#Fw<)uC7=>e3C!69X7Wd) b+Wm#(djH@5hP0viW(w|()c=~A3d`hgKv&`k literal 0 HcmV?d00001 diff --git a/src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 b/src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 new file mode 100644 index 000000000000..c8bff2e27356 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 @@ -0,0 +1,148 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[eventlistener:dependent-startup] +command=python3 -m supervisord_dependent_startup +autostart=true +autorestart=unexpected +startretries=0 +exitcodes=0,3 +events=PROCESS_STATE +buffer_size=50 + +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener --container-name bgp +events=PROCESS_STATE_EXITED +autostart=true +autorestart=unexpected + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n -iNONE +priority=1 +autostart=false +autorestart=unexpected +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true + +[program:zebra] +command=/usr/lib/frr/zebra -A 127.0.0.1 -s 90000000 -M fpm -M snmp +priority=4 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[program:staticd] +command=/usr/lib/frr/staticd -A 127.0.0.1 +priority=4 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:bfdd] +command=/usr/lib/frr/bfdd -A 127.0.0.1 +priority=4 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:bgpd] +command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:ospfd] +command=/usr/lib/frr/ospfd -A 127.0.0.1 -M snmp +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:pimd] +command=/usr/lib/frr/pimd -A 127.0.0.1 +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:fpmsyncd] +command=fpmsyncd +priority=6 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=bgpd:running + +[program:frrcfgd] +command=/usr/local/bin/frrcfgd +priority=6 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=bgpd:running + +{% if DEVICE_METADATA.localhost.docker_routing_config_mode is defined and DEVICE_METADATA.localhost.docker_routing_config_mode == "unified" %} +[program:vtysh_b] +command=/usr/bin/vtysh -b +priority=6 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=bgpd:running +{% endif %} + +{% if WARM_RESTART is defined and WARM_RESTART.bgp is defined and WARM_RESTART.bgp.bgp_eoiu is defined and WARM_RESTART.bgp.bgp_eoiu == "true" %} +[program:bgp_eoiu_marker] +command=/usr/bin/bgp_eoiu_marker.py +priority=7 +autostart=false +autorestart=false +startsecs=0 +startretries=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=bgpd:running +{% endif %} From 609bcb7ab44f7902aa2eae6725c16d49bc0acfcf Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Tue, 29 Dec 2020 18:58:58 +0000 Subject: [PATCH 08/24] Removed not needed and temporary files --- .../templates/bgpd/.bgpd.conf.j2.swp | Bin 12288 -> 0 bytes .../templates/bgpd/bgpd.main.conf.j2 | 116 ------------------ .../supervisord/.supervisord.conf.j2.swp | Bin 16384 -> 0 bytes 3 files changed, 116 deletions(-) delete mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/.bgpd.conf.j2.swp delete mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 delete mode 100644 src/sonic-frr-mgmt-framework/templates/supervisord/.supervisord.conf.j2.swp diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/.bgpd.conf.j2.swp b/src/sonic-frr-mgmt-framework/templates/bgpd/.bgpd.conf.j2.swp deleted file mode 100644 index 56eddb90ceeaeb76cd63177396bf8fb5987745e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2&x_MQ6vt=1YF$zAARZ=_(u1T~E66HVsM`uF)CH}3S=KN~CTVt)Nu8PO+KTSY z|Hgm7vx?$Xy!qoMconbWOPa3zVbO~R@eO=Cll0}iH=m@3lCQI}x!$3xwG{&61R-B{ zzSuACJtt3(5;7e2SdyLp&G7b=G8LD5T$=Sui-RBM2`x5ECAa-V?pi7lp=&y67ptqnWpqrp;psS#>pfjLvMUBrezW_Z0nV|Ea*T)EX1;T*@kN^@u z0!RP}AOR$R1dsp{_#*-aF(?-vO?*1`316Y}K4F7AtYmSaPb-hIbtv2@^*AkOv9*|m zV(cj{7ZE&CJX=DAzg}amq1@l>Ibd-fw*#G5!5nQ*G&8YWu=mM`$#vnVUPx-1&P+3N zEN5VsCzV{7Y4L-oq9|& zNYMB>Xom@CI!`q+#k+n01!!x7-rDF=?uDAhOr$J|22)oa=E(N?tHu{R5xHyLAU^<8 CP)%_F diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 deleted file mode 100644 index eab4a2702191..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.main.conf.j2 +++ /dev/null @@ -1,116 +0,0 @@ -{% from "common/functions.conf.j2" import get_ipv4_loopback_address, get_ipv6_loopback_address, get_vnet_interfaces %} -! -! template: bgpd/bgpd.main.conf.j2 -! -! bgp multiple-instance -! -! BGP configuration -! -! TSA configuration -! -ip prefix-list PL_LoopbackV4 permit {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }}/32 -! -{% if get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") != 'None' %} -ipv6 prefix-list PL_LoopbackV6 permit {{ get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | replace('/128', '/64') | ip_network }}/64 -{% endif %} -! -{% if VLAN_INTERFACE is defined %} -{% set vnet_intfs = get_vnet_interfaces(VLAN_INTERFACE) %} -{% endif %} -{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} -{% if prefix | ipv4 and name not in vnet_intfs %} -ip prefix-list LOCAL_VLAN_IPV4_PREFIX seq {{ loop.index * 5 }} permit {{ prefix | ip_network }}/{{ prefix | prefixlen }} -! -{% endif %} -{% endfor %} -{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} -{% if prefix | ipv6 and name not in vnet_intfs %} -ipv6 prefix-list LOCAL_VLAN_IPV6_PREFIX seq {{ loop.index * 5 }} permit {{ prefix | ip_network }}/{{ prefix | prefixlen }} -! -{% endif %} -{% endfor %} -! -{% if DEVICE_METADATA['localhost']['sub_role'] == 'FrontEnd' or DEVICE_METADATA['localhost']['sub_role'] == 'BackEnd' %} -route-map HIDE_INTERNAL permit 10 - set community local-AS -! -{% endif %} -! -router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} -! -{% block bgp_init %} - bgp log-neighbor-changes - no bgp default ipv4-unicast -! -{% if constants.bgp.multipath_relax.enabled is defined and constants.bgp.multipath_relax.enabled %} - bgp bestpath as-path multipath-relax -{% endif %} -! -{% if constants.bgp.graceful_restart.enabled is defined and constants.bgp.graceful_restart.enabled %} - bgp graceful-restart restart-time {{ constants.bgp.graceful_restart.restart_time | default(240) }} - bgp graceful-restart - bgp graceful-restart preserve-fw-state -{% endif %} -! -{# set router-id #} -{% if multi_asic() %} - bgp router-id {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") | ip }} -{% else %} - bgp router-id {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }} -{% endif %} -! -{# advertise loopback #} - network {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }}/32 -{% if multi_asic() %} - network {{ get_ipv4_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") | ip }}/32 route-map HIDE_INTERNAL -{% endif %} -! -{% if get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") != 'None' %} - address-family ipv6 - network {{ get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback0") | ip }}/64 - exit-address-family -{% endif %} -{% if multi_asic() %} -{% if get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") != 'None' %} - address-family ipv6 - network {{ get_ipv6_loopback_address(LOOPBACK_INTERFACE, "Loopback4096") | ip }}/64 route-map HIDE_INTERNAL - exit-address-family -{% endif %} -{% endif %} -{% endblock bgp_init %} -! -{% block vlan_advertisement %} -{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} -{% if prefix | ipv4 and name not in vnet_intfs %} - network {{ prefix }} -{% elif prefix | ipv6 and name not in vnet_intfs %} - address-family ipv6 - network {{ prefix }} - exit-address-family -{% endif %} -{% endfor %} -{% endblock vlan_advertisement %} -! -! -{% if DEVICE_METADATA['localhost']['sub_role'] == 'FrontEnd' %} - address-family ipv4 - redistribute connected route-map HIDE_INTERNAL - exit-address-family - address-family ipv6 - redistribute connected route-map HIDE_INTERNAL - exit-address-family -{% endif %} -! -{% if constants.bgp.maximum_paths.enabled is defined and constants.bgp.maximum_paths.enabled %} -{% block maximum_paths %} - address-family ipv4 - maximum-paths {{ constants.bgp.maximum_paths.ipv4 | default(64) }} - exit-address-family - address-family ipv6 - maximum-paths {{ constants.bgp.maximum_paths.ipv6 | default(64) }} - exit-address-family -{% endblock maximum_paths %} -{% endif %} -! -! end of template: bgpd/bgpd.main.conf.j2 -! diff --git a/src/sonic-frr-mgmt-framework/templates/supervisord/.supervisord.conf.j2.swp b/src/sonic-frr-mgmt-framework/templates/supervisord/.supervisord.conf.j2.swp deleted file mode 100644 index 4ceb8540be17bbd4e94d173a59c70f9fa8a3b9d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI&YiJxr00;1C)!JCAwkm$9bX%=Z>)z$rmn`LM??Y&>(d61n)3EIA&R)jcKA71} zbJ3S*xujJQk~DMS z$3Am2^WWLK*}W~a?(WWM8&j+)UmGYi#f zm4He>C7=>e38(~A0xAKOz&uSL3Kx=tX#2uS`wvy73nopksVpz4OixVOURhKVm4He> zC7=>e38(~A0xAKOfJ#6mpb}6Cs03zV0+vI_pSak+|5{WIzyDXS|1aH4$OSkH@4(w| z0vPOtt3 z5Ej8tHxlwCoQ7xMI6MJ+p$E2r4y#}Z{E8bDU&EX52D|`cAi#z`$UqmYgci7T10f&5 zhwv6W2?rqn6LOG&b#OcU)k4U5_#Do_Q8)x;V6X?aLl>-s#c**k>II*`DR>SJ!vPoq z6S|=TR>05Kqh4?k&cSJT9ZteAI0y`S;a*q^cffCp2>B5%z*%?~UW6m?804W3&Rj>x zYw#=_h66AJCUipwtbkw8KfZ_WU>C^#@-l7;ZNhXJ{DJvz;T(Jbufj<<4kNG+3|I#m z9LEi(W7V5ZP3J{_$b%xD``BD4h9(VIYO1Hp7Qi5>=8io;tJL zqEidGvSI+=W^<_5xS=P?zFpsr%9_hJWRw=THFN!6L_sK6(YH#*_U;`!$i(^3)p$OX zSRsuAlMb2ZXnIC#Yu}J+#a~+2^WiwfsD8IKs`1 zmb=W&Hg`_ls|&8v*yh>+mYZgETPM!gY1)QwyNKD-HLtSu@-5`!U%0d3YkHbSCZD2{ zdacklwT{1J560(nb4O18ZK}5af5VR0rz0V?BkD{)_GoMDl|l|as+nuLujy=O&(3VE zPgb{~=Jg|-DT_+RPjnbVFJU~`+p{&>*Jol7pU;}vhr9FHZH-0Cl50$oPcbvnW# zy~IRBeabam$6zM1F!txVkH^F{d>D}aq=4!^n=ktgsB|HAU5t(d8>L29E19ZxM3!n} zyo6!geH|F;VNl0u#Fw<)uC7=>e3C!69X7Wd) b+Wm#(djH@5hP0viW(w|()c=~A3d`hgKv&`k From 64561d6e2ea064114dd20c553b0dcb0beeafd51f Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Tue, 29 Dec 2020 20:02:46 +0000 Subject: [PATCH 09/24] Fixed setup.py not copying un-needed template file --- src/sonic-frr-mgmt-framework/setup.py | 1 - .../templates/staticd/.staticd.conf.j2.swp | Bin 12288 -> 0 bytes 2 files changed, 1 deletion(-) delete mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/.staticd.conf.j2.swp diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index 16642b37113b..667a34c3c132 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -29,7 +29,6 @@ data_files = [('frr/common', ['templates/common/daemons.common.conf.j2']), ('frr/bgpd', ['templates/bgpd/bgpd.conf.db.j2', 'templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2', - 'templates/bgpd/bgpd.main.conf.j2', 'templates/bgpd/bgpd.conf.j2', 'templates/bgpd/bgpd.conf.db.route_map.j2', 'templates/bgpd/bgpd.conf.db.pref_list.j2', diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/.staticd.conf.j2.swp b/src/sonic-frr-mgmt-framework/templates/staticd/.staticd.conf.j2.swp deleted file mode 100644 index 226c790e578ac144480448f7130be3eb9f7d6f03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2L2DC16o99CwJPdOgtw8h6y2mokRs%utt~yI0jW_aCCu*3tlQ4cmf77%BPw|G zCy0N-f8o#YtXC055Z|V|Nz)MYSjijsn9OG8&6{s`429@QwZ6izU1scj@}>7N z_{82`U~DjW&XeN$Uz+Hrsh3LIm)2|En?3pUFkpiZaw~f(u?LMbF;U?8d89=Y^H4TY z8fDDiUGC&5%z<+3f3&!3pGWH!Q{{OFj|Np+k*jMB|@(fu+9w4`n zW#rdI#(pB7kq?MLeB>#zjNCx3BR|U6->?r6g-GN!;vm$>02v?yWPl8i0Wv@a$N(82 z182v8!(J|dG$K;tPq6f=xEh&2=R!iQtVga3sd%olo=x)X#B9fL*l;+#z^`hTYemcx zYyM#eIkC3LQm3*^ZJ6+kG|yBr6V9ei6e(zLws(5n#~Z!1&i2OE=C0efsu$|S=i1%d zb&DGDu2qi=_q7!69<*BEDvl=H>iAPJMyf~mBS_*nF%7{bb}4!-h7)?LTjT2_H~^m; zBkge<2UMixeW)ISq8Oby5K5eZ)#?KLBN&&iV_o~{vUSMQ$b?X=i$Yj`2!dxEBecd1 q+T37${4myW(R`pn+yT}*u-(}KDWVKwZgQ^m(ZtG8jN*ZvPW}()z%mX1 From 0299bf350c88a20836bf9be37414318181cdbb12 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Wed, 30 Dec 2020 02:19:14 +0000 Subject: [PATCH 10/24] Added critical process list switch and fix issue related to python3 migration --- dockers/docker-fpm-frr/critical_processes | 1 - dockers/docker-fpm-frr/docker_init.sh | 10 +++++++++ .../frrcfgd/frrcfgd.py | 21 ++++++++++++------- src/sonic-frr-mgmt-framework/setup.py | 3 ++- .../templates/supervisord/critical_processes | 8 +++++++ 5 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes diff --git a/dockers/docker-fpm-frr/critical_processes b/dockers/docker-fpm-frr/critical_processes index a166f5c97a3c..2631fee15e66 100644 --- a/dockers/docker-fpm-frr/critical_processes +++ b/dockers/docker-fpm-frr/critical_processes @@ -3,4 +3,3 @@ program:staticd program:bgpd program:fpmsyncd program:bgpcfgd -program:frrcfgd diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index bc59b075ce24..124f07f3406d 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -4,6 +4,7 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d MGMT_FRAMEWORK_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]'` +CRIT_PROC_BACKUP="/usr/local/frr/supervisord/critical_processes.bak" if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then CFGGEN_PARAMS=" \ -d \ @@ -19,6 +20,11 @@ if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; th -t /usr/local/frr/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ -t /usr/local/frr/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ " + if [ ! -f $CRIT_PROC_BACKUP ]; then + mv /etc/supervisor/critical_processes $CRIT_PROC_BACKUP + fi + # change critical process list with those of enterprise release + cp /usr/local/frr/supervisord/critical_processes /etc/supervisor else CFGGEN_PARAMS=" \ -d \ @@ -32,6 +38,10 @@ else -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ " + if [ -f $CRIT_PROC_BACKUP ]; then + # restore original critical process list for community release + mv -f $CRIT_PROC_BACKUP /etc/supervisor/critical_processes + fi fi CONFIG_TYPE=$(sonic-cfggen $CFGGEN_PARAMS) diff --git a/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py index f083a672b5fe..e098dc5e2fd3 100755 --- a/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py +++ b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py @@ -169,6 +169,11 @@ def __get_reply(sock): break msg_buf.close() return (ret_code, reply_msg) + @staticmethod + def __send_data(sock, data): + if isinstance(data, str): + data = bytes(data, 'utf-8') + sock.sendall(data) def __create_frr_client(self): self.client_socks = {} for daemon in self.ALL_DAEMONS: @@ -194,7 +199,7 @@ def __create_frr_client(self): for daemon, sock in self.client_socks.items(): syslog.syslog(syslog.LOG_DEBUG, 'send initial enable command to %s' % daemon) try: - sock.sendall(bytes('enable\0', 'utf-8')) + self.__send_data(sock, 'enable\0') except socket.error as msg: syslog.syslog(syslog.LOG_ERR, 'failed to send initial enable command to %s' % daemon) return False @@ -250,7 +255,7 @@ def __proc_command(self, command, daemons): syslog.syslog(syslog.LOG_ERR, 'daemon %s is not connected' % daemon) continue try: - sock.sendall(command + '\0') + self.__send_data(sock, command + '\0') except socket.error as msg: syslog.syslog(syslog.LOG_ERR, 'failed to send command to frr daemon: %s' % msg) return (False, None) @@ -284,7 +289,7 @@ def run_vtysh_command(self, table, command, daemons): ret_val = True with self.lock: for cmd in cmd_list: - succ, reply = self.__proc_command(cmd.strip(), daemons) + succ, _ = self.__proc_command(cmd.strip(), daemons) if not succ: ret_val = False return ret_val @@ -335,7 +340,7 @@ def run(self): for line in in_lines: _, reply = self.__proc_command(line.strip(), daemons) if reply is not None: - conn_sock.sendall(reply) + self.__send_data(conn_sock, reply) else: syslog.syslog(syslog.LOG_ERR, 'failed running VTYSH command') else: @@ -1437,7 +1442,7 @@ class ExtConfigDBConnector(ConfigDBConnector): def __init__(self, ns_attrs = None): super(ExtConfigDBConnector, self).__init__() self.nosort_attrs = ns_attrs if ns_attrs is not None else {} - def raw_to_typed(self, table, raw_data): + def raw_to_typed(self, raw_data, table = ''): if len(raw_data) == 0: raw_data = None data = super(ExtConfigDBConnector, self).raw_to_typed(raw_data) @@ -1454,7 +1459,7 @@ def sub_msg_handler(self, msg_item): (table, row) = key.split(self.TABLE_NAME_SEPARATOR, 1) if table in self.handlers: client = self.get_redis_client(self.db_name) - data = self.raw_to_typed(table, client.hgetall(key)) + data = self.raw_to_typed(client.hgetall(key), table) super(ExtConfigDBConnector, self)._ConfigDBConnector__fire(table, row, data) except ValueError: pass #Ignore non table-formated redis entries @@ -2419,11 +2424,11 @@ def __apply_dep_vrf_table(self, vrf, table_name, *table_key, **extra_args): entry_list = self.config_db.get_table(table_name) match_fn = extra_args.get('match', None) for key, data in entry_list.items(): - if len(key) == 0 or key[0] != vrf: + if data is None or len(key) == 0 or key[0] != vrf: continue if match_fn is not None and not match_fn(data): continue - syslog.syslog(syslog.LOG_DEBUG, 'attr re-apply for vrf {} table {} key {}'.format(vrf, table_name, key)) + syslog.syslog(syslog.LOG_DEBUG, 'attr re-apply for vrf {} table {} key {} data {}'.format(vrf, table_name, key, data)) upd_data = {} for upd_key, upd_val in data.items(): upd_data[upd_key] = CachedDataWithOp(upd_val, CachedDataWithOp.OP_ADD) diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index 667a34c3c132..9b8bfac675f1 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -48,6 +48,7 @@ ('frr/staticd', ['templates/staticd/staticd.conf.j2', 'templates/staticd/staticd.db.conf.j2', 'templates/staticd/staticd.default_route.conf.j2']), - ('frr/supervisord', ['templates/supervisord/supervisord.conf.j2']) + ('frr/supervisord', ['templates/supervisord/supervisord.conf.j2', + 'templates/supervisord/critical_processes']) ] ) diff --git a/src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes b/src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes new file mode 100644 index 000000000000..1d9e5aa3427e --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes @@ -0,0 +1,8 @@ +program:zebra +program:staticd +program:bfdd +program:bgpd +program:ospfd +program:pimd +program:fpmsyncd +program:frrcfgd From a38469a277c44a1d42efe8840f64ec6bc9cbd363 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Wed, 30 Dec 2020 04:04:47 +0000 Subject: [PATCH 11/24] Replaced python3 un-compatible function --- src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 | 4 ++-- .../templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 | 6 +++--- .../templates/bgpd/bgpd.conf.db.addr_family.j2 | 6 +++--- src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 | 4 ++-- .../templates/ospfd/ospfd.conf.db.interface.j2 | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 index fc3b4f177f32..a4c07c026375 100644 --- a/src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 +++ b/src/sonic-frr-mgmt-framework/templates/bfdd/bfdd.conf.j2 @@ -9,7 +9,7 @@ {% block bfd_shop_peers %} {% if BFD_PEER_SINGLE_HOP %} bfd -{% for (peer_key, peer_info) in BFD_PEER_SINGLE_HOP.iteritems() %} +{% for (peer_key, peer_info) in BFD_PEER_SINGLE_HOP.items() %} {% set peer_args = '' %} {% if peer_key[0] != 'null' %} {% set peer_args = peer_args~' '~'peer'~' '~peer_key[0] %} @@ -53,7 +53,7 @@ bfd {% block bfd_mhop_peers %} {% if BFD_PEER_MULTI_HOP %} bfd -{% for (peer_key, peer_info) in BFD_PEER_MULTI_HOP.iteritems() %} +{% for (peer_key, peer_info) in BFD_PEER_MULTI_HOP.items() %} {% set peer_args = '' %} {% if peer_key[0] != 'null' %} {% set peer_args = peer_args~' '~'peer'~' '~peer_key[0] %} diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 index 4178180a6d6d..c0db96c24dd7 100644 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.evpn.j2 @@ -39,14 +39,14 @@ {% endfor %} {% endif %} {% if BGP_GLOBALS_EVPN_RT is defined and BGP_GLOBALS_EVPN_RT|length > 0 %} -{% for evpn_rt_key, evpn_rt_val in BGP_GLOBALS_EVPN_RT.iteritems() %} +{% for evpn_rt_key, evpn_rt_val in BGP_GLOBALS_EVPN_RT.items() %} {% if vrf == evpn_rt_key[0] %} route-target {{evpn_rt_val['route-target-type']}} {{evpn_rt_key[2]}} {% endif %} {% endfor %} {% endif %} {% if BGP_GLOBALS_EVPN_VNI is defined and BGP_GLOBALS_EVPN_VNI|length > 0 %} -{% for vni_key, vni_val in BGP_GLOBALS_EVPN_VNI.iteritems() %} +{% for vni_key, vni_val in BGP_GLOBALS_EVPN_VNI.items() %} {% if vrf == vni_key[0] %} vni {{vni_key[2]}} {% if 'route-distinguisher' in vni_val %} @@ -63,7 +63,7 @@ {% endfor %} {% endif %} {% if BGP_GLOBALS_EVPN_VNI_RT is defined and BGP_GLOBALS_EVPN_VNI_RT|length > 0 %} -{% for vni_rt_key, vni_rt_val in BGP_GLOBALS_EVPN_VNI_RT.iteritems() %} +{% for vni_rt_key, vni_rt_val in BGP_GLOBALS_EVPN_VNI_RT.items() %} {% if vrf == vni_rt_key[0] and vni_key[2] == vni_rt_key[2] %} route-target {{vni_rt_val['route-target-type']}} {{vni_rt_key[3]}} {% endif %} diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.j2 index a0a98d5f6339..9bf005518cc3 100644 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.j2 +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.addr_family.j2 @@ -14,7 +14,7 @@ ! address-family {{af_str}} {{safi_str_map[af]}} {% if BGP_GLOBALS_AF is defined and BGP_GLOBALS_AF|length > 0 %} -{% for af_key, af_val in BGP_GLOBALS_AF.iteritems() %} +{% for af_key, af_val in BGP_GLOBALS_AF.items() %} {% if vrf == af_key[0] and af == af_key[1] %} {% if 'ebgp_route_distance' in af_val and 'ibgp_route_distance' in af_val and 'local_route_distance' in af_val %} distance bgp {{af_val['ebgp_route_distance']}} {{af_val['ibgp_route_distance']}} {{af_val['local_route_distance']}} @@ -30,7 +30,7 @@ {% endif %} {# ------- network-prefix --------------------------- #} {% if BGP_GLOBALS_AF_NETWORK is defined and BGP_GLOBALS_AF_NETWORK|length > 0 %} -{% for af_nw_key, af_nw_val in BGP_GLOBALS_AF_NETWORK.iteritems() %} +{% for af_nw_key, af_nw_val in BGP_GLOBALS_AF_NETWORK.items() %} {% if vrf == af_nw_key[0] and af == af_nw_key[1] %} {% set af_nw_ns = namespace(nw_end = '') %} {% if 'backdoor' in af_nw_val and af_nw_val['backdoor'] == 'true' %} @@ -46,7 +46,7 @@ {# ------- network-prefix end --------------------------- #} {# ------- aggregate-prefix -Start--------------------------- #} {% if BGP_GLOBALS_AF_AGGREGATE_ADDR is defined and BGP_GLOBALS_AF_AGGREGATE_ADDR|length > 0 %} -{% for af_ag_key, af_ag_val in BGP_GLOBALS_AF_AGGREGATE_ADDR.iteritems() %} +{% for af_ag_key, af_ag_val in BGP_GLOBALS_AF_AGGREGATE_ADDR.items() %} {% set af_ag_ns = namespace(ag_end = '') %} {% if vrf == af_ag_key[0] and af == af_ag_key[1] %} {% if 'as_set' in af_ag_val and af_ag_val['as_set'] == 'true' %} diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 index cd3af528a442..11794bbf2ba9 100644 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 @@ -153,7 +153,7 @@ router bgp {{ bgp_sess['local_asn']}} vrf {{ vrf }} {# -------globals end --------------------------- #} {# -------peer-group --------------------------- #} {% if BGP_PEER_GROUP is defined and BGP_PEER_GROUP|length > 0 %} -{% for peer_group, nbr_or_peer in BGP_PEER_GROUP.iteritems() %} +{% for peer_group, nbr_or_peer in BGP_PEER_GROUP.items() %} {% if vrf == peer_group[0] %} {% set name_or_ip = peer_group[1] %} {% set nbr_or_peer_type = 'peer-group' %} @@ -164,7 +164,7 @@ router bgp {{ bgp_sess['local_asn']}} vrf {{ vrf }} {# -------peer-group end --------------------------- #} {# -------neighbor --------------------------- #} {% if BGP_NEIGHBOR is defined and BGP_NEIGHBOR|length > 0 %} -{% for nbr_addr, nbr_or_peer in BGP_NEIGHBOR.iteritems() %} +{% for nbr_addr, nbr_or_peer in BGP_NEIGHBOR.items() %} {% if nbr_addr is not string and nbr_addr|length > 1 %} {% if vrf == nbr_addr[0] %} {% set name_or_ip = nbr_addr[1] %} diff --git a/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.interface.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.interface.j2 index f5ea6c5c4785..7969c81f2dad 100644 --- a/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.interface.j2 +++ b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.db.interface.j2 @@ -1,7 +1,7 @@ {# ------------------------------------------------------------------------------------ #} {# ------------------------------------------------------------------------------------ #} {% if OSPFV2_INTERFACE is defined and OSPFV2_INTERFACE|length > 0 %} -{% for (intfkey, ospf_intf_instance) in OSPFV2_INTERFACE.iteritems() %} +{% for (intfkey, ospf_intf_instance) in OSPFV2_INTERFACE.items() %} ! {% set intfname = intfkey[0] %} {% set intfaddr = intfkey[1] %} From 022742157f3e7347728fd155d2cf1d9cc341d1fb Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Thu, 31 Dec 2020 08:56:44 +0000 Subject: [PATCH 12/24] Added UT scripts and fixed minor issues in frrcfgd --- .../frrcfgd/frrcfgd.py | 9 +- .../tests/test_constructor.py | 230 ++++++++++++++++++ 2 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 src/sonic-frr-mgmt-framework/tests/test_constructor.py diff --git a/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py index e098dc5e2fd3..e3b8c3f264c8 100755 --- a/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py +++ b/src/sonic-frr-mgmt-framework/frrcfgd/frrcfgd.py @@ -503,10 +503,13 @@ def __init__(self, cmd_str, hdlr, data): else: self.hdl_func = hdlr self.data = data + def same_daemons(self, other): + dset = lambda d: set() if d is None else set(d) + return dset(self.daemons) == dset(other.daemons) def __eq__(self, other): - return set(self.daemons) == set(other.daemons) and self.run_cmd == other.run_cmd + return self.same_daemons(other) and self.run_cmd == other.run_cmd def __ne__(self, other): - return set(self.daemons) != set(other.daemons) or self.run_cmd != other.run_cmd + return not self.same_daemons(other) or self.run_cmd != other.run_cmd def __hash__(self): return hash(self.run_cmd) def get_command(self, daemon, op, st_idx, *vals): @@ -1650,7 +1653,7 @@ def __str__(self): return 'AF %d BKH %s IP %s TRACK %d INTF %s TAG %d DIST %d VRF %s' % ( self.af, self.blackhole, self.ip, self.track, self.interface, self.tag, self.distance, self.nh_vrf) def is_zero_ip(self): - return sum([ord(x) for x in socket.inet_pton(self.af, self.ip)]) == 0 + return sum([x for x in socket.inet_pton(self.af, self.ip)]) == 0 def get_arg_list(self): arg = lambda x: '' if x is None else x num_arg = lambda x: '' if x is None or x == 0 else str(x) diff --git a/src/sonic-frr-mgmt-framework/tests/test_constructor.py b/src/sonic-frr-mgmt-framework/tests/test_constructor.py new file mode 100644 index 000000000000..55615544d6be --- /dev/null +++ b/src/sonic-frr-mgmt-framework/tests/test_constructor.py @@ -0,0 +1,230 @@ +import socket +import pytest + +from frrcfgd.frrcfgd import CachedDataWithOp +from frrcfgd.frrcfgd import BGPPeerGroup +from frrcfgd.frrcfgd import BGPKeyMapInfo +from frrcfgd.frrcfgd import BGPKeyMapList +from frrcfgd.frrcfgd import get_command_cmn +from frrcfgd.frrcfgd import CommunityList +from frrcfgd.frrcfgd import MatchPrefix +from frrcfgd.frrcfgd import MatchPrefixList +from frrcfgd.frrcfgd import AggregateAddr +from frrcfgd.frrcfgd import IpNextHop +from frrcfgd.frrcfgd import IpNextHopSet + +def test_data_with_op(): + data = CachedDataWithOp() + assert(data.data is None) + assert(data.op == CachedDataWithOp.OP_NONE) + data = CachedDataWithOp(10, CachedDataWithOp.OP_ADD) + assert(data.data == 10) + assert(data.op == CachedDataWithOp.OP_ADD) + +def test_peer_group(): + pg = BGPPeerGroup('Vrf_red') + assert(pg.vrf == 'Vrf_red') + assert(len(pg.ref_nbrs) == 0) + +def test_command_map(): + def cmd_hdlr(): + pass + key_map1 = BGPKeyMapInfo('test command', cmd_hdlr, None) + assert(key_map1.daemons is None) + assert(key_map1.run_cmd == 'test command') + assert(key_map1.hdl_func == cmd_hdlr) + assert(key_map1.data is None) + key_map2 = BGPKeyMapInfo('[bgpd,ospfd]daemon command', None, 100) + assert(key_map2.daemons == ['bgpd', 'ospfd']) + assert(key_map2.run_cmd == 'daemon command') + assert(key_map2.hdl_func == get_command_cmn) + assert(key_map2.data == 100) + +def get_cmd_map_list(attr_list, map_key = None): + map_list = [] + for attr in attr_list: + tokens = attr[0].split('|', 1) + if len(tokens) == 2: + key = tokens[1] + else: + key = None + if map_key is not None and key is not None and map_key != key: + continue + cmd_hdlr = cmd_data = None + if len(attr) >= 4: + cmd_hdlr = attr[2] + cmd_data = attr[3] + elif len(attr) == 3: + cmd_data = attr[2] + map_list.append(BGPKeyMapInfo(attr[1], cmd_hdlr, cmd_data)) + return map_list + +def test_command_map_list(): + def cmd_hdlr(num): + pass + map_list = [('abc', 'set attribute abc'), + ('defg', 'system config', cmd_hdlr, 10), + ('test', 'system test', [20, 30]), + ('xyz', 'config test'), + ('ip_cmd|ipv4', 'test on ipv4'), + ('ip_cmd|ipv6', 'test on ipv6')] + cmd_map_list = BGPKeyMapList(map_list, 'frrcfg', {'ip_cmd': 'ipv4'}) + chk_map_list = get_cmd_map_list(map_list, 'ipv4') + for idx, cmd_map in enumerate(cmd_map_list): + assert(chk_map_list[idx] == cmd_map[1]) + cmd_map_list = BGPKeyMapList(map_list, 'frrcfg', {'ip_cmd': 'ipv6'}) + chk_map_list = get_cmd_map_list(map_list, 'ipv6') + for idx, cmd_map in enumerate(cmd_map_list): + assert(chk_map_list[idx] == cmd_map[1]) + +def test_community_list(): + for ext in [False, True]: + comm_list = CommunityList('comm', ext) + assert(comm_list.name == 'comm') + assert(comm_list.is_ext == ext) + assert(comm_list.match_action is None) + assert(comm_list.is_std is None) + assert(len(comm_list.mbr_list) == 0) + +def test_match_prefix(): + pfx = MatchPrefix(socket.AF_INET, '1.2.3.4/16') + assert(pfx.ip_prefix == '1.2.0.0/16') + assert(pfx.min_len is None) + assert(pfx.max_len is None) + assert(pfx.action == 'permit') + pfx = MatchPrefix(socket.AF_INET, '10.10.10.10/24', '25..29', 'deny') + assert(pfx.ip_prefix == '10.10.10.0/24') + assert(pfx.min_len == 25) + assert(pfx.max_len == 29) + assert(pfx.action == 'deny') + pfx = MatchPrefix(socket.AF_INET, '100.0.0.0/8', '16..32') + assert(pfx.ip_prefix == '100.0.0.0/8') + assert(pfx.min_len == 16) + assert(pfx.max_len is None) + assert(pfx.action == 'permit') + pfx = MatchPrefix(socket.AF_INET, '20.20.20.20/28', '25..30', 'deny') + assert(pfx.ip_prefix == '20.20.20.16/28') + assert(pfx.min_len is None) + assert(pfx.max_len == 30) + assert(pfx.action == 'deny') + + pfx = MatchPrefix(socket.AF_INET6, '1:2::3:4/64') + assert(pfx.ip_prefix == '1:2::/64') + assert(pfx.min_len is None) + assert(pfx.max_len is None) + assert(pfx.action == 'permit') + pfx = MatchPrefix(socket.AF_INET6, '10:10::10:10/64', '70..100', 'deny') + assert(pfx.ip_prefix == '10:10::/64') + assert(pfx.min_len == 70) + assert(pfx.max_len == 100) + assert(pfx.action == 'deny') + pfx = MatchPrefix(socket.AF_INET6, '1001::/16', '16..128') + assert(pfx.ip_prefix == '1001::/16') + assert(pfx.min_len is None) + assert(pfx.max_len == 128) + assert(pfx.action == 'permit') + +def test_match_prefix_list(): + ipv4_pfx_attrs = [('10.1.1.1/16', '18..24', 'permit'), + ('20.2.2.2/24', None, 'deny'), + ('30.3.3.3/8', '10..32', 'permit'), + ('40.4.4.4/28', '20..30', 'deny')] + ipv6_pfx_attrs = [('1000:1::1/64', '80..120', 'permit'), + ('2000:2::2/96', None, 'deny'), + ('3000:3::3/32', '40..128', 'permit'), + ('4000:4::4/80', '60..100', 'deny')] + + pfx_list = MatchPrefixList() + for attr in ipv4_pfx_attrs: + pfx_list.add_prefix(*attr) + assert(pfx_list.af == socket.AF_INET) + assert(len(pfx_list) == len(ipv4_pfx_attrs)) + chk_pfx_list = [] + for attr in ipv4_pfx_attrs: + chk_pfx_list.append(MatchPrefix(socket.AF_INET, *attr)) + assert(all([x == y for x, y in zip(chk_pfx_list, pfx_list)])) + + pfx_list = MatchPrefixList() + for attr in ipv6_pfx_attrs: + pfx_list.add_prefix(*attr) + assert(pfx_list.af == socket.AF_INET6) + assert(len(pfx_list) == len(ipv6_pfx_attrs)) + chk_pfx_list = [] + for attr in ipv6_pfx_attrs: + chk_pfx_list.append(MatchPrefix(socket.AF_INET6, *attr)) + assert(all([x == y for x, y in zip(chk_pfx_list, pfx_list)])) + +def test_match_prefix_list_fail(): + pfx_list = MatchPrefixList() + pfx_list.add_prefix('1.2.3.0/24') + with pytest.raises(ValueError): + pfx_list.add_prefix('1::/64') + +def test_aggregate_address(): + addr = AggregateAddr() + assert(addr.as_set == False) + assert(addr.summary_only == False) + +def test_ip_nexthop(): + for af in [socket.AF_INET, socket.AF_INET6]: + nh = IpNextHop(af, None, None, None, 'Loopback0', None, None, None) + assert(nh.af == af) + assert(nh.blackhole == 'false') + assert(nh.ip == ('0.0.0.0' if af == socket.AF_INET else '::')) + assert(nh.track == 0) + assert(nh.interface == 'Loopback0') + assert(nh.tag == 0) + assert(nh.distance == 0) + assert(nh.nh_vrf == '') + arg_list = nh.get_arg_list() + assert(arg_list == ['false', '', 'Loopback0'] + [''] * 4) + nh = IpNextHop(af, 'true', '1.1.1.1' if af == socket.AF_INET else '1::1', + 1, 'Ethernet0', 100, 2, 'default') + assert(nh.blackhole == 'true') + assert(nh.ip == ('0.0.0.0' if af == socket.AF_INET else '::')) + assert(nh.track == 1) + assert(nh.interface == '') + assert(nh.tag == 100) + assert(nh.distance == 2) + assert(nh.nh_vrf == '') + arg_list = nh.get_arg_list() + assert(arg_list == ['true', '', '', '1', '100', '2', '']) + nh = IpNextHop(socket.AF_INET, 'false', '1.2.3.4', 5, 'Ethernet1', 2345, 3, 'Vrf_red') + assert(nh.af == socket.AF_INET) + assert(nh.blackhole == 'false') + assert(nh.ip == '1.2.3.4') + assert(nh.track == 5) + assert(nh.interface == 'Ethernet1') + assert(nh.tag == 2345) + assert(nh.distance == 3) + assert(nh.nh_vrf == 'Vrf_red') + arg_list = nh.get_arg_list() + assert(arg_list == ['false', '1.2.3.4', 'Ethernet1', '5', '2345', '3', 'Vrf_red']) + nh = IpNextHop(socket.AF_INET6, 'false', '1001:1::2002', 6, 'Ethernet2', 9000, 4, 'Vrf_blue') + assert(nh.af == socket.AF_INET6) + assert(nh.blackhole == 'false') + assert(nh.ip == '1001:1::2002') + assert(nh.track == 6) + assert(nh.interface == 'Ethernet2') + assert(nh.tag == 9000) + assert(nh.distance == 4) + assert(nh.nh_vrf == 'Vrf_blue') + arg_list = nh.get_arg_list() + assert(arg_list == ['false', '1001:1::2002', 'Ethernet2', '6', '9000', '4', 'Vrf_blue']) + +def test_nexthop_set(): + for af in [socket.AF_INET, socket.AF_INET6]: + nh_set = IpNextHopSet(af) + bkh_list = ['false', 'false', 'false', 'true'] + ip_list = ['1.1.1.1', '2.2.2.2', '3.3.3.3', None] + ip6_list = ['1::1', '2::2', '3::3', None] + intf_list = [None, 'Vlan0', 'Loopback1', None] + tag_list = [1000, 2000, 3000, 4000] + vrf_list = ['default', 'Vrf_red', 'Vrf_blue', None] + nh_set = IpNextHopSet(af, bkh_list, ip_list if af == socket.AF_INET else ip6_list, None, + intf_list, tag_list, None, vrf_list) + test_set = set() + for idx in range(len(ip_list)): + test_set.add(IpNextHop(af, bkh_list[idx], ip_list[idx] if af == socket.AF_INET else ip6_list[idx], + None, intf_list[idx], tag_list[idx], None, vrf_list[idx])) + assert(nh_set == test_set) From ecd1e2e852dc9f0ebc123f09023d31b5966242a3 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Tue, 5 Jan 2021 04:17:38 +0000 Subject: [PATCH 13/24] Changed according to code review comment --- dockers/docker-fpm-frr/docker_init.sh | 2 +- .../frr/supervisord/supervisord.conf.j2 | 45 ++++++ src/sonic-frr-mgmt-framework/setup.py | 6 +- .../templates/bgpd/bgpd.conf.j2 | 4 - .../templates/supervisord/supervisord.conf.j2 | 148 ------------------ 5 files changed, 48 insertions(+), 157 deletions(-) delete mode 100644 src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 124f07f3406d..9dc7842c3a3a 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -10,7 +10,7 @@ if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; th -d \ -y /etc/sonic/constants.yml \ -t /usr/share/sonic/templates/frr_vars.j2 \ - -t /usr/local/frr/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ + -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ -t /usr/local/frr/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ -t /usr/local/frr/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ diff --git a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 index 205b57e5f616..1f50f1b09af7 100644 --- a/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 +++ b/dockers/docker-fpm-frr/frr/supervisord/supervisord.conf.j2 @@ -50,6 +50,20 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=zebra:running +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +[program:bfdd] +command=/usr/lib/frr/bfdd -A 127.0.0.1 +priority=4 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running +{% endif %} + [program:bgpd] command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp priority=5 @@ -62,6 +76,32 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=zebra:running +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +[program:ospfd] +command=/usr/lib/frr/ospfd -A 127.0.0.1 -M snmp +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running + +[program:pimd] +command=/usr/lib/frr/pimd -A 127.0.0.1 +priority=5 +stopsignal=KILL +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=zebra:running +{% endif %} + [program:fpmsyncd] command=fpmsyncd priority=6 @@ -73,8 +113,13 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=bgpd:running +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +[program:frrcfgd] +command=/usr/local/bin/frrcfgd +{% else %} [program:bgpcfgd] command=/usr/local/bin/bgpcfgd +{% endif %} priority=6 autostart=false autorestart=false diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index 9b8bfac675f1..956cf90f5fef 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -3,7 +3,7 @@ setuptools.setup( name = 'sonic-frr-mgmt-framework', version = '1.0', - description = 'Utility to dynamically configuration FRR based on database update', + description = 'Utility to dynamically configuration FRR based on config DB data update event', url = 'https://github.com/Azure/sonic-buildimage', packages = setuptools.find_packages(), entry_points = { @@ -28,7 +28,6 @@ ], data_files = [('frr/common', ['templates/common/daemons.common.conf.j2']), ('frr/bgpd', ['templates/bgpd/bgpd.conf.db.j2', - 'templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2', 'templates/bgpd/bgpd.conf.j2', 'templates/bgpd/bgpd.conf.db.route_map.j2', 'templates/bgpd/bgpd.conf.db.pref_list.j2', @@ -48,7 +47,6 @@ ('frr/staticd', ['templates/staticd/staticd.conf.j2', 'templates/staticd/staticd.db.conf.j2', 'templates/staticd/staticd.default_route.conf.j2']), - ('frr/supervisord', ['templates/supervisord/supervisord.conf.j2', - 'templates/supervisord/critical_processes']) + ('frr/supervisord', ['templates/supervisord/critical_processes']) ] ) diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 index 006108dbf78a..92e4abd7375c 100644 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 @@ -12,10 +12,6 @@ ! agentx ! -{% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} -{% include "bgpd.spine_chassis_frontend_router.conf.j2" %} -{% endif %} -! {% include "bgpd.conf.db.j2" %} ! ! end of template: bgpd/bgpd.conf.j2 diff --git a/src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 b/src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 deleted file mode 100644 index c8bff2e27356..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/supervisord/supervisord.conf.j2 +++ /dev/null @@ -1,148 +0,0 @@ -[supervisord] -logfile_maxbytes=1MB -logfile_backups=2 -nodaemon=true - -[eventlistener:dependent-startup] -command=python3 -m supervisord_dependent_startup -autostart=true -autorestart=unexpected -startretries=0 -exitcodes=0,3 -events=PROCESS_STATE -buffer_size=50 - -[eventlistener:supervisor-proc-exit-listener] -command=/usr/bin/supervisor-proc-exit-listener --container-name bgp -events=PROCESS_STATE_EXITED -autostart=true -autorestart=unexpected - -[program:rsyslogd] -command=/usr/sbin/rsyslogd -n -iNONE -priority=1 -autostart=false -autorestart=unexpected -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true - -[program:zebra] -command=/usr/lib/frr/zebra -A 127.0.0.1 -s 90000000 -M fpm -M snmp -priority=4 -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=rsyslogd:running - -[program:staticd] -command=/usr/lib/frr/staticd -A 127.0.0.1 -priority=4 -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - -[program:bfdd] -command=/usr/lib/frr/bfdd -A 127.0.0.1 -priority=4 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - -[program:bgpd] -command=/usr/lib/frr/bgpd -A 127.0.0.1 -M snmp -priority=5 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - -[program:ospfd] -command=/usr/lib/frr/ospfd -A 127.0.0.1 -M snmp -priority=5 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - -[program:pimd] -command=/usr/lib/frr/pimd -A 127.0.0.1 -priority=5 -stopsignal=KILL -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=zebra:running - -[program:fpmsyncd] -command=fpmsyncd -priority=6 -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=bgpd:running - -[program:frrcfgd] -command=/usr/local/bin/frrcfgd -priority=6 -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=bgpd:running - -{% if DEVICE_METADATA.localhost.docker_routing_config_mode is defined and DEVICE_METADATA.localhost.docker_routing_config_mode == "unified" %} -[program:vtysh_b] -command=/usr/bin/vtysh -b -priority=6 -autostart=false -autorestart=false -startsecs=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=bgpd:running -{% endif %} - -{% if WARM_RESTART is defined and WARM_RESTART.bgp is defined and WARM_RESTART.bgp.bgp_eoiu is defined and WARM_RESTART.bgp.bgp_eoiu == "true" %} -[program:bgp_eoiu_marker] -command=/usr/bin/bgp_eoiu_marker.py -priority=7 -autostart=false -autorestart=false -startsecs=0 -startretries=0 -stdout_logfile=syslog -stderr_logfile=syslog -dependent_startup=true -dependent_startup_wait_for=bgpd:running -{% endif %} From 30b68c929e7e6123b226fe7b20b4d20f249bd76e Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Thu, 7 Jan 2021 21:41:29 +0000 Subject: [PATCH 14/24] Added jinja template to generate critical_processes list based on device_metadata flag --- dockers/docker-fpm-frr/Dockerfile.j2 | 1 - dockers/docker-fpm-frr/critical_processes | 5 --- dockers/docker-fpm-frr/docker_init.sh | 33 +++++-------------- .../frr/supervisord/critical_processes.j2 | 12 +++++++ src/sonic-frr-mgmt-framework/setup.py | 3 +- .../templates/supervisord/critical_processes | 8 ----- 6 files changed, 22 insertions(+), 40 deletions(-) delete mode 100644 dockers/docker-fpm-frr/critical_processes create mode 100644 dockers/docker-fpm-frr/frr/supervisord/critical_processes.j2 delete mode 100644 src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes diff --git a/dockers/docker-fpm-frr/Dockerfile.j2 b/dockers/docker-fpm-frr/Dockerfile.j2 index ab8b585899f9..f271673a99cd 100644 --- a/dockers/docker-fpm-frr/Dockerfile.j2 +++ b/dockers/docker-fpm-frr/Dockerfile.j2 @@ -54,7 +54,6 @@ COPY ["TSA", "/usr/bin/TSA"] COPY ["TSB", "/usr/bin/TSB"] COPY ["TSC", "/usr/bin/TSC"] COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] -COPY ["critical_processes", "/etc/supervisor"] RUN chmod a+x /usr/bin/TSA && \ chmod a+x /usr/bin/TSB && \ chmod a+x /usr/bin/TSC diff --git a/dockers/docker-fpm-frr/critical_processes b/dockers/docker-fpm-frr/critical_processes deleted file mode 100644 index 2631fee15e66..000000000000 --- a/dockers/docker-fpm-frr/critical_processes +++ /dev/null @@ -1,5 +0,0 @@ -program:zebra -program:staticd -program:bgpd -program:fpmsyncd -program:bgpcfgd diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 9dc7842c3a3a..46b84cfd4bed 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -4,44 +4,29 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d MGMT_FRAMEWORK_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]'` -CRIT_PROC_BACKUP="/usr/local/frr/supervisord/critical_processes.bak" -if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then CFGGEN_PARAMS=" \ -d \ -y /etc/sonic/constants.yml \ -t /usr/share/sonic/templates/frr_vars.j2 \ -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ - -t /usr/local/frr/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ + -t /usr/share/sonic/templates/supervisord/critical_processes.j2,/etc/supervisor/critical_processes \ -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ - -t /usr/local/frr/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ +" +if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then + CFGGEN_PARAMS+=" \ + -t /usr/local/frr/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ + -t /usr/local/frr/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ -t /usr/local/frr/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ -t /usr/local/frr/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ " - if [ ! -f $CRIT_PROC_BACKUP ]; then - mv /etc/supervisor/critical_processes $CRIT_PROC_BACKUP - fi - # change critical process list with those of enterprise release - cp /usr/local/frr/supervisord/critical_processes /etc/supervisor else - CFGGEN_PARAMS=" \ - -d \ - -y /etc/sonic/constants.yml \ - -t /usr/share/sonic/templates/supervisord/frr_vars.j2 \ - -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ + CFGGEN_PARAMS+=" \ -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ - -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ -t /usr/share/sonic/templates/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ - -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ - -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ - -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ " - if [ -f $CRIT_PROC_BACKUP ]; then - # restore original critical process list for community release - mv -f $CRIT_PROC_BACKUP /etc/supervisor/critical_processes - fi fi CONFIG_TYPE=$(sonic-cfggen $CFGGEN_PARAMS) @@ -80,8 +65,8 @@ if [ -z "$CONFIG_TYPE" ] || [ "$CONFIG_TYPE" == "separated" ]; then rm -f /etc/frr/frr.conf elif [ "$CONFIG_TYPE" == "unified" ]; then echo "service integrated-vtysh-config" > /etc/frr/vtysh.conf - rm -f /etc/frr/bgpd.conf /etc/frr/zebra.conf /etc/frr/staticd.conf - rm -f /etc/frr/bfdd.conf /etc/frr/ospfd.conf /etc/frr/pimd.conf + rm -f /etc/frr/bgpd.conf /etc/frr/zebra.conf /etc/frr/staticd.conf \ + /etc/frr/bfdd.conf /etc/frr/ospfd.conf /etc/frr/pimd.conf fi chown -R frr:frr /etc/frr/ diff --git a/dockers/docker-fpm-frr/frr/supervisord/critical_processes.j2 b/dockers/docker-fpm-frr/frr/supervisord/critical_processes.j2 new file mode 100644 index 000000000000..9a90a5c94eb8 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/supervisord/critical_processes.j2 @@ -0,0 +1,12 @@ +program:zebra +program:staticd +program:bgpd +program:fpmsyncd +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +program:bfdd +program:ospfd +program:pimd +program:frrcfgd +{% else %} +program:bgpcfgd +{% endif %} diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index 956cf90f5fef..1b2c04ff1acd 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -46,7 +46,6 @@ 'templates/ospfd/ospfd.conf.db.vlink.j2']), ('frr/staticd', ['templates/staticd/staticd.conf.j2', 'templates/staticd/staticd.db.conf.j2', - 'templates/staticd/staticd.default_route.conf.j2']), - ('frr/supervisord', ['templates/supervisord/critical_processes']) + 'templates/staticd/staticd.default_route.conf.j2']) ] ) diff --git a/src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes b/src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes deleted file mode 100644 index 1d9e5aa3427e..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/supervisord/critical_processes +++ /dev/null @@ -1,8 +0,0 @@ -program:zebra -program:staticd -program:bfdd -program:bgpd -program:ospfd -program:pimd -program:fpmsyncd -program:frrcfgd From 0160efb4a48d6075b1f28d584ef8bc532a5ccec0 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Thu, 7 Jan 2021 22:03:11 +0000 Subject: [PATCH 15/24] Fixed minor issue of indentation --- dockers/docker-fpm-frr/docker_init.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 46b84cfd4bed..e6a2b83504aa 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -4,16 +4,16 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d MGMT_FRAMEWORK_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]'` - CFGGEN_PARAMS=" \ - -d \ - -y /etc/sonic/constants.yml \ - -t /usr/share/sonic/templates/frr_vars.j2 \ - -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ - -t /usr/share/sonic/templates/supervisord/critical_processes.j2,/etc/supervisor/critical_processes \ - -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ - -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ - -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ - -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ +CFGGEN_PARAMS=" \ + -d \ + -y /etc/sonic/constants.yml \ + -t /usr/share/sonic/templates/frr_vars.j2 \ + -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ + -t /usr/share/sonic/templates/supervisord/critical_processes.j2,/etc/supervisor/critical_processes \ + -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ + -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ + -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ + -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ " if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then CFGGEN_PARAMS+=" \ From 73354aaf7562f3d580918c84f3ae023c5ff258f0 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Fri, 8 Jan 2021 03:03:30 +0000 Subject: [PATCH 16/24] Added UT cases to test FRR command mapping --- .../tests/test_config.py | 176 +++++++++++++++++- .../tests/test_constructor.py | 28 +-- 2 files changed, 191 insertions(+), 13 deletions(-) diff --git a/src/sonic-frr-mgmt-framework/tests/test_config.py b/src/sonic-frr-mgmt-framework/tests/test_config.py index d2987ad1f000..ed31c1e28ec8 100644 --- a/src/sonic-frr-mgmt-framework/tests/test_config.py +++ b/src/sonic-frr-mgmt-framework/tests/test_config.py @@ -1,2 +1,176 @@ +import copy +import re +from unittest.mock import MagicMock, NonCallableMagicMock, patch + +swsssdk_module_mock = MagicMock(ConfigDBConnector = NonCallableMagicMock) + +@patch.dict('sys.modules', swsssdk = swsssdk_module_mock) def test_contructor(): - assert(True) + from frrcfgd.frrcfgd import BGPConfigDaemon + daemon = BGPConfigDaemon() + daemon.start() + for table, hdlr in daemon.table_handler_list: + daemon.config_db.subscribe.assert_any_call(table, hdlr) + daemon.config_db.pubsub.psubscribe.assert_called_once() + daemon.stop() + daemon.config_db.sub_thread.stop.assert_called() + daemon.config_db.sub_thread.is_alive.assert_called_once() + daemon.config_db.sub_thread.join.assert_called_once() + +class CmdMapTestInfo: + data_buf = {} + def __init__(self, table, key, data, exp_cmd, no_del = False, neg_cmd = None, + chk_data = None, daemons = None, ignore_tail = False): + self.table_name = table + self.key = key + self.data = data + self.vtysh_cmd = exp_cmd + self.no_del = no_del + self.vtysh_neg_cmd = neg_cmd + self.chk_data = chk_data + self.daemons = daemons + self.ignore_tail = ignore_tail + @classmethod + def add_test_data(cls, test): + assert(isinstance(test.data, dict)) + cls.data_buf.setdefault( + test.table_name, {}).setdefault(test.key, {}).update(test.data) + @classmethod + def del_test_data(cls, test): + assert(test.table_name in cls.data_buf and + test.key in cls.data_buf[test.table_name]) + cache_data = cls.data_buf[test.table_name][test.key] + assert(isinstance(test.data, dict)) + for k, v in test.data.items(): + assert(k in cache_data and cache_data[k] == v) + del(cache_data[k]) + @classmethod + def get_test_data(cls, test): + assert(test.table_name in cls.data_buf and + test.key in cls.data_buf[test.table_name]) + return copy.deepcopy(cls.data_buf[test.table_name][test.key]) + @staticmethod + def compose_vtysh_cmd(cmd_list, negtive = False): + cmdline = 'vtysh' + for cmd in cmd_list: + cmd = cmd.format('no ' if negtive else '') + cmdline += " -c '%s'" % cmd + return cmdline + def check_running_cmd(self, mock, is_del): + if is_del: + vtysh_cmd = self.vtysh_cmd if self.vtysh_neg_cmd is None else self.vtysh_neg_cmd + else: + vtysh_cmd = self.vtysh_cmd + if callable(vtysh_cmd): + cmds = [] + for call in mock.call_args_list: + assert(call[0][0] == self.table_name) + cmds.append(call[0][1]) + vtysh_cmd(is_del, cmds, self.chk_data) + else: + if self.ignore_tail is None: + mock.assert_called_with(self.table_name, self.compose_vtysh_cmd(vtysh_cmd, is_del), + True, self.daemons) + else: + mock.assert_called_with(self.table_name, self.compose_vtysh_cmd(vtysh_cmd, is_del), + True, self.daemons, self.ignore_tail) + +def hdl_confed_peers_cmd(is_del, cmd_list, chk_data): + assert(len(chk_data) >= len(cmd_list)) + if is_del: + chk_data = list(reversed(chk_data)) + for idx, cmd in enumerate(cmd_list): + last_cmd = re.findall(r"-c\s+'([^']+)'\s*", cmd)[-1] + neg_cmd = False + if last_cmd.startswith('no '): + neg_cmd = True + last_cmd = last_cmd[len('no '):] + assert(last_cmd.startswith('bgp confederation peers ')) + peer_set = set(last_cmd[len('bgp confederation peers '):].split()) + if is_del or (len(chk_data) >= 3 and idx == 0): + assert(neg_cmd) + else: + assert(not neg_cmd) + assert(peer_set == chk_data[idx]) + +conf_cmd = 'configure terminal' +conf_bgp_cmd = lambda vrf, asn: [conf_cmd, 'router bgp %d vrf %s' % (asn, vrf)] +conf_no_bgp_cmd = lambda vrf, asn: [conf_cmd, 'no router bgp %d%s' % (asn, '' if vrf == 'default' else ' vrf %s' % vrf)] +conf_bgp_dft_cmd = lambda vrf, asn: conf_bgp_cmd(vrf, asn) + ['no bgp default ipv4-unicast'] +conf_bgp_af_cmd = lambda vrf, asn, af: conf_bgp_cmd(vrf, asn) + ['address-family %s unicast' % af] + +bgp_globals_data = [ + CmdMapTestInfo('BGP_GLOBALS', 'default', {'local_asn': 100}, + conf_bgp_dft_cmd('default', 100), False, conf_no_bgp_cmd('default', 100), None, None, None), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'router_id': '1.1.1.1'}, + conf_bgp_cmd('default', 100) + ['{}bgp router-id 1.1.1.1']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'load_balance_mp_relax': 'true'}, + conf_bgp_cmd('default', 100) + ['{}bgp bestpath as-path multipath-relax ']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'as_path_mp_as_set': 'true'}, + conf_bgp_cmd('default', 100) + ['bgp bestpath as-path multipath-relax as-set'], False, + conf_bgp_cmd('default', 100) + ['bgp bestpath as-path multipath-relax ']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'always_compare_med': 'false'}, + conf_bgp_cmd('default', 100) + ['no bgp always-compare-med']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'external_compare_router_id': 'true'}, + conf_bgp_cmd('default', 100) + ['{}bgp bestpath compare-routerid']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'ignore_as_path_length': 'true'}, + conf_bgp_cmd('default', 100) + ['{}bgp bestpath as-path ignore']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'graceful_restart_enable': 'true'}, + conf_bgp_cmd('default', 100) + ['{}bgp graceful-restart']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'gr_restart_time': '10'}, + conf_bgp_cmd('default', 100) + ['{}bgp graceful-restart restart-time 10']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'gr_stale_routes_time': '20'}, + conf_bgp_cmd('default', 100) + ['{}bgp graceful-restart stalepath-time 20']), + CmdMapTestInfo('BGP_GLOBALS', 'default', {'gr_preserve_fw_state': 'true'}, + conf_bgp_cmd('default', 100) + ['{}bgp graceful-restart preserve-fw-state']), + CmdMapTestInfo('BGP_GLOBALS_AF', 'default|ipv4_unicast', {'ebgp_route_distance': '100', + 'ibgp_route_distance': '115', + 'local_route_distance': '238'}, + conf_bgp_af_cmd('default', 100, 'ipv4') + ['{}distance bgp 100 115 238']), + CmdMapTestInfo('BGP_GLOBALS_AF', 'default|ipv6_unicast', {'advertise-all-vni': 'true'}, + conf_bgp_af_cmd('default', 100, 'ipv6') + ['{}advertise-all-vni']), + CmdMapTestInfo('BGP_GLOBALS', 'Vrf_red', {'local_asn': 200}, + conf_bgp_dft_cmd('Vrf_red', 200), False, conf_no_bgp_cmd('Vrf_red', 200), None, None, None), + CmdMapTestInfo('BGP_GLOBALS', 'Vrf_red', {'med_confed': 'true'}, + conf_bgp_cmd('Vrf_red', 200) + ['{}bgp bestpath med confed']), + CmdMapTestInfo('BGP_GLOBALS', 'Vrf_red', {'confed_peers': ['2', '10', '5']}, + hdl_confed_peers_cmd, True, None, [{'2', '10', '5'}]), + CmdMapTestInfo('BGP_GLOBALS', 'Vrf_red', {'confed_peers': ['10', '8']}, + hdl_confed_peers_cmd, False, None, [{'2', '5'}, {'8'}, {'10', '8'}]), + CmdMapTestInfo('BGP_GLOBALS', 'Vrf_red', {'keepalive': '300', 'holdtime': '900'}, + conf_bgp_cmd('Vrf_red', 200) + ['{}timers bgp 300 900']), + CmdMapTestInfo('BGP_GLOBALS', 'Vrf_red', {'max_med_admin': 'true', 'max_med_admin_val': '20'}, + conf_bgp_cmd('Vrf_red', 200) + ['{}bgp max-med administrative 20']), + CmdMapTestInfo('BGP_GLOBALS_AF', 'Vrf_red|ipv4_unicast', {'import_vrf': 'Vrf_test'}, + conf_bgp_af_cmd('Vrf_red', 200, 'ipv4') + ['{}import vrf Vrf_test']), + CmdMapTestInfo('BGP_GLOBALS_AF', 'Vrf_red|ipv6_unicast', {'import_vrf_route_map': 'test_map'}, + conf_bgp_af_cmd('Vrf_red', 200, 'ipv6') + ['{}import vrf route-map test_map']), +] + +@patch.dict('sys.modules', swsssdk = swsssdk_module_mock) +@patch('frrcfgd.frrcfgd.g_run_command') +def data_set_del_test(test_data, run_cmd): + from frrcfgd.frrcfgd import BGPConfigDaemon + daemon = BGPConfigDaemon() + data_buf = {} + # add data in list + for test in test_data: + run_cmd.reset_mock() + hdlr = [h for t, h in daemon.table_handler_list if t == test.table_name] + assert(len(hdlr) == 1) + CmdMapTestInfo.add_test_data(test) + hdlr[0](test.table_name, test.key, CmdMapTestInfo.get_test_data(test)) + test.check_running_cmd(run_cmd, False) + # delete data in reverse direction + for test in reversed(test_data): + if test.no_del: + continue + run_cmd.reset_mock() + hdlr = [h for t, h in daemon.table_handler_list if t == test.table_name] + assert(len(hdlr) == 1) + CmdMapTestInfo.del_test_data(test) + hdlr[0](test.table_name, test.key, CmdMapTestInfo.get_test_data(test)) + test.check_running_cmd(run_cmd, True) + +def test_bgp_globals(): + data_set_del_test(bgp_globals_data) diff --git a/src/sonic-frr-mgmt-framework/tests/test_constructor.py b/src/sonic-frr-mgmt-framework/tests/test_constructor.py index 55615544d6be..14faa36d2e66 100644 --- a/src/sonic-frr-mgmt-framework/tests/test_constructor.py +++ b/src/sonic-frr-mgmt-framework/tests/test_constructor.py @@ -1,17 +1,21 @@ import socket import pytest - -from frrcfgd.frrcfgd import CachedDataWithOp -from frrcfgd.frrcfgd import BGPPeerGroup -from frrcfgd.frrcfgd import BGPKeyMapInfo -from frrcfgd.frrcfgd import BGPKeyMapList -from frrcfgd.frrcfgd import get_command_cmn -from frrcfgd.frrcfgd import CommunityList -from frrcfgd.frrcfgd import MatchPrefix -from frrcfgd.frrcfgd import MatchPrefixList -from frrcfgd.frrcfgd import AggregateAddr -from frrcfgd.frrcfgd import IpNextHop -from frrcfgd.frrcfgd import IpNextHopSet +from unittest.mock import MagicMock, NonCallableMagicMock, patch + +swsssdk_module_mock = MagicMock(ConfigDBConnector = NonCallableMagicMock) + +with patch.dict('sys.modules', swsssdk = swsssdk_module_mock): + from frrcfgd.frrcfgd import CachedDataWithOp + from frrcfgd.frrcfgd import BGPPeerGroup + from frrcfgd.frrcfgd import BGPKeyMapInfo + from frrcfgd.frrcfgd import BGPKeyMapList + from frrcfgd.frrcfgd import get_command_cmn + from frrcfgd.frrcfgd import CommunityList + from frrcfgd.frrcfgd import MatchPrefix + from frrcfgd.frrcfgd import MatchPrefixList + from frrcfgd.frrcfgd import AggregateAddr + from frrcfgd.frrcfgd import IpNextHop + from frrcfgd.frrcfgd import IpNextHopSet def test_data_with_op(): data = CachedDataWithOp() From 3abb609524551de5da55166cac673f8d2f5ad8e3 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Fri, 8 Jan 2021 23:10:53 +0000 Subject: [PATCH 17/24] Used new bash command substitution format to replace outdated one --- dockers/docker-fpm-frr/docker_init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index e6a2b83504aa..31da0df016b6 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -3,7 +3,7 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d -MGMT_FRAMEWORK_CONFIG=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]'` +MGMT_FRAMEWORK_CONFIG=$(sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]') CFGGEN_PARAMS=" \ -d \ -y /etc/sonic/constants.yml \ From cf341e9df5487a563123b08281817c75245e25de Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Wed, 13 Jan 2021 02:12:32 +0000 Subject: [PATCH 18/24] Changed to avoid calling sonic-cfggen twice --- dockers/docker-fpm-frr/docker_init.sh | 24 +++---- dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 | 4 ++ dockers/docker-fpm-frr/frr/frr_vars.j2 | 15 ++++- .../frr/staticd/staticd.conf.j2 | 12 ++++ src/sonic-frr-mgmt-framework/setup.py | 28 ++++----- .../templates/bgpd/bgpd.conf.j2 | 18 ------ ...bgpd.spine_chassis_frontend_router.conf.j2 | 63 ------------------- .../templates/common/daemons.common.conf.j2 | 14 ----- .../templates/staticd/staticd.conf.j2 | 20 ------ .../staticd/staticd.default_route.conf.j2 | 10 --- 10 files changed, 52 insertions(+), 156 deletions(-) delete mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 delete mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 delete mode 100644 src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 delete mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 delete mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 31da0df016b6..1a42a8d801c9 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -3,32 +3,28 @@ mkdir -p /etc/frr mkdir -p /etc/supervisor/conf.d -MGMT_FRAMEWORK_CONFIG=$(sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"]') CFGGEN_PARAMS=" \ -d \ -y /etc/sonic/constants.yml \ -t /usr/share/sonic/templates/frr_vars.j2 \ -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ + -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ -t /usr/share/sonic/templates/supervisord/critical_processes.j2,/etc/supervisor/critical_processes \ -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ + -t /usr/share/sonic/templates/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ + -t /usr/local/sonic/frr/bfdd.conf.j2,/etc/frr/bfdd.conf \ + -t /usr/local/sonic/frr/ospfd.conf.j2,/etc/frr/ospfd.conf \ " -if [ -n "$MGMT_FRAMEWORK_CONFIG" ] && [ "$MGMT_FRAMEWORK_CONFIG" == "true" ]; then - CFGGEN_PARAMS+=" \ - -t /usr/local/frr/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ - -t /usr/local/frr/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ - -t /usr/local/frr/bfdd/bfdd.conf.j2,/etc/frr/bfdd.conf \ - -t /usr/local/frr/ospfd/ospfd.conf.j2,/etc/frr/ospfd.conf \ - " -else - CFGGEN_PARAMS+=" \ - -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ - -t /usr/share/sonic/templates/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ - " + +FRR_VARS=$(sonic-cfggen $CFGGEN_PARAMS) +MGMT_FRAMEWORK_CONFIG=$(echo $FRR_VARS | jq -r '.frr_mgmt_framework_config') +CONFIG_TYPE=$(echo $FRR_VARS | jq -r '.docker_routing_config_mode') +if [ -z "$MGMT_FRAMEWORK_CONFIG" ] || [ "$MGMT_FRAMEWORK_CONFIG" == "false" ]; then + rm /etc/frr/bfdd.conf /etc/frr/ospfd.conf fi -CONFIG_TYPE=$(sonic-cfggen $CFGGEN_PARAMS) update_default_gw() { diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 index 85182e5430e8..6c667da37c44 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 @@ -14,11 +14,15 @@ ! agentx ! +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +{% include "bgpd.conf.db.j2" %} +{% else %} {% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} {% include "bgpd.spine_chassis_frontend_router.conf.j2" %} {% endif %} ! {% include "bgpd.main.conf.j2" %} +{% endif %} ! ! end of template: bgpd/bgpd.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/frr_vars.j2 b/dockers/docker-fpm-frr/frr/frr_vars.j2 index 9909604e5f1c..662608a1fd8b 100644 --- a/dockers/docker-fpm-frr/frr/frr_vars.j2 +++ b/dockers/docker-fpm-frr/frr/frr_vars.j2 @@ -1 +1,14 @@ -{{ DEVICE_METADATA["localhost"]["docker_routing_config_mode"] }} +{ + "frr_mgmt_framework_config": + {% if "frr_mgmt_framework_config" in DEVICE_METADATA["localhost"].keys() %} + "{{ DEVICE_METADATA["localhost"]["frr_mgmt_framework_config"] }}" + {% else %} + "" + {% endif %}, + "docker_routing_config_mode": + {% if "docker_routing_config_mode" in DEVICE_METADATA["localhost"].keys() %} + "{{ DEVICE_METADATA["localhost"]["docker_routing_config_mode"] }}" + {% else %} + "" + {% endif %} +} diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 index 4831325276c7..dab79d99150b 100644 --- a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 @@ -8,7 +8,19 @@ ! {% include "common/daemons.common.conf.j2" %} ! +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +{% if MGMT_VRF_CONFIG %} +{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +{% else %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +! +{% include "staticd.db.conf.j2" %} +{% else %} {% include "staticd.default_route.conf.j2" %} ! {% include "staticd.loopback_route.conf.j2" %} +{% endif %} ! diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index 1b2c04ff1acd..bb02e4e2e521 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -26,26 +26,22 @@ 'pytest-cov', 'sonic-config-engine' ], - data_files = [('frr/common', ['templates/common/daemons.common.conf.j2']), - ('frr/bgpd', ['templates/bgpd/bgpd.conf.db.j2', - 'templates/bgpd/bgpd.conf.j2', - 'templates/bgpd/bgpd.conf.db.route_map.j2', - 'templates/bgpd/bgpd.conf.db.pref_list.j2', - 'templates/bgpd/bgpd.conf.db.nbr_or_peer.j2', - 'templates/bgpd/bgpd.conf.db.nbr_af.j2', - 'templates/bgpd/bgpd.conf.db.comm_list.j2', - 'templates/bgpd/bgpd.conf.db.addr_family.j2', - 'templates/bgpd/bgpd.conf.db.addr_family.evpn.j2']), - ('frr/bfdd', ['templates/bfdd/bfdd.conf.j2']), - ('frr/ospfd', ['templates/ospfd/ospfd.conf.j2', + data_files = [('sonic/frr', ['templates/bgpd/bgpd.conf.db.j2', + 'templates/bgpd/bgpd.conf.db.route_map.j2', + 'templates/bgpd/bgpd.conf.db.pref_list.j2', + 'templates/bgpd/bgpd.conf.db.nbr_or_peer.j2', + 'templates/bgpd/bgpd.conf.db.nbr_af.j2', + 'templates/bgpd/bgpd.conf.db.comm_list.j2', + 'templates/bgpd/bgpd.conf.db.addr_family.j2', + 'templates/bgpd/bgpd.conf.db.addr_family.evpn.j2', + 'templates/bfdd/bfdd.conf.j2', + 'templates/ospfd/ospfd.conf.j2', 'templates/ospfd/ospfd.conf.db.area.j2', 'templates/ospfd/ospfd.conf.db.comm_list.j2', 'templates/ospfd/ospfd.conf.db.distributeroute.j2', 'templates/ospfd/ospfd.conf.db.interface.j2', 'templates/ospfd/ospfd.conf.db.policyrange.j2', - 'templates/ospfd/ospfd.conf.db.vlink.j2']), - ('frr/staticd', ['templates/staticd/staticd.conf.j2', - 'templates/staticd/staticd.db.conf.j2', - 'templates/staticd/staticd.default_route.conf.j2']) + 'templates/ospfd/ospfd.conf.db.vlink.j2', + 'templates/staticd/staticd.db.conf.j2']) ] ) diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 deleted file mode 100644 index 92e4abd7375c..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 +++ /dev/null @@ -1,18 +0,0 @@ -! -! template: bgpd/bgpd.conf.j2 -! -{% block banner %} -! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/quagga/bgpd.conf.j2 with config DB data -! file: bgpd.conf -! -{% endblock banner %} -! -{% include "common/daemons.common.conf.j2" %} -! -agentx -! -{% include "bgpd.conf.db.j2" %} -! -! end of template: bgpd/bgpd.conf.j2 -! diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 deleted file mode 100644 index 94dacbc3af78..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.spine_chassis_frontend_router.conf.j2 +++ /dev/null @@ -1,63 +0,0 @@ -! -{# VNET BGP Instance #} -! Vnet BGP instance -{% set interfaces_in_vnets = [] %} -{% block vnet_bgp_instance %} -{% for vnet_name, vnet_metadata in VNET.items() %} -router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} vrf {{ vnet_name }} - no bgp default ipv4-unicast - bgp log-neighbor-changes - bgp bestpath as-path multipath-relax - no bgp default ipv4-unicast - bgp graceful-restart restart-time 240 - bgp graceful-restart -{# Router ID #} -{% for (name, prefix) in LOOPBACK_INTERFACE | pfx_filter %} -{% if prefix | ipv4 and name == 'Loopback0' %} - bgp router-id {{ prefix | ip }} -{% endif %} -{% endfor %} -{# Got interfaces that belong this vnet #} -{% set interfaces_in_vnet = [] %} -{% for (key, metadata) in INTERFACE.items() %} -{% if "vnet_name" in metadata and metadata["vnet_name"] == vnet_name %} -{% for (name_prefix_pair, metadata) in INTERFACE.items() %} -{% if key == name_prefix_pair[0] %} -{% if interfaces_in_vnet.append( name_prefix_pair[1] | ip ) %} -{% endif %} -{% if interfaces_in_vnets.append( name_prefix_pair[1] | ip ) %} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -{% endfor %} -{# Each bgp neighbors #} -{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.items() %} -{% if "local_addr" in bgp_session and bgp_session["local_addr"] in interfaces_in_vnet %} -{% if bgp_session['asn'] | int != 0 %} - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{# set the bgp neighbor timers if they have not default values #} -{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60) - or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %} - neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} -{% endif %} -{% if 'admin_status' in bgp_session and bgp_session['admin_status'] == 'down' or 'admin_status' not in bgp_session and 'default_bgp_status' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %} - neighbor {{ neighbor_addr }} shutdown -{% endif %} -{% if neighbor_addr | ipv4 %} - address-family ipv4 unicast - neighbor {{ neighbor_addr }} activate - neighbor {{ neighbor_addr }} soft-reconfiguration inbound - maximum-paths 64 - exit-address-family -{% endif %} - address-family l2vpn evpn - advertise ipv4 unicast - exit-address-family -{% endif %} -{% endif %} -{% endfor %} -{% endfor %} -{% endblock vnet_bgp_instance %} -! diff --git a/src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 b/src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 deleted file mode 100644 index 1c3efdfa72fb..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/common/daemons.common.conf.j2 +++ /dev/null @@ -1,14 +0,0 @@ -! template: common/daemons.common.conf.j2 -! -{% block sys_init %} -hostname {{ DEVICE_METADATA['localhost']['hostname'] }} -password zebra -enable password zebra -{% endblock sys_init %} -! -{% block logging %} -log syslog informational -log facility local4 -{% endblock logging %} -! -! end of template: common/daemons.common.conf.j2 diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 deleted file mode 100644 index fea2be47be8f..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 +++ /dev/null @@ -1,20 +0,0 @@ -! -{% block banner %} -! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/frr/staticd.conf.j2 using config DB data -! file: staticd.conf -! -{% endblock banner %} -! -{% include "common/daemons.common.conf.j2" %} -! -{% if MGMT_VRF_CONFIG %} -{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -{% else %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -! -{% include "staticd.db.conf.j2" %} -! diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 deleted file mode 100644 index 22d61ebbd0ff..000000000000 --- a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.default_route.conf.j2 +++ /dev/null @@ -1,10 +0,0 @@ -! -{% block default_route %} -! set static default route to mgmt gateway as a backup to learned default -{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} -{% if prefix | ipv4 %} -ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 -{% endif %} -{% endfor %} -{% endblock default_route %} -! From da9a9a12531113ac6d1e59c8cd6ff4d0b8e001ad Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Wed, 13 Jan 2021 07:44:13 +0000 Subject: [PATCH 19/24] Added frr.conf generation with frr_mgmt_framework_config set to support FRR unified mode --- dockers/docker-fpm-frr/frr/frr.conf.j2 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dockers/docker-fpm-frr/frr/frr.conf.j2 b/dockers/docker-fpm-frr/frr/frr.conf.j2 index 99900790366c..be8169a11636 100644 --- a/dockers/docker-fpm-frr/frr/frr.conf.j2 +++ b/dockers/docker-fpm-frr/frr/frr.conf.j2 @@ -13,9 +13,27 @@ agentx ! {% include "zebra/zebra.interfaces.conf.j2" %} ! +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} +{% if MGMT_VRF_CONFIG %} +{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +{% else %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +! +{% include "staticd.db.conf.j2" %} +! +{% include "bgpd.conf.db.j2" %} +! +{% include "ospfd.conf.j2" %} +! +{% include "bfdd.conf.j2" %} +{% else %} {% include "staticd/staticd.default_route.conf.j2" %} ! {% include "staticd/staticd.loopback_route.conf.j2" %} ! {% include "bgpd/bgpd.main.conf.j2" %} +{% endif %} ! From e5874c129148ebf319bf55e54169e578669f019e Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Wed, 13 Jan 2021 19:40:15 +0000 Subject: [PATCH 20/24] Added comment to FRR conf template --- src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 | 4 ++++ src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 | 4 ++++ .../templates/staticd/staticd.db.conf.j2 | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 index 11794bbf2ba9..4b49813e4c93 100644 --- a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.db.j2 @@ -1,3 +1,7 @@ +! template: bgpd/bgpd.conf.db.j2 +! +! BGP configuration using config DB BGP instance tables +! {# ------------------------------------------------------------------------------------ #} {% include "bgpd.conf.db.pref_list.j2" %} {# ------------------------------------------------------------------------------------ #} diff --git a/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 index b31926919ce4..d9ace5972dab 100644 --- a/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 +++ b/src/sonic-frr-mgmt-framework/templates/ospfd/ospfd.conf.j2 @@ -1,2 +1,6 @@ +! template: ospfd/ospfd.conf.j2 +! +! OSPF configuration using config DB OSPF instance tables +! {% include "ospfd.conf.db.comm_list.j2" %} {% include "ospfd.conf.db.interface.j2" %} diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.conf.j2 index 8ac8e42a4733..238f0f1acb61 100644 --- a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.conf.j2 +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.conf.j2 @@ -1,3 +1,7 @@ +! template: staticd/staticd.db.conf.j2 +! +! Static Route configuration using config DB static route table +! {% macro iproute(ip_prefix, nh_blackhole, nh_ip, nh_intf, nh_dist, nh_tag, nh_vrf) %} {%- set ns = namespace(str = None) %} {%- set ip_addr = ip_prefix.split('/')[0] %} From e92997c2a55c94bcb968ec5652377caf106c6c6b Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Thu, 14 Jan 2021 23:54:28 +0000 Subject: [PATCH 21/24] Changed according code review comment --- dockers/docker-fpm-frr/docker_init.sh | 4 ++-- dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 | 4 ---- dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 | 5 +++++ .../docker-fpm-frr/frr/gen_staticd.conf.j2 | 5 +++++ .../frr/staticd/staticd.conf.j2 | 12 ---------- src/sonic-frr-mgmt-framework/setup.py | 4 +++- .../templates/bgpd/bgpd.conf.j2 | 15 +++++++++++++ .../templates/staticd/staticd.conf.j2 | 22 +++++++++++++++++++ 8 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 create mode 100644 dockers/docker-fpm-frr/frr/gen_staticd.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 1a42a8d801c9..416306e8bac7 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -8,10 +8,10 @@ CFGGEN_PARAMS=" \ -y /etc/sonic/constants.yml \ -t /usr/share/sonic/templates/frr_vars.j2 \ -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ - -t /usr/share/sonic/templates/bgpd/bgpd.conf.j2,/etc/frr/bgpd.conf \ + -t /usr/share/sonic/templates/gen_bgpd.conf.j2,/etc/frr/bgpd.conf \ -t /usr/share/sonic/templates/supervisord/critical_processes.j2,/etc/supervisor/critical_processes \ -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ - -t /usr/share/sonic/templates/staticd/staticd.conf.j2,/etc/frr/staticd.conf \ + -t /usr/share/sonic/templates/gen_staticd.conf.j2,/etc/frr/staticd.conf \ -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ diff --git a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 index 6c667da37c44..85182e5430e8 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/bgpd.conf.j2 @@ -14,15 +14,11 @@ ! agentx ! -{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} -{% include "bgpd.conf.db.j2" %} -{% else %} {% if DEVICE_METADATA['localhost']['type'] == "SpineChassisFrontendRouter" %} {% include "bgpd.spine_chassis_frontend_router.conf.j2" %} {% endif %} ! {% include "bgpd.main.conf.j2" %} -{% endif %} ! ! end of template: bgpd/bgpd.conf.j2 ! diff --git a/dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 new file mode 100644 index 000000000000..2b5af9513f37 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 @@ -0,0 +1,5 @@ +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} + {% include "/usr/local/sonic/frr/bgpd.conf.j2" %} +{% else %} + {% include "/usr/share/sonic/templates/bgpd/bgpd.conf.j2" %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/gen_staticd.conf.j2 b/dockers/docker-fpm-frr/frr/gen_staticd.conf.j2 new file mode 100644 index 000000000000..f1d0c5f46290 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/gen_staticd.conf.j2 @@ -0,0 +1,5 @@ +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} + {% include "/usr/local/sonic/frr/staticd.conf.j2" %} +{% else %} + {% include "/usr/share/sonic/templates/staticd/staticd.conf.j2" %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 index dab79d99150b..4831325276c7 100644 --- a/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/staticd.conf.j2 @@ -8,19 +8,7 @@ ! {% include "common/daemons.common.conf.j2" %} ! -{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} -{% if MGMT_VRF_CONFIG %} -{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -{% else %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -! -{% include "staticd.db.conf.j2" %} -{% else %} {% include "staticd.default_route.conf.j2" %} ! {% include "staticd.loopback_route.conf.j2" %} -{% endif %} ! diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index bb02e4e2e521..571862873828 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -26,7 +26,8 @@ 'pytest-cov', 'sonic-config-engine' ], - data_files = [('sonic/frr', ['templates/bgpd/bgpd.conf.db.j2', + data_files = [('sonic/frr', ['templates/bgpd/bgpd.conf.j2', + 'templates/bgpd/bgpd.conf.db.j2', 'templates/bgpd/bgpd.conf.db.route_map.j2', 'templates/bgpd/bgpd.conf.db.pref_list.j2', 'templates/bgpd/bgpd.conf.db.nbr_or_peer.j2', @@ -42,6 +43,7 @@ 'templates/ospfd/ospfd.conf.db.interface.j2', 'templates/ospfd/ospfd.conf.db.policyrange.j2', 'templates/ospfd/ospfd.conf.db.vlink.j2', + 'templates/staticd/staticd.conf.j2', 'templates/staticd/staticd.db.conf.j2']) ] ) diff --git a/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 new file mode 100644 index 000000000000..e37ad2a32056 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/bgpd/bgpd.conf.j2 @@ -0,0 +1,15 @@ +{% block banner %} +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/quagga/bgpd.conf.j2 with config DB data +! file: bgpd.conf +! +{% endblock banner %} +! +{% include "common/daemons.common.conf.j2" %} +! +agentx +! +{% include "bgpd.conf.db.j2" %} +! +! end of template: bgpd/bgpd.conf.j2 +! diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 new file mode 100644 index 000000000000..2f867cd41741 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 @@ -0,0 +1,22 @@ + +{% block banner %} +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/frr/staticd.conf.j2 using config DB data +! file: staticd.conf +! +{% endblock banner %} +! +{% with agentx='false' %} +{% include "daemons.common.conf.j2" %} +{% endwith %} +! +{% if MGMT_VRF_CONFIG %} +{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +{% else %} +{% include "staticd.default_route.conf.j2" %} +{% endif %} +! +{% include "staticd.db.conf.j2" %} +! From 3b49d2316a5d05769d2b36b1a68b1d47bc02d596 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Thu, 14 Jan 2021 16:23:56 -0800 Subject: [PATCH 22/24] Fixed include template file issue --- src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 index 2f867cd41741..a3b638431eeb 100644 --- a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 @@ -7,7 +7,7 @@ {% endblock banner %} ! {% with agentx='false' %} -{% include "daemons.common.conf.j2" %} +{% include "common/daemons.common.conf.j2" %} {% endwith %} ! {% if MGMT_VRF_CONFIG %} From ee973b515e70d2e9224aae2ece92d59abe9e2eb5 Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Fri, 15 Jan 2021 04:40:09 +0000 Subject: [PATCH 23/24] Fixed inlcuded template not found issue --- dockers/docker-fpm-frr/docker_init.sh | 6 ++-- .../frr/{ => bgpd}/gen_bgpd.conf.j2 | 0 dockers/docker-fpm-frr/frr/frr.conf.j2 | 18 ----------- dockers/docker-fpm-frr/frr/gen_frr.conf.j2 | 5 ++++ .../frr/{ => staticd}/gen_staticd.conf.j2 | 0 src/sonic-frr-mgmt-framework/setup.py | 4 ++- .../templates/frr/frr.conf.j2 | 30 +++++++++++++++++++ .../templates/staticd/staticd.conf.j2 | 4 +-- .../staticd/staticd.db.default_route.conf.j2 | 9 ++++++ 9 files changed, 52 insertions(+), 24 deletions(-) rename dockers/docker-fpm-frr/frr/{ => bgpd}/gen_bgpd.conf.j2 (100%) create mode 100644 dockers/docker-fpm-frr/frr/gen_frr.conf.j2 rename dockers/docker-fpm-frr/frr/{ => staticd}/gen_staticd.conf.j2 (100%) create mode 100644 src/sonic-frr-mgmt-framework/templates/frr/frr.conf.j2 create mode 100644 src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.default_route.conf.j2 diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 416306e8bac7..2170ca699283 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -8,11 +8,11 @@ CFGGEN_PARAMS=" \ -y /etc/sonic/constants.yml \ -t /usr/share/sonic/templates/frr_vars.j2 \ -t /usr/share/sonic/templates/supervisord/supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ - -t /usr/share/sonic/templates/gen_bgpd.conf.j2,/etc/frr/bgpd.conf \ + -t /usr/share/sonic/templates/bgpd/gen_bgpd.conf.j2,/etc/frr/bgpd.conf \ -t /usr/share/sonic/templates/supervisord/critical_processes.j2,/etc/supervisor/critical_processes \ -t /usr/share/sonic/templates/zebra/zebra.conf.j2,/etc/frr/zebra.conf \ - -t /usr/share/sonic/templates/gen_staticd.conf.j2,/etc/frr/staticd.conf \ - -t /usr/share/sonic/templates/frr.conf.j2,/etc/frr/frr.conf \ + -t /usr/share/sonic/templates/staticd/gen_staticd.conf.j2,/etc/frr/staticd.conf \ + -t /usr/share/sonic/templates/gen_frr.conf.j2,/etc/frr/frr.conf \ -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ -t /usr/local/sonic/frr/bfdd.conf.j2,/etc/frr/bfdd.conf \ diff --git a/dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/gen_bgpd.conf.j2 rename to dockers/docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 diff --git a/dockers/docker-fpm-frr/frr/frr.conf.j2 b/dockers/docker-fpm-frr/frr/frr.conf.j2 index be8169a11636..99900790366c 100644 --- a/dockers/docker-fpm-frr/frr/frr.conf.j2 +++ b/dockers/docker-fpm-frr/frr/frr.conf.j2 @@ -13,27 +13,9 @@ agentx ! {% include "zebra/zebra.interfaces.conf.j2" %} ! -{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} -{% if MGMT_VRF_CONFIG %} -{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -{% else %} -{% include "staticd.default_route.conf.j2" %} -{% endif %} -! -{% include "staticd.db.conf.j2" %} -! -{% include "bgpd.conf.db.j2" %} -! -{% include "ospfd.conf.j2" %} -! -{% include "bfdd.conf.j2" %} -{% else %} {% include "staticd/staticd.default_route.conf.j2" %} ! {% include "staticd/staticd.loopback_route.conf.j2" %} ! {% include "bgpd/bgpd.main.conf.j2" %} -{% endif %} ! diff --git a/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 b/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 new file mode 100644 index 000000000000..055658f8b515 --- /dev/null +++ b/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 @@ -0,0 +1,5 @@ +{% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} + {% include "/usr/local/sonic/frr/frr.conf.j2" %} +{% else %} + {% include "/usr/share/sonic/templates/frr.conf.j2" %} +{% endif %} diff --git a/dockers/docker-fpm-frr/frr/gen_staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/gen_staticd.conf.j2 similarity index 100% rename from dockers/docker-fpm-frr/frr/gen_staticd.conf.j2 rename to dockers/docker-fpm-frr/frr/staticd/gen_staticd.conf.j2 diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index 571862873828..c9bff63d8c73 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -44,6 +44,8 @@ 'templates/ospfd/ospfd.conf.db.policyrange.j2', 'templates/ospfd/ospfd.conf.db.vlink.j2', 'templates/staticd/staticd.conf.j2', - 'templates/staticd/staticd.db.conf.j2']) + 'templates/staticd/staticd.db.conf.j2', + 'templates/staticd/staticd.db.default_route.conf.j2', + 'templates/frr/frr.conf.j2']) ] ) diff --git a/src/sonic-frr-mgmt-framework/templates/frr/frr.conf.j2 b/src/sonic-frr-mgmt-framework/templates/frr/frr.conf.j2 new file mode 100644 index 000000000000..f1f015a6e7a6 --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/frr/frr.conf.j2 @@ -0,0 +1,30 @@ +! +{% block banner %} +! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== +! generated by templates/frr.conf.j2 with config DB data +! file: frr.conf +! +{% endblock banner %} +! +{% include "common/daemons.common.conf.j2" %} +! +agentx +! +{% include "zebra/zebra.interfaces.conf.j2" %} +! +{% if MGMT_VRF_CONFIG %} +{% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} +{% include "staticd.db.default_route.conf.j2" %} +{% endif %} +{% else %} +{% include "staticd.db.default_route.conf.j2" %} +{% endif %} +! +{% include "staticd.db.conf.j2" %} +! +{% include "bgpd.conf.db.j2" %} +! +{% include "ospfd.conf.j2" %} +! +{% include "bfdd.conf.j2" %} +! diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 index a3b638431eeb..0ab193f4a1f8 100644 --- a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.conf.j2 @@ -12,10 +12,10 @@ ! {% if MGMT_VRF_CONFIG %} {% if MGMT_VRF_CONFIG['vrf_global']['mgmtVrfEnabled'] == 'false' %} -{% include "staticd.default_route.conf.j2" %} +{% include "staticd.db.default_route.conf.j2" %} {% endif %} {% else %} -{% include "staticd.default_route.conf.j2" %} +{% include "staticd.db.default_route.conf.j2" %} {% endif %} ! {% include "staticd.db.conf.j2" %} diff --git a/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.default_route.conf.j2 b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.default_route.conf.j2 new file mode 100644 index 000000000000..63d532203aaa --- /dev/null +++ b/src/sonic-frr-mgmt-framework/templates/staticd/staticd.db.default_route.conf.j2 @@ -0,0 +1,9 @@ +! +{% block default_route %} +! set static default route to mgmt gateway as a backup to learned default +{% if MGMT_INTERFACE %} +{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %} +{% endfor %} +{% endif %} +{% endblock default_route %} +! From 6e6dde58689ec77f8a48d021119b5877c211357e Mon Sep 17 00:00:00 2001 From: Zhenhong Zhao Date: Fri, 22 Jan 2021 21:12:50 +0000 Subject: [PATCH 24/24] Changed the target folder name of frrcfgd template files --- dockers/docker-fpm-frr/docker_init.sh | 4 +- .../docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 | 2 +- dockers/docker-fpm-frr/frr/gen_frr.conf.j2 | 2 +- .../frr/staticd/gen_staticd.conf.j2 | 2 +- src/sonic-frr-mgmt-framework/setup.py | 42 +++++++++---------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/dockers/docker-fpm-frr/docker_init.sh b/dockers/docker-fpm-frr/docker_init.sh index 2170ca699283..96149de4c379 100755 --- a/dockers/docker-fpm-frr/docker_init.sh +++ b/dockers/docker-fpm-frr/docker_init.sh @@ -15,8 +15,8 @@ CFGGEN_PARAMS=" \ -t /usr/share/sonic/templates/gen_frr.conf.j2,/etc/frr/frr.conf \ -t /usr/share/sonic/templates/isolate.j2,/usr/sbin/bgp-isolate \ -t /usr/share/sonic/templates/unisolate.j2,/usr/sbin/bgp-unisolate \ - -t /usr/local/sonic/frr/bfdd.conf.j2,/etc/frr/bfdd.conf \ - -t /usr/local/sonic/frr/ospfd.conf.j2,/etc/frr/ospfd.conf \ + -t /usr/local/sonic/frrcfgd/bfdd.conf.j2,/etc/frr/bfdd.conf \ + -t /usr/local/sonic/frrcfgd/ospfd.conf.j2,/etc/frr/ospfd.conf \ " FRR_VARS=$(sonic-cfggen $CFGGEN_PARAMS) diff --git a/dockers/docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 b/dockers/docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 index 2b5af9513f37..bb6d7f6a5a65 100644 --- a/dockers/docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/bgpd/gen_bgpd.conf.j2 @@ -1,5 +1,5 @@ {% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} - {% include "/usr/local/sonic/frr/bgpd.conf.j2" %} + {% include "/usr/local/sonic/frrcfgd/bgpd.conf.j2" %} {% else %} {% include "/usr/share/sonic/templates/bgpd/bgpd.conf.j2" %} {% endif %} diff --git a/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 b/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 index 055658f8b515..181437da07a0 100644 --- a/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 +++ b/dockers/docker-fpm-frr/frr/gen_frr.conf.j2 @@ -1,5 +1,5 @@ {% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} - {% include "/usr/local/sonic/frr/frr.conf.j2" %} + {% include "/usr/local/sonic/frrcfgd/frr.conf.j2" %} {% else %} {% include "/usr/share/sonic/templates/frr.conf.j2" %} {% endif %} diff --git a/dockers/docker-fpm-frr/frr/staticd/gen_staticd.conf.j2 b/dockers/docker-fpm-frr/frr/staticd/gen_staticd.conf.j2 index f1d0c5f46290..1346c9a4993b 100644 --- a/dockers/docker-fpm-frr/frr/staticd/gen_staticd.conf.j2 +++ b/dockers/docker-fpm-frr/frr/staticd/gen_staticd.conf.j2 @@ -1,5 +1,5 @@ {% if DEVICE_METADATA.localhost.frr_mgmt_framework_config is defined and DEVICE_METADATA.localhost.frr_mgmt_framework_config == "true" %} - {% include "/usr/local/sonic/frr/staticd.conf.j2" %} + {% include "/usr/local/sonic/frrcfgd/staticd.conf.j2" %} {% else %} {% include "/usr/share/sonic/templates/staticd/staticd.conf.j2" %} {% endif %} diff --git a/src/sonic-frr-mgmt-framework/setup.py b/src/sonic-frr-mgmt-framework/setup.py index c9bff63d8c73..d8681d1bbd88 100755 --- a/src/sonic-frr-mgmt-framework/setup.py +++ b/src/sonic-frr-mgmt-framework/setup.py @@ -26,26 +26,26 @@ 'pytest-cov', 'sonic-config-engine' ], - data_files = [('sonic/frr', ['templates/bgpd/bgpd.conf.j2', - 'templates/bgpd/bgpd.conf.db.j2', - 'templates/bgpd/bgpd.conf.db.route_map.j2', - 'templates/bgpd/bgpd.conf.db.pref_list.j2', - 'templates/bgpd/bgpd.conf.db.nbr_or_peer.j2', - 'templates/bgpd/bgpd.conf.db.nbr_af.j2', - 'templates/bgpd/bgpd.conf.db.comm_list.j2', - 'templates/bgpd/bgpd.conf.db.addr_family.j2', - 'templates/bgpd/bgpd.conf.db.addr_family.evpn.j2', - 'templates/bfdd/bfdd.conf.j2', - 'templates/ospfd/ospfd.conf.j2', - 'templates/ospfd/ospfd.conf.db.area.j2', - 'templates/ospfd/ospfd.conf.db.comm_list.j2', - 'templates/ospfd/ospfd.conf.db.distributeroute.j2', - 'templates/ospfd/ospfd.conf.db.interface.j2', - 'templates/ospfd/ospfd.conf.db.policyrange.j2', - 'templates/ospfd/ospfd.conf.db.vlink.j2', - 'templates/staticd/staticd.conf.j2', - 'templates/staticd/staticd.db.conf.j2', - 'templates/staticd/staticd.db.default_route.conf.j2', - 'templates/frr/frr.conf.j2']) + data_files = [('sonic/frrcfgd', ['templates/bgpd/bgpd.conf.j2', + 'templates/bgpd/bgpd.conf.db.j2', + 'templates/bgpd/bgpd.conf.db.route_map.j2', + 'templates/bgpd/bgpd.conf.db.pref_list.j2', + 'templates/bgpd/bgpd.conf.db.nbr_or_peer.j2', + 'templates/bgpd/bgpd.conf.db.nbr_af.j2', + 'templates/bgpd/bgpd.conf.db.comm_list.j2', + 'templates/bgpd/bgpd.conf.db.addr_family.j2', + 'templates/bgpd/bgpd.conf.db.addr_family.evpn.j2', + 'templates/bfdd/bfdd.conf.j2', + 'templates/ospfd/ospfd.conf.j2', + 'templates/ospfd/ospfd.conf.db.area.j2', + 'templates/ospfd/ospfd.conf.db.comm_list.j2', + 'templates/ospfd/ospfd.conf.db.distributeroute.j2', + 'templates/ospfd/ospfd.conf.db.interface.j2', + 'templates/ospfd/ospfd.conf.db.policyrange.j2', + 'templates/ospfd/ospfd.conf.db.vlink.j2', + 'templates/staticd/staticd.conf.j2', + 'templates/staticd/staticd.db.conf.j2', + 'templates/staticd/staticd.db.default_route.conf.j2', + 'templates/frr/frr.conf.j2']) ] )