From 07663650dfc544c7018cb8ecedbe62590e4b82de Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Tue, 22 Aug 2017 13:09:45 -0700 Subject: [PATCH 01/17] IPv4 prefixes shouldn't be sent by default over IPv6 session with FRR. RB= G=lnos-reviewers R=ntrianta,rjonnadu,rmolina,sfardeen,zxu A= --- dockers/docker-fpm-frr/bgpd.conf.j2 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index d04f6ac623e0..c66d5bfb232f 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -21,6 +21,7 @@ log facility local4 router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp log-neighbor-changes bgp bestpath as-path multipath-relax + no bgp default ipv4-unicast {# TODO: use lo[0] for backward compatibility, will revisit the case with multiple lo interfaces #} bgp router-id {{ minigraph_lo_interfaces[0]['addr'] }} {# advertise loopback #} @@ -53,6 +54,12 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if minigraph_devices[inventory_hostname]['type'] == 'ToRRouter' %} neighbor {{ neighbor_addr }} allowas-in 1 {% endif %} +{% if neighbor_addr | ipv4 %} + address-family ipv4 + neighbor {{ neighbor_addr }} activate + maximum-paths 64 + exit-address-family +{% endif %} {% if neighbor_addr | ipv6 %} address-family ipv6 neighbor {{ neighbor_addr }} activate From 45ab08731f9247e387b2f439d9a7a72319746cbc Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Sun, 27 Aug 2017 00:31:48 -0700 Subject: [PATCH 02/17] RR client support in minigraph for FRR A= --- dockers/docker-fpm-frr/bgpd.conf.j2 | 6 ++++++ src/sonic-config-engine/minigraph.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index c66d5bfb232f..1ed09ba9b61d 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -57,12 +57,18 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if neighbor_addr | ipv4 %} address-family ipv4 neighbor {{ neighbor_addr }} activate +{% if bgp_session['rrclient'] != 0 %} + neighbor {{ bgp_session['addr'] }} route-reflector-client +{% endif %} maximum-paths 64 exit-address-family {% endif %} {% if neighbor_addr | ipv6 %} address-family ipv6 neighbor {{ neighbor_addr }} activate +{% if bgp_session['rrclient'] != 0 %} + neighbor {{ bgp_session['addr'] }} route-reflector-client +{% endif %} maximum-paths 64 exit-address-family {% endif %} diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 6dbf0d570d47..a8bd445ebb20 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -274,6 +274,10 @@ def parse_cpg(cpg, hname): for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): asn = router.find(str(QName(ns1, "ASN"))).text hostname = router.find(str(QName(ns1, "Hostname"))).text + if router.find(str(QName(ns1, "RRClient"))): + rrclient = '1' + else: + rrclient = '0' if hostname == hname: myasn = int(asn) peers = router.find(str(QName(ns1, "Peers"))) @@ -292,6 +296,7 @@ def parse_cpg(cpg, hname): bgp_session = bgp_sessions[peer] if hostname == bgp_session['name']: bgp_session['asn'] = int(asn) + bgp_session['rrclient'] = int(rrclient) return bgp_sessions, myasn, bgp_peers_with_range From c9a2c927ac353f780d5016948d5686cdd4ee63b2 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Sun, 27 Aug 2017 01:02:43 -0700 Subject: [PATCH 03/17] Sync to master --- .../Accton-AS5712-54X/port_config.ini | 74 ++++++++ .../Accton-AS5712-54X/sai.profile | 2 + .../installer.conf | 3 + .../led_proc_init.soc | 163 ++++++++++++++++ .../x86_64-accton_as5712_54x-r0/minigraph.xml | 151 +++++++++++++++ .../plugins/eeprom.py | 24 +++ .../plugins/sfputil.py | 175 ++++++++++++++++++ .../Arista-7050-Q16S64/port_config.ini | 114 ++++++------ .../Arista-7050-QX32/port_config.ini | 66 +++---- .../Arista-7050-QX-32S/port_config.ini | 66 +++---- .../Arista-7060-CX32S/port_config.ini | 66 +++---- .../plugins/sfputil.py | 11 +- .../Arista-7260CX3-64/port_config.ini | 67 ------- .../Arista-7260CX3-C64/port_config.ini | 67 +++++++ .../sai.profile | 0 .../Arista-7260CX3-D108C8/port_config.ini | 121 ++++++++++++ .../Arista-7260CX3-D108C8/sai.profile | 1 + .../x86_64-arista_7260cx3_64/minigraph.xml | 4 +- .../plugins/sfputil.py | 14 +- .../x86_64-mlnx_msn2100-r0/plugins/sfputil.py | 70 +++++-- .../x86_64-mlnx_msn2410-r0/plugins/sfputil.py | 70 +++++-- .../x86_64-mlnx_msn2700-r0/plugins/sfputil.py | 70 +++++-- .../x86_64-mlnx_msn2740-r0/plugins/sfputil.py | 70 +++++-- dockers/docker-config-engine/Dockerfile.j2 | 2 +- dockers/docker-orchagent/Dockerfile.j2 | 1 + dockers/docker-orchagent/ports.json.j2 | 11 ++ dockers/docker-orchagent/start.sh | 1 + dockers/docker-orchagent/swssconfig.sh | 2 +- platform/broadcom/sai.mk | 8 +- .../broadcom/sonic-platform-modules-arista | 2 +- platform/broadcom/sonic-platform-modules-dell | 2 +- platform/cavium/cavm-sai.mk | 2 +- platform/cavium/cavm-xpnet.mk | 2 +- sonic-slave/Dockerfile | 2 +- src/sonic-config-engine/minigraph.py | 17 ++ .../tests/simple-sample-graph.xml | 62 +++++++ src/sonic-config-engine/tests/test_cfggen.py | 5 + src/sonic-linux-kernel | 2 +- src/sonic-sairedis | 2 +- src/sonic-swss | 2 +- 40 files changed, 1274 insertions(+), 320 deletions(-) create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/installer.conf create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py create mode 100644 device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py delete mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini create mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini rename device/arista/x86_64-arista_7260cx3_64/{Arista-7260CX3-64 => Arista-7260CX3-C64}/sai.profile (100%) create mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini create mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile create mode 100644 dockers/docker-orchagent/ports.json.j2 diff --git a/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini b/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini new file mode 100644 index 000000000000..61325e1ec43c --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini @@ -0,0 +1,74 @@ +# name lanes alias +Ethernet0 13 tenGigE0 +Ethernet1 14 tenGigE1 +Ethernet2 15 tenGigE2 +Ethernet3 16 tenGigE3 +Ethernet4 21 tenGigE4 +Ethernet5 22 tenGigE5 +Ethernet6 23 tenGigE6 +Ethernet7 24 tenGigE7 +Ethernet8 25 tenGigE8 +Ethernet9 26 tenGigE9 +Ethernet10 27 tenGigE10 +Ethernet11 28 tenGigE11 +Ethernet12 29 tenGigE12 +Ethernet13 30 tenGigE13 +Ethernet14 31 tenGigE14 +Ethernet15 32 tenGigE15 +Ethernet16 45 tenGigE16 +Ethernet17 46 tenGigE17 +Ethernet18 47 tenGigE18 +Ethernet19 48 tenGigE19 +Ethernet20 49 tenGigE20 +Ethernet21 50 tenGigE21 +Ethernet22 51 tenGigE22 +Ethernet23 52 tenGigE23 +Ethernet24 53 tenGigE24 +Ethernet25 54 tenGigE25 +Ethernet26 55 tenGigE26 +Ethernet27 56 tenGigE27 +Ethernet28 57 tenGigE28 +Ethernet29 58 tenGigE29 +Ethernet30 59 tenGigE30 +Ethernet31 60 tenGigE31 +Ethernet32 61 tenGigE32 +Ethernet33 62 tenGigE33 +Ethernet34 63 tenGigE34 +Ethernet35 64 tenGigE35 +Ethernet36 65 tenGigE36 +Ethernet37 66 tenGigE37 +Ethernet38 67 tenGigE38 +Ethernet39 68 tenGigE39 +Ethernet40 69 tenGigE40 +Ethernet41 70 tenGigE41 +Ethernet42 71 tenGigE42 +Ethernet43 72 tenGigE43 +Ethernet44 73 tenGigE44 +Ethernet45 74 tenGigE45 +Ethernet46 75 tenGigE46 +Ethernet47 76 tenGigE47 +Ethernet48 97 tenGigE48 +Ethernet49 98 tenGigE49 +Ethernet50 99 tenGigE50 +Ethernet51 100 tenGigE51 +Ethernet52 101 tenGigE52 +Ethernet53 102 tenGigE53 +Ethernet54 103 tenGigE54 +Ethernet55 104 tenGigE55 +Ethernet56 81 tenGigE56 +Ethernet57 82 tenGigE57 +Ethernet58 83 tenGigE58 +Ethernet59 84 tenGigE59 +Ethernet60 105 tenGigE60 +Ethernet61 106 tenGigE61 +Ethernet62 107 tenGigE62 +Ethernet63 108 tenGigE63 +Ethernet64 109 tenGigE64 +Ethernet65 110 tenGigE65 +Ethernet66 111 tenGigE66 +Ethernet67 112 tenGigE67 +Ethernet68 77 tenGigE68 +Ethernet69 78 tenGigE69 +Ethernet70 79 tenGigE70 +Ethernet71 80 tenGigE71 + diff --git a/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile b/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile new file mode 100644 index 000000000000..7fafa54db963 --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/td2-as5712-72x10G.config.bcm + diff --git a/device/accton/x86_64-accton_as5712_54x-r0/installer.conf b/device/accton/x86_64-accton_as5712_54x-r0/installer.conf new file mode 100644 index 000000000000..14404194ef53 --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x2f8 +CONSOLE_DEV=1 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc new file mode 100644 index 000000000000..e27679db9ab0 --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc @@ -0,0 +1,163 @@ +# LED setting for active +# ----------------------------------------------------------------------------- +# for as5712_54x (48xg+6qxg) +# +# on green - if link up +# off - if link down +# blink - if active +# ----------------------------------------------------------------------------- +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 + +led 0 stop +led 0 prog \ + 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ + 61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \ + D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \ + 06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \ + 96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \ + 04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \ + 0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00 +led 0 start + +led 1 stop +led 1 prog \ + 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ + 61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \ + 67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \ + 67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \ + 67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \ + D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \ + 63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \ + FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \ + 85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \ + A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \ + 57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00 +led 1 start + diff --git a/device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml b/device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml new file mode 100644 index 000000000000..8d89f28b0d86 --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml @@ -0,0 +1,151 @@ + + + + + + OCPSCH0104001MS + 10.10.1.26 + switch1 + 10.10.1.25 + 1 + 10 + 3 + + + OCPSCH0104002MS + 10.10.2.26 + switch1 + 10.10.2.25 + 1 + 10 + 3 + + + + + 64536 + switch1 + + +
10.10.1.26
+ + +
+ +
10.10.2.26
+ + +
+
+ +
+ + 64542 + OCPSCH0104001MS + + + + 64543 + OCPSCH0104002MS + + +
+
+ + + + + + HostIP + Loopback0 + + 100.0.0.9/32 + + 100.0.0.9/32 + + + + + + + + switch1 + + + + + + Ethernet48 + 10.10.1.25/30 + + + + Ethernet52 + 10.10.2.25/30 + + + + + + + + + + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet24 + switch1 + Ethernet48 + + + 40000 + DeviceInterfaceLink + OCPSCH0104002MS + Ethernet24 + switch1 + Ethernet52 + + + + + switch1 + Accton-AS5712-54X + + + + + + + switch1 + + + DhcpResources + + + + + NtpResources + + 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org + + + SyslogResources + + + + + ErspanDestinationIpv4 + + 2.2.2.2 + + + + + + + switch1 + Accton-AS5712-54X +
diff --git a/device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py new file mode 100644 index 000000000000..7681caafeef4 --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + #Two i2c buses might get flipped order, check them both. + if not os.path.exists(self.eeprom_path): + self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py new file mode 100644 index 000000000000..070b1da934cb --- /dev/null +++ b/device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py @@ -0,0 +1,175 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 + + EEPROM_OFFSET = 20 + + _port_to_eeprom_mapping = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for x in range(0, self.port_end + 1): + self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/accton/qsfp_modprs") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/accton/qsfp_lpmode") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/accton/qsfp_lpmode", "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def reset(self, port_num): + QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/devices/platform/accton/qsfp_reset" + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # File content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + # Flip the bit back high and write back to the register to take port out of reset + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + return True diff --git a/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini b/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini index 28edbeccf224..dea477b26152 100644 --- a/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini @@ -1,57 +1,57 @@ -# name lanes alias -Ethernet0 125,126,127,128 Ethernet1/1 -Ethernet4 121,122,123,124 Ethernet2/1 -Ethernet8 13,14,15,16 Ethernet3/1 -Ethernet12 9,10,11,12 Ethernet4/1 -Ethernet16 17,18,19,20 Ethernet5/1 -Ethernet20 21,22,23,24 Ethernet6/1 -Ethernet24 25,26,27,28 Ethernet7/1 -Ethernet28 29,30,31,32 Ethernet8/1 -Ethernet32 37,38,39,40 Ethernet9/1 -Ethernet36 33,34,35,36 Ethernet10/1 -Ethernet40 45,46,47,48 Ethernet11/1 -Ethernet44 41,42,43,44 Ethernet12/1 -Ethernet48 53,54,55,56 Ethernet13/1 -Ethernet52 49,50,51,52 Ethernet14/1 -Ethernet56 69,70,71,72 Ethernet15/1 -Ethernet60 65,66,67,68 Ethernet16/1 -Ethernet64 77 Ethernet17/1 -Ethernet65 78 Ethernet17/2 -Ethernet66 79 Ethernet17/3 -Ethernet67 80 Ethernet17/4 -Ethernet68 73 Ethernet18/1 -Ethernet69 74 Ethernet18/2 -Ethernet70 75 Ethernet18/3 -Ethernet71 76 Ethernet18/4 -Ethernet72 93 Ethernet19/1 -Ethernet73 94 Ethernet19/2 -Ethernet74 95 Ethernet19/3 -Ethernet75 96 Ethernet19/4 -Ethernet76 89 Ethernet20/1 -Ethernet77 90 Ethernet20/2 -Ethernet78 91 Ethernet20/3 -Ethernet79 92 Ethernet20/4 -Ethernet80 101 Ethernet21/1 -Ethernet81 102 Ethernet21/2 -Ethernet82 103 Ethernet21/3 -Ethernet83 104 Ethernet21/4 -Ethernet84 97 Ethernet22/1 -Ethernet85 98 Ethernet22/2 -Ethernet86 99 Ethernet22/3 -Ethernet87 100 Ethernet22/4 -Ethernet88 109 Ethernet23/1 -Ethernet89 110 Ethernet23/2 -Ethernet90 111 Ethernet23/3 -Ethernet91 112 Ethernet23/4 -Ethernet92 105 Ethernet24/1 -Ethernet93 106 Ethernet24/2 -Ethernet94 107 Ethernet24/3 -Ethernet95 108 Ethernet24/4 -Ethernet96 61,62,63,64 Ethernet25 -Ethernet100 57,58,59,60 Ethernet26 -Ethernet104 81,82,83,84 Ethernet27 -Ethernet108 85,86,87,88 Ethernet28 -Ethernet112 117,118,119,120 Ethernet29 -Ethernet116 113,114,115,116 Ethernet30 -Ethernet120 5,6,7,8 Ethernet31 -Ethernet124 1,2,3,4 Ethernet32 +# name lanes alias port +Ethernet0 125,126,127,128 Ethernet1/1 1 +Ethernet4 121,122,123,124 Ethernet2/1 2 +Ethernet8 13,14,15,16 Ethernet3/1 3 +Ethernet12 9,10,11,12 Ethernet4/1 4 +Ethernet16 17,18,19,20 Ethernet5/1 5 +Ethernet20 21,22,23,24 Ethernet6/1 6 +Ethernet24 25,26,27,28 Ethernet7/1 7 +Ethernet28 29,30,31,32 Ethernet8/1 8 +Ethernet32 37,38,39,40 Ethernet9/1 9 +Ethernet36 33,34,35,36 Ethernet10/1 10 +Ethernet40 45,46,47,48 Ethernet11/1 11 +Ethernet44 41,42,43,44 Ethernet12/1 12 +Ethernet48 53,54,55,56 Ethernet13/1 13 +Ethernet52 49,50,51,52 Ethernet14/1 14 +Ethernet56 69,70,71,72 Ethernet15/1 15 +Ethernet60 65,66,67,68 Ethernet16/1 16 +Ethernet64 77 Ethernet17/1 17 +Ethernet65 78 Ethernet17/2 17 +Ethernet66 79 Ethernet17/3 17 +Ethernet67 80 Ethernet17/4 17 +Ethernet68 73 Ethernet18/1 18 +Ethernet69 74 Ethernet18/2 18 +Ethernet70 75 Ethernet18/3 18 +Ethernet71 76 Ethernet18/4 18 +Ethernet72 93 Ethernet19/1 19 +Ethernet73 94 Ethernet19/2 19 +Ethernet74 95 Ethernet19/3 19 +Ethernet75 96 Ethernet19/4 19 +Ethernet76 89 Ethernet20/1 20 +Ethernet77 90 Ethernet20/2 20 +Ethernet78 91 Ethernet20/3 20 +Ethernet79 92 Ethernet20/4 20 +Ethernet80 101 Ethernet21/1 21 +Ethernet81 102 Ethernet21/2 21 +Ethernet82 103 Ethernet21/3 21 +Ethernet83 104 Ethernet21/4 21 +Ethernet84 97 Ethernet22/1 22 +Ethernet85 98 Ethernet22/2 22 +Ethernet86 99 Ethernet22/3 22 +Ethernet87 100 Ethernet22/4 22 +Ethernet88 109 Ethernet23/1 23 +Ethernet89 110 Ethernet23/2 23 +Ethernet90 111 Ethernet23/3 23 +Ethernet91 112 Ethernet23/4 23 +Ethernet92 105 Ethernet24/1 24 +Ethernet93 106 Ethernet24/2 24 +Ethernet94 107 Ethernet24/3 24 +Ethernet95 108 Ethernet24/4 24 +Ethernet96 61,62,63,64 Ethernet25 25 +Ethernet100 57,58,59,60 Ethernet26 26 +Ethernet104 81,82,83,84 Ethernet27 27 +Ethernet108 85,86,87,88 Ethernet28 28 +Ethernet112 117,118,119,120 Ethernet29 29 +Ethernet116 113,114,115,116 Ethernet30 30 +Ethernet120 5,6,7,8 Ethernet31 31 +Ethernet124 1,2,3,4 Ethernet32 32 diff --git a/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini b/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini index b9ab8854a2ec..32fa6885fa93 100644 --- a/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias -Ethernet0 125,126,127,128 Ethernet1/1 -Ethernet4 121,122,123,124 Ethernet2/1 -Ethernet8 13,14,15,16 Ethernet3/1 -Ethernet12 9,10,11,12 Ethernet4/1 -Ethernet16 17,18,19,20 Ethernet5/1 -Ethernet20 21,22,23,24 Ethernet6/1 -Ethernet24 25,26,27,28 Ethernet7/1 -Ethernet28 29,30,31,32 Ethernet8/1 -Ethernet32 37,38,39,40 Ethernet9/1 -Ethernet36 33,34,35,36 Ethernet10/1 -Ethernet40 45,46,47,48 Ethernet11/1 -Ethernet44 41,42,43,44 Ethernet12/1 -Ethernet48 53,54,55,56 Ethernet13/1 -Ethernet52 49,50,51,52 Ethernet14/1 -Ethernet56 69,70,71,72 Ethernet15/1 -Ethernet60 65,66,67,68 Ethernet16/1 -Ethernet64 77,78,79,80 Ethernet17/1 -Ethernet68 73,74,75,76 Ethernet18/1 -Ethernet72 93,94,95,96 Ethernet19/1 -Ethernet76 89,90,91,92 Ethernet20/1 -Ethernet80 101,102,103,104 Ethernet21/1 -Ethernet84 97,98,99,100 Ethernet22/1 -Ethernet88 109,110,111,112 Ethernet23/1 -Ethernet92 105,106,107,108 Ethernet24/1 -Ethernet96 61,62,63,64 Ethernet25 -Ethernet100 57,58,59,60 Ethernet26 -Ethernet104 81,82,83,84 Ethernet27 -Ethernet108 85,86,87,88 Ethernet28 -Ethernet112 117,118,119,120 Ethernet29 -Ethernet116 113,114,115,116 Ethernet30 -Ethernet120 5,6,7,8 Ethernet31 -Ethernet124 1,2,3,4 Ethernet32 +# name lanes alias port +Ethernet0 125,126,127,128 Ethernet1/1 1 +Ethernet4 121,122,123,124 Ethernet2/1 2 +Ethernet8 13,14,15,16 Ethernet3/1 3 +Ethernet12 9,10,11,12 Ethernet4/1 4 +Ethernet16 17,18,19,20 Ethernet5/1 5 +Ethernet20 21,22,23,24 Ethernet6/1 6 +Ethernet24 25,26,27,28 Ethernet7/1 7 +Ethernet28 29,30,31,32 Ethernet8/1 8 +Ethernet32 37,38,39,40 Ethernet9/1 9 +Ethernet36 33,34,35,36 Ethernet10/1 10 +Ethernet40 45,46,47,48 Ethernet11/1 11 +Ethernet44 41,42,43,44 Ethernet12/1 12 +Ethernet48 53,54,55,56 Ethernet13/1 13 +Ethernet52 49,50,51,52 Ethernet14/1 14 +Ethernet56 69,70,71,72 Ethernet15/1 15 +Ethernet60 65,66,67,68 Ethernet16/1 16 +Ethernet64 77,78,79,80 Ethernet17/1 17 +Ethernet68 73,74,75,76 Ethernet18/1 18 +Ethernet72 93,94,95,96 Ethernet19/1 19 +Ethernet76 89,90,91,92 Ethernet20/1 20 +Ethernet80 101,102,103,104 Ethernet21/1 21 +Ethernet84 97,98,99,100 Ethernet22/1 22 +Ethernet88 109,110,111,112 Ethernet23/1 23 +Ethernet92 105,106,107,108 Ethernet24/1 24 +Ethernet96 61,62,63,64 Ethernet25 25 +Ethernet100 57,58,59,60 Ethernet26 26 +Ethernet104 81,82,83,84 Ethernet27 27 +Ethernet108 85,86,87,88 Ethernet28 28 +Ethernet112 117,118,119,120 Ethernet29 29 +Ethernet116 113,114,115,116 Ethernet30 30 +Ethernet120 5,6,7,8 Ethernet31 31 +Ethernet124 1,2,3,4 Ethernet32 32 diff --git a/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini b/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini index b56d958499d4..cb36404ac44f 100644 --- a/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias -Ethernet0 9,10,11,12 Ethernet5/1 -Ethernet4 13,14,15,16 Ethernet6/1 -Ethernet8 17,18,19,20 Ethernet7/1 -Ethernet12 21,22,23,24 Ethernet8/1 -Ethernet16 29,30,31,32 Ethernet9/1 -Ethernet20 25,26,27,28 Ethernet10/1 -Ethernet24 33,34,35,36 Ethernet11/1 -Ethernet28 37,38,39,40 Ethernet12/1 -Ethernet32 45,46,47,48 Ethernet13/1 -Ethernet36 41,42,43,44 Ethernet14/1 -Ethernet40 49,50,51,52 Ethernet15/1 -Ethernet44 53,54,55,56 Ethernet16/1 -Ethernet48 69,70,71,72 Ethernet17/1 -Ethernet52 65,66,67,68 Ethernet18/1 -Ethernet56 73,74,75,76 Ethernet19/1 -Ethernet60 77,78,79,80 Ethernet20/1 -Ethernet64 93,94,95,96 Ethernet21/1 -Ethernet68 89,90,91,92 Ethernet22/1 -Ethernet72 97,98,99,100 Ethernet23/1 -Ethernet76 101,102,103,104 Ethernet24/1 -Ethernet80 109,110,111,112 Ethernet25/1 -Ethernet84 105,106,107,108 Ethernet26/1 -Ethernet88 121,122,123,124 Ethernet27/1 -Ethernet92 125,126,127,128 Ethernet28/1 -Ethernet96 61,62,63,64 Ethernet29 -Ethernet100 57,58,59,60 Ethernet30 -Ethernet104 81,82,83,84 Ethernet31 -Ethernet108 85,86,87,88 Ethernet32 -Ethernet112 117,118,119,120 Ethernet33 -Ethernet116 113,114,115,116 Ethernet34 -Ethernet120 1,2,3,4 Ethernet35 -Ethernet124 5,6,7,8 Ethernet36 +# name lanes alias port +Ethernet0 9,10,11,12 Ethernet5/1 5 +Ethernet4 13,14,15,16 Ethernet6/1 6 +Ethernet8 17,18,19,20 Ethernet7/1 7 +Ethernet12 21,22,23,24 Ethernet8/1 8 +Ethernet16 29,30,31,32 Ethernet9/1 9 +Ethernet20 25,26,27,28 Ethernet10/1 10 +Ethernet24 33,34,35,36 Ethernet11/1 11 +Ethernet28 37,38,39,40 Ethernet12/1 12 +Ethernet32 45,46,47,48 Ethernet13/1 13 +Ethernet36 41,42,43,44 Ethernet14/1 14 +Ethernet40 49,50,51,52 Ethernet15/1 15 +Ethernet44 53,54,55,56 Ethernet16/1 16 +Ethernet48 69,70,71,72 Ethernet17/1 17 +Ethernet52 65,66,67,68 Ethernet18/1 18 +Ethernet56 73,74,75,76 Ethernet19/1 19 +Ethernet60 77,78,79,80 Ethernet20/1 20 +Ethernet64 93,94,95,96 Ethernet21/1 21 +Ethernet68 89,90,91,92 Ethernet22/1 22 +Ethernet72 97,98,99,100 Ethernet23/1 23 +Ethernet76 101,102,103,104 Ethernet24/1 24 +Ethernet80 109,110,111,112 Ethernet25/1 25 +Ethernet84 105,106,107,108 Ethernet26/1 26 +Ethernet88 121,122,123,124 Ethernet27/1 27 +Ethernet92 125,126,127,128 Ethernet28/1 28 +Ethernet96 61,62,63,64 Ethernet29 29 +Ethernet100 57,58,59,60 Ethernet30 30 +Ethernet104 81,82,83,84 Ethernet31 31 +Ethernet108 85,86,87,88 Ethernet32 32 +Ethernet112 117,118,119,120 Ethernet33 33 +Ethernet116 113,114,115,116 Ethernet34 34 +Ethernet120 1,2,3,4 Ethernet35 35 +Ethernet124 5,6,7,8 Ethernet36 36 diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini index 414fb94efbc1..c1dbcfabd9e3 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias -Ethernet0 33,34,35,36 Ethernet1/1 -Ethernet4 37,38,39,40 Ethernet2/1 -Ethernet8 41,42,43,44 Ethernet3/1 -Ethernet12 45,46,47,48 Ethernet4/1 -Ethernet16 49,50,51,52 Ethernet5/1 -Ethernet20 53,54,55,56 Ethernet6/1 -Ethernet24 57,58,59,60 Ethernet7/1 -Ethernet28 61,62,63,64 Ethernet8/1 -Ethernet32 65,66,67,68 Ethernet9/1 -Ethernet36 69,70,71,72 Ethernet10/1 -Ethernet40 73,74,75,76 Ethernet11/1 -Ethernet44 77,78,79,80 Ethernet12/1 -Ethernet48 81,82,83,84 Ethernet13/1 -Ethernet52 85,86,87,88 Ethernet14/1 -Ethernet56 89,90,91,92 Ethernet15/1 -Ethernet60 93,94,95,96 Ethernet16/1 -Ethernet64 97,98,99,100 Ethernet17/1 -Ethernet68 101,102,103,104 Ethernet18/1 -Ethernet72 105,106,107,108 Ethernet19/1 -Ethernet76 109,110,111,112 Ethernet20/1 -Ethernet80 113,114,115,116 Ethernet21/1 -Ethernet84 117,118,119,120 Ethernet22/1 -Ethernet88 121,122,123,124 Ethernet23/1 -Ethernet92 125,126,127,128 Ethernet24/1 -Ethernet96 1,2,3,4 Ethernet25/1 -Ethernet100 5,6,7,8 Ethernet26/1 -Ethernet104 9,10,11,12 Ethernet27/1 -Ethernet108 13,14,15,16 Ethernet28/1 -Ethernet112 17,18,19,20 Ethernet29/1 -Ethernet116 21,22,23,24 Ethernet30/1 -Ethernet120 25,26,27,28 Ethernet31/1 -Ethernet124 29,30,31,32 Ethernet32/1 +# name lanes alias port +Ethernet0 33,34,35,36 Ethernet1/1 1 +Ethernet4 37,38,39,40 Ethernet2/1 2 +Ethernet8 41,42,43,44 Ethernet3/1 3 +Ethernet12 45,46,47,48 Ethernet4/1 4 +Ethernet16 49,50,51,52 Ethernet5/1 5 +Ethernet20 53,54,55,56 Ethernet6/1 6 +Ethernet24 57,58,59,60 Ethernet7/1 7 +Ethernet28 61,62,63,64 Ethernet8/1 8 +Ethernet32 65,66,67,68 Ethernet9/1 9 +Ethernet36 69,70,71,72 Ethernet10/1 10 +Ethernet40 73,74,75,76 Ethernet11/1 11 +Ethernet44 77,78,79,80 Ethernet12/1 12 +Ethernet48 81,82,83,84 Ethernet13/1 13 +Ethernet52 85,86,87,88 Ethernet14/1 14 +Ethernet56 89,90,91,92 Ethernet15/1 15 +Ethernet60 93,94,95,96 Ethernet16/1 16 +Ethernet64 97,98,99,100 Ethernet17/1 17 +Ethernet68 101,102,103,104 Ethernet18/1 18 +Ethernet72 105,106,107,108 Ethernet19/1 19 +Ethernet76 109,110,111,112 Ethernet20/1 20 +Ethernet80 113,114,115,116 Ethernet21/1 21 +Ethernet84 117,118,119,120 Ethernet22/1 22 +Ethernet88 121,122,123,124 Ethernet23/1 23 +Ethernet92 125,126,127,128 Ethernet24/1 24 +Ethernet96 1,2,3,4 Ethernet25/1 25 +Ethernet100 5,6,7,8 Ethernet26/1 26 +Ethernet104 9,10,11,12 Ethernet27/1 27 +Ethernet108 13,14,15,16 Ethernet28/1 28 +Ethernet112 17,18,19,20 Ethernet29/1 29 +Ethernet116 21,22,23,24 Ethernet30/1 30 +Ethernet120 25,26,27,28 Ethernet31/1 31 +Ethernet124 29,30,31,32 Ethernet32/1 32 diff --git a/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py b/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py index b85e0f53653e..9a6d770d460b 100644 --- a/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py +++ b/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py @@ -1,9 +1,12 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: import arista.utils.sonic_sfputil as arista_sfputil -except ImportError, e: - raise ImportError (str(e) + "- required module not found") +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -sfputil = arista_sfputil.getSfpUtil() +SfpUtil = arista_sfputil.getSfpUtil() diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini deleted file mode 100644 index c0213576d087..000000000000 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini +++ /dev/null @@ -1,67 +0,0 @@ -# name lanes alias port -Ethernet0 77,78,79,80 Ethernet1/1 1 -Ethernet4 65,66,67,68 Ethernet2/1 2 -Ethernet8 85,86,87,88 Ethernet3/1 3 -Ethernet12 89,90,91,92 Ethernet4/1 4 -Ethernet16 109,110,111,112 Ethernet5/1 5 -Ethernet20 97,98,99,100 Ethernet6/1 6 -Ethernet24 117,118,119,120 Ethernet7/1 7 -Ethernet28 5,6,7,8 Ethernet8/1 8 -Ethernet32 17,18,19,20 Ethernet9/1 9 -Ethernet36 13,14,15,16 Ethernet10/1 10 -Ethernet40 29,30,31,32 Ethernet11/1 11 -Ethernet44 37,38,39,40 Ethernet12/1 12 -Ethernet48 49,50,51,52 Ethernet13/1 13 -Ethernet52 45,46,47,48 Ethernet14/1 14 -Ethernet56 61,62,63,64 Ethernet15/1 15 -Ethernet60 121,122,123,124 Ethernet16/1 16 -Ethernet64 193,194,195,196 Ethernet17/1 17 -Ethernet68 133,134,135,136 Ethernet18/1 18 -Ethernet72 205,206,207,208 Ethernet19/1 19 -Ethernet76 213,214,215,216 Ethernet20/1 20 -Ethernet80 225,226,227,228 Ethernet21/1 21 -Ethernet84 221,222,223,224 Ethernet22/1 22 -Ethernet88 237,238,239,240 Ethernet23/1 23 -Ethernet92 245,246,247,248 Ethernet24/1 24 -Ethernet96 141,142,143,144 Ethernet25/1 25 -Ethernet100 249,250,251,252 Ethernet26/1 26 -Ethernet104 149,150,151,152 Ethernet27/1 27 -Ethernet108 153,154,155,156 Ethernet28/1 28 -Ethernet112 173,174,175,176 Ethernet29/1 29 -Ethernet116 161,162,163,164 Ethernet30/1 30 -Ethernet120 181,182,183,184 Ethernet31/1 31 -Ethernet124 185,186,187,188 Ethernet32/1 32 -Ethernet128 69,70,71,72 Ethernet33/1 33 -Ethernet132 73,74,75,76 Ethernet34/1 34 -Ethernet136 93,94,95,96 Ethernet35/1 35 -Ethernet140 81,82,83,84 Ethernet36/1 36 -Ethernet144 101,102,103,104 Ethernet37/1 37 -Ethernet148 105,106,107,108 Ethernet38/1 38 -Ethernet152 1,2,3,4 Ethernet39/1 39 -Ethernet156 113,114,115,116 Ethernet40/1 40 -Ethernet160 9,10,11,12 Ethernet41/1 41 -Ethernet164 21,22,23,24 Ethernet42/1 42 -Ethernet168 33,34,35,36 Ethernet43/1 43 -Ethernet172 25,26,27,28 Ethernet44/1 44 -Ethernet176 41,42,43,44 Ethernet45/1 45 -Ethernet180 53,54,55,56 Ethernet46/1 46 -Ethernet184 125,126,127,128 Ethernet47/1 47 -Ethernet188 57,58,59,60 Ethernet48/1 48 -Ethernet192 129,130,131,132 Ethernet49/1 49 -Ethernet196 197,198,199,200 Ethernet50/1 50 -Ethernet200 209,210,211,212 Ethernet51/1 51 -Ethernet204 201,202,203,204 Ethernet52/1 52 -Ethernet208 217,218,219,220 Ethernet53/1 53 -Ethernet212 229,230,231,232 Ethernet54/1 54 -Ethernet216 241,242,243,244 Ethernet55/1 55 -Ethernet220 233,234,235,236 Ethernet56/1 56 -Ethernet224 253,254,255,256 Ethernet57/1 57 -Ethernet228 137,138,139,140 Ethernet58/1 58 -Ethernet232 157,158,159,160 Ethernet59/1 59 -Ethernet236 145,146,147,148 Ethernet60/1 60 -Ethernet240 165,166,167,168 Ethernet61/1 61 -Ethernet244 169,170,171,172 Ethernet62/1 62 -Ethernet248 189,190,191,192 Ethernet63/1 63 -Ethernet252 177,178,179,180 Ethernet64/1 64 -Ethernet256 257 Ethernet65 65 -Ethernet260 259 Ethernet66 66 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini new file mode 100644 index 000000000000..4f073e46dce3 --- /dev/null +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini @@ -0,0 +1,67 @@ +# name lanes alias port +Ethernet0 77,78,79,80 Ethernet1/1 1 +Ethernet4 65,66,67,68 Ethernet2/1 2 +Ethernet8 85,86,87,88 Ethernet3/1 3 +Ethernet12 89,90,91,92 Ethernet4/1 4 +Ethernet16 109,110,111,112 Ethernet5/1 5 +Ethernet20 97,98,99,100 Ethernet6/1 6 +Ethernet24 5,6,7,8 Ethernet7/1 7 +Ethernet28 13,14,15,16 Ethernet8/1 8 +Ethernet32 25,26,27,28 Ethernet9/1 9 +Ethernet36 21,22,23,24 Ethernet10/1 10 +Ethernet40 37,38,39,40 Ethernet11/1 11 +Ethernet44 45,46,47,48 Ethernet12/1 12 +Ethernet48 57,58,59,60 Ethernet13/1 13 +Ethernet52 53,54,55,56 Ethernet14/1 14 +Ethernet56 117,118,119,120 Ethernet15/1 15 +Ethernet60 121,122,123,124 Ethernet16/1 16 +Ethernet64 141,142,143,144 Ethernet17/1 17 +Ethernet68 133,134,135,136 Ethernet18/1 18 +Ethernet72 197,198,199,200 Ethernet19/1 19 +Ethernet76 205,206,207,208 Ethernet20/1 20 +Ethernet80 217,218,219,220 Ethernet21/1 21 +Ethernet84 213,214,215,216 Ethernet22/1 22 +Ethernet88 229,230,231,232 Ethernet23/1 23 +Ethernet92 237,238,239,240 Ethernet24/1 24 +Ethernet96 249,250,251,252 Ethernet25/1 25 +Ethernet100 245,246,247,248 Ethernet26/1 26 +Ethernet104 149,150,151,152 Ethernet27/1 27 +Ethernet108 153,154,155,156 Ethernet28/1 28 +Ethernet112 173,174,175,176 Ethernet29/1 29 +Ethernet116 161,162,163,164 Ethernet30/1 30 +Ethernet120 181,182,183,184 Ethernet31/1 31 +Ethernet124 185,186,187,188 Ethernet32/1 32 +Ethernet128 69,70,71,72 Ethernet33/1 33 +Ethernet132 73,74,75,76 Ethernet34/1 34 +Ethernet136 93,94,95,96 Ethernet35/1 35 +Ethernet140 81,82,83,84 Ethernet36/1 36 +Ethernet144 101,102,103,104 Ethernet37/1 37 +Ethernet148 105,106,107,108 Ethernet38/1 38 +Ethernet152 9,10,11,12 Ethernet39/1 39 +Ethernet156 1,2,3,4 Ethernet40/1 40 +Ethernet160 17,18,19,20 Ethernet41/1 41 +Ethernet164 29,30,31,32 Ethernet42/1 42 +Ethernet168 41,42,43,44 Ethernet43/1 43 +Ethernet172 33,34,35,36 Ethernet44/1 44 +Ethernet176 49,50,51,52 Ethernet45/1 45 +Ethernet180 61,62,63,64 Ethernet46/1 46 +Ethernet184 125,126,127,128 Ethernet47/1 47 +Ethernet188 113,114,115,116 Ethernet48/1 48 +Ethernet192 129,130,131,132 Ethernet49/1 49 +Ethernet196 137,138,139,140 Ethernet50/1 50 +Ethernet200 201,202,203,204 Ethernet51/1 51 +Ethernet204 193,194,195,196 Ethernet52/1 52 +Ethernet208 209,210,211,212 Ethernet53/1 53 +Ethernet212 221,222,223,224 Ethernet54/1 54 +Ethernet216 233,234,235,236 Ethernet55/1 55 +Ethernet220 225,226,227,228 Ethernet56/1 56 +Ethernet224 241,242,243,244 Ethernet57/1 57 +Ethernet228 253,254,255,256 Ethernet58/1 58 +Ethernet232 157,158,159,160 Ethernet59/1 59 +Ethernet236 145,146,147,148 Ethernet60/1 60 +Ethernet240 165,166,167,168 Ethernet61/1 61 +Ethernet244 169,170,171,172 Ethernet62/1 62 +Ethernet248 189,190,191,192 Ethernet63/1 63 +Ethernet252 177,178,179,180 Ethernet64/1 64 +Ethernet256 257 Ethernet65 65 +Ethernet260 259 Ethernet66 66 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/sai.profile b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/sai.profile similarity index 100% rename from device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/sai.profile rename to device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/sai.profile diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini new file mode 100644 index 000000000000..b06d1c7575d4 --- /dev/null +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini @@ -0,0 +1,121 @@ +# name lanes alias port +Ethernet0 77,78 Ethernet1/1 1 +Ethernet2 79,80 Ethernet1/3 2 +Ethernet4 65,66 Ethernet2/1 3 +Ethernet6 67,68 Ethernet2/3 4 +Ethernet8 85,86 Ethernet3/1 5 +Ethernet10 87,88 Ethernet3/3 6 +Ethernet12 89,90 Ethernet4/1 7 +Ethernet14 91,92 Ethernet4/3 8 +Ethernet16 109,110 Ethernet5/1 9 +Ethernet18 111,112 Ethernet5/3 10 +Ethernet20 97,98 Ethernet6/1 11 +Ethernet22 99,100 Ethernet6/3 12 +Ethernet24 5,6 Ethernet7/1 13 +Ethernet26 7,8 Ethernet7/3 14 +Ethernet28 13,14 Ethernet8/1 15 +Ethernet30 15,16 Ethernet8/3 16 +Ethernet32 25,26 Ethernet9/1 17 +Ethernet34 27,28 Ethernet9/3 18 +Ethernet36 21,22 Ethernet10/1 19 +Ethernet38 23,24 Ethernet10/3 20 +Ethernet40 37,38 Ethernet11/1 21 +Ethernet42 39,40 Ethernet11/3 22 +Ethernet44 45,46 Ethernet12/1 23 +Ethernet46 47,48 Ethernet12/3 24 +Ethernet48 57,58 Ethernet13/1 25 +Ethernet50 59,60 Ethernet13/3 26 +Ethernet52 53,54 Ethernet14/1 27 +Ethernet54 55,56 Ethernet14/3 28 +Ethernet56 117,118 Ethernet15/1 29 +Ethernet58 119,120 Ethernet15/3 30 +Ethernet60 121,122 Ethernet16/1 31 +Ethernet62 123,124 Ethernet16/3 32 +Ethernet64 141,142 Ethernet17/1 33 +Ethernet66 143,144 Ethernet17/3 34 +Ethernet68 133,134,135,136 Ethernet18/1 35 +Ethernet72 197,198 Ethernet19/1 36 +Ethernet74 199,200 Ethernet19/3 37 +Ethernet76 205,206,207,208 Ethernet20/1 38 +Ethernet80 217,218 Ethernet21/1 39 +Ethernet82 219,220 Ethernet21/3 40 +Ethernet84 213,214 Ethernet22/1 41 +Ethernet86 215,216 Ethernet22/3 42 +Ethernet88 229,230 Ethernet23/1 43 +Ethernet90 231,232 Ethernet23/3 44 +Ethernet92 237,238 Ethernet24/1 45 +Ethernet94 239,240 Ethernet24/3 46 +Ethernet96 249,250 Ethernet25/1 47 +Ethernet98 251,252 Ethernet25/3 48 +Ethernet100 245,246 Ethernet26/1 49 +Ethernet102 247,248 Ethernet26/3 50 +Ethernet104 149,150 Ethernet27/1 51 +Ethernet106 151,152 Ethernet27/3 52 +Ethernet108 153,154 Ethernet28/1 53 +Ethernet110 155,156 Ethernet28/3 54 +Ethernet112 173,174 Ethernet29/1 55 +Ethernet114 175,176 Ethernet29/3 56 +Ethernet116 161,162 Ethernet30/1 57 +Ethernet118 163,164 Ethernet30/3 58 +Ethernet120 181,182 Ethernet31/1 59 +Ethernet122 183,184 Ethernet31/3 60 +Ethernet124 185,186 Ethernet32/1 61 +Ethernet126 187,188 Ethernet32/3 62 +Ethernet128 69,70 Ethernet33/1 63 +Ethernet130 71,72 Ethernet33/3 64 +Ethernet132 73,74 Ethernet34/1 65 +Ethernet134 75,76 Ethernet34/3 66 +Ethernet136 93,94 Ethernet35/1 67 +Ethernet138 95,96 Ethernet35/3 68 +Ethernet140 81,82 Ethernet36/1 69 +Ethernet142 83,84 Ethernet36/3 70 +Ethernet144 101,102 Ethernet37/1 71 +Ethernet146 103,104 Ethernet37/3 72 +Ethernet148 105,106 Ethernet38/1 73 +Ethernet150 107,108 Ethernet38/3 74 +Ethernet152 9,10 Ethernet39/1 75 +Ethernet154 11,12 Ethernet39/3 76 +Ethernet156 1,2 Ethernet40/1 77 +Ethernet158 3,4 Ethernet40/3 78 +Ethernet160 17,18 Ethernet41/1 79 +Ethernet162 19,20 Ethernet41/3 80 +Ethernet164 29,30 Ethernet42/1 81 +Ethernet166 31,32 Ethernet42/1 82 +Ethernet168 41,42 Ethernet43/1 83 +Ethernet170 43,44 Ethernet43/3 84 +Ethernet172 33,34 Ethernet44/1 85 +Ethernet174 35,36 Ethernet44/3 86 +Ethernet176 49,50,51,52 Ethernet45/1 87 +Ethernet180 61,62,63,64 Ethernet46/1 88 +Ethernet184 125,126,127,128 Ethernet47/1 89 +Ethernet188 113,114,115,116 Ethernet48/1 90 +Ethernet192 129,130,131,132 Ethernet49/1 91 +Ethernet196 137,138,139,140 Ethernet50/1 92 +Ethernet200 201,202,203,204 Ethernet51/1 93 +Ethernet204 193,194,195,196 Ethernet52/1 94 +Ethernet208 209,210 Ethernet53/1 95 +Ethernet210 211,212 Ethernet53/3 96 +Ethernet212 221,222 Ethernet54/1 97 +Ethernet214 223,224 Ethernet54/3 98 +Ethernet216 233,234 Ethernet55/1 99 +Ethernet218 235,236 Ethernet55/3 100 +Ethernet220 225,226 Ethernet56/1 101 +Ethernet222 227,228 Ethernet56/3 102 +Ethernet224 241,242 Ethernet57/1 103 +Ethernet226 243,244 Ethernet57/3 104 +Ethernet228 253,254 Ethernet58/1 105 +Ethernet230 255,256 Ethernet58/3 106 +Ethernet232 157,158 Ethernet59/1 107 +Ethernet234 159,160 Ethernet59/3 108 +Ethernet236 145,146 Ethernet60/1 109 +Ethernet238 147,148 Ethernet60/3 110 +Ethernet240 165,166 Ethernet61/1 111 +Ethernet242 167,168 Ethernet61/3 112 +Ethernet244 169,170 Ethernet62/1 113 +Ethernet246 171,172 Ethernet62/3 114 +Ethernet248 189,190 Ethernet63/1 115 +Ethernet250 191,192 Ethernet63/3 116 +Ethernet252 177,178 Ethernet64/1 117 +Ethernet254 179,180 Ethernet64/3 118 +Ethernet256 257 Ethernet257 119 +Ethernet260 259 Ethernet259 120 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile new file mode 100644 index 000000000000..030527daf9c0 --- /dev/null +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/th2-a7260cx3-64-108x50G+10x100G.config.bcm diff --git a/device/arista/x86_64-arista_7260cx3_64/minigraph.xml b/device/arista/x86_64-arista_7260cx3_64/minigraph.xml index 957b60822ba8..2c632dacc471 100644 --- a/device/arista/x86_64-arista_7260cx3_64/minigraph.xml +++ b/device/arista/x86_64-arista_7260cx3_64/minigraph.xml @@ -809,7 +809,7 @@ sonic - Arista-7260CX3-64 + Arista-7260CX3-C64 @@ -844,5 +844,5 @@ sonic - Arista-7260CX3-64 + Arista-7260CX3-C64 diff --git a/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py b/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py index ce60de2b384d..9a6d770d460b 100644 --- a/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py +++ b/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py @@ -1,8 +1,12 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - import arista.utils.sonic_sfputil as arista_sfputil -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import arista.utils.sonic_sfputil as arista_sfputil +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -sfputil = arista_sfputil.getSfpUtil() + +SfpUtil = arista_sfputil.getSfpUtil() diff --git a/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py index c6628e66e419..ce0adde71a15 100644 --- a/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py @@ -1,28 +1,62 @@ -#! /usr/bin/python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 15 - ports_in_block = 16 + PORT_START = 0 + PORT_END = 15 + PORTS_IN_BLOCK = 16 - eeprom_offset = 1 + EEPROM_OFFSET = 1 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} - _qsfp_ports = range(0, ports_in_block + 1) + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/bsp/qsfp/qsfp{0}" - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) - sfputilbase.__init__(self, port_num) - + self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + raise NotImplementedError + + def get_low_power_mode(self, port_num): + + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + + raise NotImplementedError + + def reset(self, port_num): + + raise NotImplementedError diff --git a/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py index 9d4474ac1ec9..db71cb423503 100644 --- a/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py @@ -1,28 +1,62 @@ -#! /usr/bin/python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 55 - ports_in_block = 56 + PORT_START = 0 + PORT_END = 55 + PORTS_IN_BLOCK = 56 - eeprom_offset = 1 + EEPROM_OFFSET = 1 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} - _qsfp_ports = range(0, ports_in_block + 1) + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/bsp/qsfp/qsfp{0}" - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) - sfputilbase.__init__(self, port_num) - + self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + raise NotImplementedError + + def get_low_power_mode(self, port_num): + + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + + raise NotImplementedError + + def reset(self, port_num): + + raise NotImplementedError diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py index 04e9a4eff85e..b746af219917 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py @@ -1,28 +1,62 @@ -#! /usr/bin/python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 31 - ports_in_block = 32 + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 - eeprom_offset = 1 + EEPROM_OFFSET = 1 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} - _qsfp_ports = range(0, ports_in_block + 1) + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/bsp/qsfp/qsfp{0}" - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) - sfputilbase.__init__(self, port_num) - + self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + raise NotImplementedError + + def get_low_power_mode(self, port_num): + + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + + raise NotImplementedError + + def reset(self, port_num): + + raise NotImplementedError diff --git a/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py index 04e9a4eff85e..b746af219917 100644 --- a/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py @@ -1,28 +1,62 @@ -#! /usr/bin/python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 31 - ports_in_block = 32 + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 - eeprom_offset = 1 + EEPROM_OFFSET = 1 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} - _qsfp_ports = range(0, ports_in_block + 1) + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/bsp/qsfp/qsfp{0}" - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) - sfputilbase.__init__(self, port_num) - + self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + raise NotImplementedError + + def get_low_power_mode(self, port_num): + + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + + raise NotImplementedError + + def reset(self, port_num): + + raise NotImplementedError diff --git a/dockers/docker-config-engine/Dockerfile.j2 b/dockers/docker-config-engine/Dockerfile.j2 index 68555d44779b..b4d924bddfc3 100644 --- a/dockers/docker-config-engine/Dockerfile.j2 +++ b/dockers/docker-config-engine/Dockerfile.j2 @@ -10,7 +10,7 @@ RUN apt-get install -y python-lxml python-yaml python-bitarray python-pip python RUN pip install --upgrade pip -RUN pip install netaddr ipaddr jinja2 pyangbind +RUN pip install netaddr ipaddr jinja2 pyangbind==0.5.10 {% if docker_config_engine_debs.strip() %} COPY \ diff --git a/dockers/docker-orchagent/Dockerfile.j2 b/dockers/docker-orchagent/Dockerfile.j2 index 73fb087401ab..587d8f4db2ee 100755 --- a/dockers/docker-orchagent/Dockerfile.j2 +++ b/dockers/docker-orchagent/Dockerfile.j2 @@ -30,5 +30,6 @@ COPY ["arp_update", "start.sh", "orchagent.sh", "swssconfig.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["ipinip.json.j2", "/usr/share/sonic/templates/"] COPY ["mirror.json.j2", "/usr/share/sonic/templates/"] +COPY ["ports.json.j2", "/usr/share/sonic/templates/"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-orchagent/ports.json.j2 b/dockers/docker-orchagent/ports.json.j2 new file mode 100644 index 000000000000..f59ee993eead --- /dev/null +++ b/dockers/docker-orchagent/ports.json.j2 @@ -0,0 +1,11 @@ +[ +{% for interface in ethernet_interfaces %} + { + "PORT_TABLE:{{ interface['name'] }}": { + "speed": "{{ interface['speed'] }}" + }, + "OP": "SET" + }{% if not loop.last %},{% endif %} + +{% endfor %} +] diff --git a/dockers/docker-orchagent/start.sh b/dockers/docker-orchagent/start.sh index 40ef66441c02..5f961a8bd294 100755 --- a/dockers/docker-orchagent/start.sh +++ b/dockers/docker-orchagent/start.sh @@ -4,6 +4,7 @@ mkdir -p /etc/swss/config.d/ sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/mirror.json.j2 > /etc/swss/config.d/mirror.json +sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json export platform=`sonic-cfggen -m /etc/sonic/minigraph.xml -v platform` diff --git a/dockers/docker-orchagent/swssconfig.sh b/dockers/docker-orchagent/swssconfig.sh index 768417779e2d..2530aca06bb3 100755 --- a/dockers/docker-orchagent/swssconfig.sh +++ b/dockers/docker-orchagent/swssconfig.sh @@ -38,7 +38,7 @@ fast_reboot HWSKU=`sonic-cfggen -m /etc/sonic/minigraph.xml -v minigraph_hwsku` -SWSSCONFIG_ARGS="00-copp.config.json ipinip.json mirror.json " +SWSSCONFIG_ARGS="00-copp.config.json ipinip.json mirror.json ports.json " if [ "$HWSKU" == "Force10-S6000" ]; then SWSSCONFIG_ARGS+="td2.32ports.buffers.json td2.32ports.qos.json " diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index ec7a34253075..eaf188485fed 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_2.1.5.1-16-20170712202323.49_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_2.1.5.1-16-20170712202323.49_amd64.deb?sv=2015-04-05&sr=b&sig=jsPXiAoSyKqZ1SmiyeEj73W8tRlri8ysExnWvc%2BWSi4%3D&se=2031-03-21T22%3A49%3A32Z&sp=r" +BRCM_SAI = libsaibcm_2.1.5.1-17_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_2.1.5.1-17_amd64.deb?sv=2015-04-05&sr=b&sig=6sJ4dd%2FF1hqStNQk5Z6d%2BYQGRZxLDihXRl60EeN7agc%3D&se=2031-05-02T09%3A37%3A54Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_2.1.5.1-16-20170712202323.49_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_2.1.5.1-17_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_2.1.5.1-16-20170712202323.49_amd64.deb?sv=2015-04-05&sr=b&sig=azYZkCi%2FFGS4eELKhIozOok3qimfH%2FjdXlz%2BS2MRBco%3D&se=2031-03-21T22%3A49%3A57Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_2.1.5.1-17_amd64.deb?sv=2015-04-05&sr=b&sig=syV0rie0L2Dn4lhmndCTyCTgXQv8DPoWD3IxtlSdeNo%3D&se=2031-05-02T09%3A37%3A18Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV) $(BRCM_SAI)_DEPENDS += $(BRCM_OPENNSL) diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 51bbe2cd86af..7c505290bb26 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 51bbe2cd86af7df20b27e0cd1f02c2ad08ab2f03 +Subproject commit 7c505290bb26babdef604a377e71b3df702897a8 diff --git a/platform/broadcom/sonic-platform-modules-dell b/platform/broadcom/sonic-platform-modules-dell index 6cff8248fa8c..5ab014c0d4f9 160000 --- a/platform/broadcom/sonic-platform-modules-dell +++ b/platform/broadcom/sonic-platform-modules-dell @@ -1 +1 @@ -Subproject commit 6cff8248fa8c772a077bf3dcb5c86a376357f261 +Subproject commit 5ab014c0d4f9ad71d7791e7d4da0645d2b2d493b diff --git a/platform/cavium/cavm-sai.mk b/platform/cavium/cavm-sai.mk index c52c4960b9d6..0008135729c5 100644 --- a/platform/cavium/cavm-sai.mk +++ b/platform/cavium/cavm-sai.mk @@ -1,6 +1,6 @@ # Cavium SAI -CAVM_SAI_GITHUB = https://github.com/XPliant/OpenXPS/raw/eedd0b8bb7e7a09602a24418a462a5c10792a145/SAI/cavm-sai/ +CAVM_SAI_GITHUB = https://github.com/XPliant/OpenXPS/raw/13a7eaf10f523e7887964ca235f19095fcc88537/SAI/cavm-sai/ CAVM_LIBSAI = libsai.deb CAVM_SAI = sai.deb diff --git a/platform/cavium/cavm-xpnet.mk b/platform/cavium/cavm-xpnet.mk index 613fa9433564..ed86558a36ae 100644 --- a/platform/cavium/cavm-xpnet.mk +++ b/platform/cavium/cavm-xpnet.mk @@ -1,4 +1,4 @@ -CAVM_SAI_URL = https://github.com/XPliant/OpenXPS/raw/092461a1cf57a11132fbf8e74fa79bab3ab00f2a/SAI +CAVM_SAI_URL = https://github.com/XPliant/OpenXPS/raw/c26aea6a7098936ab3692e148238d73fa8962585/SAI CAVM_XPNET_DEB = xp80-Pcie-Endpoint.deb $(CAVM_XPNET_DEB)_URL = $(CAVM_SAI_URL)/netdev/$(CAVM_XPNET_DEB) diff --git a/sonic-slave/Dockerfile b/sonic-slave/Dockerfile index 826a7129a7e0..f194bf604caa 100644 --- a/sonic-slave/Dockerfile +++ b/sonic-slave/Dockerfile @@ -221,7 +221,7 @@ RUN pip install \ RUN pip install j2cli # For sonic config engine testing -RUN pip install pyangbind +RUN pip install pyangbind==0.5.10 # For supervisor build RUN pip install meld3 mock diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index a8bd445ebb20..c0b2e6550a9f 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -330,6 +330,19 @@ def parse_meta(meta, hname): deployment_id = value return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id +def parse_deviceinfo(meta, hwsku): + ethernet_interfaces = [] + + for device_info in meta.findall(str(QName(ns, "DeviceInfo"))): + dev_sku = device_info.find(str(QName(ns, "HwSku"))).text + if dev_sku == hwsku: + interfaces = device_info.find(str(QName(ns, "EthernetInterfaces"))) + for interface in interfaces.findall(str(QName(ns1, "EthernetInterface"))): + name = interface.find(str(QName(ns, "InterfaceName"))).text + speed = interface.find(str(QName(ns, "Speed"))).text + ethernet_interfaces.append({ 'name':name, 'speed':speed }) + + return ethernet_interfaces def get_console_info(devices, dev, port): for k, v in devices.items(): @@ -416,6 +429,7 @@ def parse_xml(filename, platform=None, port_config_file=None): neighbors = None devices = None hostname = None + ethernet_interfaces = [] syslog_servers = [] dhcp_servers = [] ntp_servers = [] @@ -445,6 +459,8 @@ def parse_xml(filename, platform=None, port_config_file=None): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) + elif child.tag == str(QName(ns, "DeviceInfos")): + ethernet_interfaces = parse_deviceinfo(child, hwsku) results = {} results['minigraph_hwsku'] = hwsku @@ -493,6 +509,7 @@ def parse_xml(filename, platform=None, port_config_file=None): results['forced_mgmt_routes'] = mgmt_routes results['erspan_dst'] = erspan_dst results['deployment_id'] = deployment_id + results['ethernet_interfaces'] = ethernet_interfaces return results diff --git a/src/sonic-config-engine/tests/simple-sample-graph.xml b/src/sonic-config-engine/tests/simple-sample-graph.xml index 20bfb07f00d0..7daae24f49a6 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph.xml @@ -200,6 +200,68 @@ + + + true + + + DeviceInterface + + true + true + 1 + fortyGigE0/0 + + false + 0 + 0 + 10000 + + + DeviceInterface + + true + true + 1 + fortyGigE0/4 + + false + 0 + 0 + 25000 + + + DeviceInterface + + true + true + 1 + fortyGigE0/8 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + fortyGigE0/12 + + false + 0 + 0 + 1000000 + + + true + 0 + Force10-S6000 + + switch-t0 Force10-S6000 diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index d3ff3e8b9f4e..153b0bb14f36 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -119,3 +119,8 @@ def test_minigraph_deployment_id(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v deployment_id' output = self.run_script(argument) self.assertEqual(output.strip(), "1") + + def test_minigraph_ethernet_interfaces(self): + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v ethernet_interfaces' + output = self.run_script(argument) + self.assertEqual(output.strip(), "[{'speed': '10000', 'name': 'fortyGigE0/0'}, {'speed': '25000', 'name': 'fortyGigE0/4'}, {'speed': '40000', 'name': 'fortyGigE0/8'}, {'speed': '1000000', 'name': 'fortyGigE0/12'}]") diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index a97c5e416f8d..b386d52bd68b 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit a97c5e416f8d4c8d6ddd69a7bb6b983527b3c627 +Subproject commit b386d52bd68bdc5facbd837e265f49a8350e14a1 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 7e70b4d63020..3f4afbbd9d7e 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 7e70b4d63020fc9ea1aa009c264e4effab7bcda0 +Subproject commit 3f4afbbd9d7ed2f077922e0cb0d59df743e34a9a diff --git a/src/sonic-swss b/src/sonic-swss index f9b55d30276d..eaccf67cabd2 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit f9b55d30276d1a6ab94e7321d9b2a3bf076fd683 +Subproject commit eaccf67cabd22df0ff7d0117fe55f4261bc961d9 From 38a82615dc0707b37508f26668dbf1cef6818305 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 28 Aug 2017 18:07:14 -0700 Subject: [PATCH 04/17] Revert "Sync to master" This reverts commit c9a2c927ac353f780d5016948d5686cdd4ee63b2. --- .../Accton-AS5712-54X/port_config.ini | 74 -------- .../Accton-AS5712-54X/sai.profile | 2 - .../installer.conf | 3 - .../led_proc_init.soc | 163 ---------------- .../x86_64-accton_as5712_54x-r0/minigraph.xml | 151 --------------- .../plugins/eeprom.py | 24 --- .../plugins/sfputil.py | 175 ------------------ .../Arista-7050-Q16S64/port_config.ini | 114 ++++++------ .../Arista-7050-QX32/port_config.ini | 66 +++---- .../Arista-7050-QX-32S/port_config.ini | 66 +++---- .../Arista-7060-CX32S/port_config.ini | 66 +++---- .../plugins/sfputil.py | 11 +- .../Arista-7260CX3-64/port_config.ini | 67 +++++++ .../sai.profile | 0 .../Arista-7260CX3-C64/port_config.ini | 67 ------- .../Arista-7260CX3-D108C8/port_config.ini | 121 ------------ .../Arista-7260CX3-D108C8/sai.profile | 1 - .../x86_64-arista_7260cx3_64/minigraph.xml | 4 +- .../plugins/sfputil.py | 14 +- .../x86_64-mlnx_msn2100-r0/plugins/sfputil.py | 70 ++----- .../x86_64-mlnx_msn2410-r0/plugins/sfputil.py | 70 ++----- .../x86_64-mlnx_msn2700-r0/plugins/sfputil.py | 70 ++----- .../x86_64-mlnx_msn2740-r0/plugins/sfputil.py | 70 ++----- dockers/docker-config-engine/Dockerfile.j2 | 2 +- dockers/docker-orchagent/Dockerfile.j2 | 1 - dockers/docker-orchagent/ports.json.j2 | 11 -- dockers/docker-orchagent/start.sh | 1 - dockers/docker-orchagent/swssconfig.sh | 2 +- platform/broadcom/sai.mk | 8 +- .../broadcom/sonic-platform-modules-arista | 2 +- platform/broadcom/sonic-platform-modules-dell | 2 +- platform/cavium/cavm-sai.mk | 2 +- platform/cavium/cavm-xpnet.mk | 2 +- sonic-slave/Dockerfile | 2 +- src/sonic-config-engine/minigraph.py | 17 -- .../tests/simple-sample-graph.xml | 62 ------- src/sonic-config-engine/tests/test_cfggen.py | 5 - src/sonic-linux-kernel | 2 +- src/sonic-sairedis | 2 +- src/sonic-swss | 2 +- 40 files changed, 320 insertions(+), 1274 deletions(-) delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/installer.conf delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py delete mode 100644 device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py create mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini rename device/arista/x86_64-arista_7260cx3_64/{Arista-7260CX3-C64 => Arista-7260CX3-64}/sai.profile (100%) delete mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini delete mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini delete mode 100644 device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile delete mode 100644 dockers/docker-orchagent/ports.json.j2 diff --git a/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini b/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini deleted file mode 100644 index 61325e1ec43c..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/port_config.ini +++ /dev/null @@ -1,74 +0,0 @@ -# name lanes alias -Ethernet0 13 tenGigE0 -Ethernet1 14 tenGigE1 -Ethernet2 15 tenGigE2 -Ethernet3 16 tenGigE3 -Ethernet4 21 tenGigE4 -Ethernet5 22 tenGigE5 -Ethernet6 23 tenGigE6 -Ethernet7 24 tenGigE7 -Ethernet8 25 tenGigE8 -Ethernet9 26 tenGigE9 -Ethernet10 27 tenGigE10 -Ethernet11 28 tenGigE11 -Ethernet12 29 tenGigE12 -Ethernet13 30 tenGigE13 -Ethernet14 31 tenGigE14 -Ethernet15 32 tenGigE15 -Ethernet16 45 tenGigE16 -Ethernet17 46 tenGigE17 -Ethernet18 47 tenGigE18 -Ethernet19 48 tenGigE19 -Ethernet20 49 tenGigE20 -Ethernet21 50 tenGigE21 -Ethernet22 51 tenGigE22 -Ethernet23 52 tenGigE23 -Ethernet24 53 tenGigE24 -Ethernet25 54 tenGigE25 -Ethernet26 55 tenGigE26 -Ethernet27 56 tenGigE27 -Ethernet28 57 tenGigE28 -Ethernet29 58 tenGigE29 -Ethernet30 59 tenGigE30 -Ethernet31 60 tenGigE31 -Ethernet32 61 tenGigE32 -Ethernet33 62 tenGigE33 -Ethernet34 63 tenGigE34 -Ethernet35 64 tenGigE35 -Ethernet36 65 tenGigE36 -Ethernet37 66 tenGigE37 -Ethernet38 67 tenGigE38 -Ethernet39 68 tenGigE39 -Ethernet40 69 tenGigE40 -Ethernet41 70 tenGigE41 -Ethernet42 71 tenGigE42 -Ethernet43 72 tenGigE43 -Ethernet44 73 tenGigE44 -Ethernet45 74 tenGigE45 -Ethernet46 75 tenGigE46 -Ethernet47 76 tenGigE47 -Ethernet48 97 tenGigE48 -Ethernet49 98 tenGigE49 -Ethernet50 99 tenGigE50 -Ethernet51 100 tenGigE51 -Ethernet52 101 tenGigE52 -Ethernet53 102 tenGigE53 -Ethernet54 103 tenGigE54 -Ethernet55 104 tenGigE55 -Ethernet56 81 tenGigE56 -Ethernet57 82 tenGigE57 -Ethernet58 83 tenGigE58 -Ethernet59 84 tenGigE59 -Ethernet60 105 tenGigE60 -Ethernet61 106 tenGigE61 -Ethernet62 107 tenGigE62 -Ethernet63 108 tenGigE63 -Ethernet64 109 tenGigE64 -Ethernet65 110 tenGigE65 -Ethernet66 111 tenGigE66 -Ethernet67 112 tenGigE67 -Ethernet68 77 tenGigE68 -Ethernet69 78 tenGigE69 -Ethernet70 79 tenGigE70 -Ethernet71 80 tenGigE71 - diff --git a/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile b/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile deleted file mode 100644 index 7fafa54db963..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/Accton-AS5712-54X/sai.profile +++ /dev/null @@ -1,2 +0,0 @@ -SAI_INIT_CONFIG_FILE=/etc/bcm/td2-as5712-72x10G.config.bcm - diff --git a/device/accton/x86_64-accton_as5712_54x-r0/installer.conf b/device/accton/x86_64-accton_as5712_54x-r0/installer.conf deleted file mode 100644 index 14404194ef53..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/installer.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONSOLE_PORT=0x2f8 -CONSOLE_DEV=1 -CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc deleted file mode 100644 index e27679db9ab0..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc +++ /dev/null @@ -1,163 +0,0 @@ -# LED setting for active -# ----------------------------------------------------------------------------- -# for as5712_54x (48xg+6qxg) -# -# on green - if link up -# off - if link down -# blink - if active -# ----------------------------------------------------------------------------- -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 - -led 0 stop -led 0 prog \ - 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ - 61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \ - D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \ - 06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \ - 96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \ - 04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \ - 0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00 -led 0 start - -led 1 stop -led 1 prog \ - 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ - 61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \ - 67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \ - 67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \ - 67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \ - D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \ - 63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \ - FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \ - 85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \ - A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \ - 57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00 -led 1 start - diff --git a/device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml b/device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml deleted file mode 100644 index 8d89f28b0d86..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/minigraph.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - OCPSCH0104001MS - 10.10.1.26 - switch1 - 10.10.1.25 - 1 - 10 - 3 - - - OCPSCH0104002MS - 10.10.2.26 - switch1 - 10.10.2.25 - 1 - 10 - 3 - - - - - 64536 - switch1 - - -
10.10.1.26
- - -
- -
10.10.2.26
- - -
-
- -
- - 64542 - OCPSCH0104001MS - - - - 64543 - OCPSCH0104002MS - - -
-
- - - - - - HostIP - Loopback0 - - 100.0.0.9/32 - - 100.0.0.9/32 - - - - - - - - switch1 - - - - - - Ethernet48 - 10.10.1.25/30 - - - - Ethernet52 - 10.10.2.25/30 - - - - - - - - - - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet24 - switch1 - Ethernet48 - - - 40000 - DeviceInterfaceLink - OCPSCH0104002MS - Ethernet24 - switch1 - Ethernet52 - - - - - switch1 - Accton-AS5712-54X - - - - - - - switch1 - - - DhcpResources - - - - - NtpResources - - 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org - - - SyslogResources - - - - - ErspanDestinationIpv4 - - 2.2.2.2 - - - - - - - switch1 - Accton-AS5712-54X -
diff --git a/device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py deleted file mode 100644 index 7681caafeef4..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/plugins/eeprom.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -try: - import exceptions - import binascii - import time - import optparse - import warnings - import os - import sys - from sonic_eeprom import eeprom_base - from sonic_eeprom import eeprom_tlvinfo - import subprocess -except ImportError, e: - raise ImportError (str(e) + "- required module not found") - -class board(eeprom_tlvinfo.TlvInfoDecoder): - _TLV_INFO_MAX_LEN = 256 - def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" - #Two i2c buses might get flipped order, check them both. - if not os.path.exists(self.eeprom_path): - self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" - super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py deleted file mode 100644 index 070b1da934cb..000000000000 --- a/device/accton/x86_64-accton_as5712_54x-r0/plugins/sfputil.py +++ /dev/null @@ -1,175 +0,0 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# - -try: - import time - from sonic_sfp.sfputilbase import SfpUtilBase -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) - - -class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" - - PORT_START = 0 - PORT_END = 31 - PORTS_IN_BLOCK = 32 - - EEPROM_OFFSET = 20 - - _port_to_eeprom_mapping = {} - - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return range(0, self.PORTS_IN_BLOCK + 1) - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping - - def __init__(self): - eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" - - for x in range(0, self.port_end + 1): - self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) - - SfpUtilBase.__init__(self) - - def get_presence(self, port_num): - # Check for invalid port_num - if port_num < self.port_start or port_num > self.port_end: - return False - - try: - reg_file = open("/sys/devices/platform/accton/qsfp_modprs") - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return False - - content = reg_file.readline().rstrip() - - # content is a string containing the hex representation of the register - reg_value = int(content, 16) - - # Mask off the bit corresponding to our port - mask = (1 << port_num) - - # ModPrsL is active low - if reg_value & mask == 0: - return True - - return False - - def get_low_power_mode(self, port_num): - # Check for invalid port_num - if port_num < self.port_start or port_num > self.port_end: - return False - - try: - reg_file = open("/sys/devices/platform/accton/qsfp_lpmode") - except IOError as e: - print "Error: unable to open file: %s" % str(e) - - content = reg_file.readline().rstrip() - - # content is a string containing the hex representation of the register - reg_value = int(content, 16) - - # Mask off the bit corresponding to our port - mask = (1 << port_num) - - # LPMode is active high - if reg_value & mask == 0: - return False - - return True - - def set_low_power_mode(self, port_num, lpmode): - # Check for invalid port_num - if port_num < self.port_start or port_num > self.port_end: - return False - - try: - reg_file = open("/sys/devices/platform/accton/qsfp_lpmode", "r+") - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return False - - content = reg_file.readline().rstrip() - - # content is a string containing the hex representation of the register - reg_value = int(content, 16) - - # Mask off the bit corresponding to our port - mask = (1 << port_num) - - # LPMode is active high; set or clear the bit accordingly - if lpmode is True: - reg_value = reg_value | mask - else: - reg_value = reg_value & ~mask - - # Convert our register value back to a hex string and write back - content = hex(reg_value) - - reg_file.seek(0) - reg_file.write(content) - reg_file.close() - - return True - - def reset(self, port_num): - QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/devices/platform/accton/qsfp_reset" - - # Check for invalid port_num - if port_num < self.port_start or port_num > self.port_end: - return False - - try: - reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return False - - content = reg_file.readline().rstrip() - - # File content is a string containing the hex representation of the register - reg_value = int(content, 16) - - # Mask off the bit corresponding to our port - mask = (1 << port_num) - - # ResetL is active low - reg_value = reg_value & ~mask - - # Convert our register value back to a hex string and write back - reg_file.seek(0) - reg_file.write(hex(reg_value)) - reg_file.close() - - # Sleep 1 second to allow it to settle - time.sleep(1) - - # Flip the bit back high and write back to the register to take port out of reset - try: - reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "w") - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return False - - reg_value = reg_value | mask - reg_file.seek(0) - reg_file.write(hex(reg_value)) - reg_file.close() - - return True diff --git a/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini b/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini index dea477b26152..28edbeccf224 100644 --- a/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini @@ -1,57 +1,57 @@ -# name lanes alias port -Ethernet0 125,126,127,128 Ethernet1/1 1 -Ethernet4 121,122,123,124 Ethernet2/1 2 -Ethernet8 13,14,15,16 Ethernet3/1 3 -Ethernet12 9,10,11,12 Ethernet4/1 4 -Ethernet16 17,18,19,20 Ethernet5/1 5 -Ethernet20 21,22,23,24 Ethernet6/1 6 -Ethernet24 25,26,27,28 Ethernet7/1 7 -Ethernet28 29,30,31,32 Ethernet8/1 8 -Ethernet32 37,38,39,40 Ethernet9/1 9 -Ethernet36 33,34,35,36 Ethernet10/1 10 -Ethernet40 45,46,47,48 Ethernet11/1 11 -Ethernet44 41,42,43,44 Ethernet12/1 12 -Ethernet48 53,54,55,56 Ethernet13/1 13 -Ethernet52 49,50,51,52 Ethernet14/1 14 -Ethernet56 69,70,71,72 Ethernet15/1 15 -Ethernet60 65,66,67,68 Ethernet16/1 16 -Ethernet64 77 Ethernet17/1 17 -Ethernet65 78 Ethernet17/2 17 -Ethernet66 79 Ethernet17/3 17 -Ethernet67 80 Ethernet17/4 17 -Ethernet68 73 Ethernet18/1 18 -Ethernet69 74 Ethernet18/2 18 -Ethernet70 75 Ethernet18/3 18 -Ethernet71 76 Ethernet18/4 18 -Ethernet72 93 Ethernet19/1 19 -Ethernet73 94 Ethernet19/2 19 -Ethernet74 95 Ethernet19/3 19 -Ethernet75 96 Ethernet19/4 19 -Ethernet76 89 Ethernet20/1 20 -Ethernet77 90 Ethernet20/2 20 -Ethernet78 91 Ethernet20/3 20 -Ethernet79 92 Ethernet20/4 20 -Ethernet80 101 Ethernet21/1 21 -Ethernet81 102 Ethernet21/2 21 -Ethernet82 103 Ethernet21/3 21 -Ethernet83 104 Ethernet21/4 21 -Ethernet84 97 Ethernet22/1 22 -Ethernet85 98 Ethernet22/2 22 -Ethernet86 99 Ethernet22/3 22 -Ethernet87 100 Ethernet22/4 22 -Ethernet88 109 Ethernet23/1 23 -Ethernet89 110 Ethernet23/2 23 -Ethernet90 111 Ethernet23/3 23 -Ethernet91 112 Ethernet23/4 23 -Ethernet92 105 Ethernet24/1 24 -Ethernet93 106 Ethernet24/2 24 -Ethernet94 107 Ethernet24/3 24 -Ethernet95 108 Ethernet24/4 24 -Ethernet96 61,62,63,64 Ethernet25 25 -Ethernet100 57,58,59,60 Ethernet26 26 -Ethernet104 81,82,83,84 Ethernet27 27 -Ethernet108 85,86,87,88 Ethernet28 28 -Ethernet112 117,118,119,120 Ethernet29 29 -Ethernet116 113,114,115,116 Ethernet30 30 -Ethernet120 5,6,7,8 Ethernet31 31 -Ethernet124 1,2,3,4 Ethernet32 32 +# name lanes alias +Ethernet0 125,126,127,128 Ethernet1/1 +Ethernet4 121,122,123,124 Ethernet2/1 +Ethernet8 13,14,15,16 Ethernet3/1 +Ethernet12 9,10,11,12 Ethernet4/1 +Ethernet16 17,18,19,20 Ethernet5/1 +Ethernet20 21,22,23,24 Ethernet6/1 +Ethernet24 25,26,27,28 Ethernet7/1 +Ethernet28 29,30,31,32 Ethernet8/1 +Ethernet32 37,38,39,40 Ethernet9/1 +Ethernet36 33,34,35,36 Ethernet10/1 +Ethernet40 45,46,47,48 Ethernet11/1 +Ethernet44 41,42,43,44 Ethernet12/1 +Ethernet48 53,54,55,56 Ethernet13/1 +Ethernet52 49,50,51,52 Ethernet14/1 +Ethernet56 69,70,71,72 Ethernet15/1 +Ethernet60 65,66,67,68 Ethernet16/1 +Ethernet64 77 Ethernet17/1 +Ethernet65 78 Ethernet17/2 +Ethernet66 79 Ethernet17/3 +Ethernet67 80 Ethernet17/4 +Ethernet68 73 Ethernet18/1 +Ethernet69 74 Ethernet18/2 +Ethernet70 75 Ethernet18/3 +Ethernet71 76 Ethernet18/4 +Ethernet72 93 Ethernet19/1 +Ethernet73 94 Ethernet19/2 +Ethernet74 95 Ethernet19/3 +Ethernet75 96 Ethernet19/4 +Ethernet76 89 Ethernet20/1 +Ethernet77 90 Ethernet20/2 +Ethernet78 91 Ethernet20/3 +Ethernet79 92 Ethernet20/4 +Ethernet80 101 Ethernet21/1 +Ethernet81 102 Ethernet21/2 +Ethernet82 103 Ethernet21/3 +Ethernet83 104 Ethernet21/4 +Ethernet84 97 Ethernet22/1 +Ethernet85 98 Ethernet22/2 +Ethernet86 99 Ethernet22/3 +Ethernet87 100 Ethernet22/4 +Ethernet88 109 Ethernet23/1 +Ethernet89 110 Ethernet23/2 +Ethernet90 111 Ethernet23/3 +Ethernet91 112 Ethernet23/4 +Ethernet92 105 Ethernet24/1 +Ethernet93 106 Ethernet24/2 +Ethernet94 107 Ethernet24/3 +Ethernet95 108 Ethernet24/4 +Ethernet96 61,62,63,64 Ethernet25 +Ethernet100 57,58,59,60 Ethernet26 +Ethernet104 81,82,83,84 Ethernet27 +Ethernet108 85,86,87,88 Ethernet28 +Ethernet112 117,118,119,120 Ethernet29 +Ethernet116 113,114,115,116 Ethernet30 +Ethernet120 5,6,7,8 Ethernet31 +Ethernet124 1,2,3,4 Ethernet32 diff --git a/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini b/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini index 32fa6885fa93..b9ab8854a2ec 100644 --- a/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias port -Ethernet0 125,126,127,128 Ethernet1/1 1 -Ethernet4 121,122,123,124 Ethernet2/1 2 -Ethernet8 13,14,15,16 Ethernet3/1 3 -Ethernet12 9,10,11,12 Ethernet4/1 4 -Ethernet16 17,18,19,20 Ethernet5/1 5 -Ethernet20 21,22,23,24 Ethernet6/1 6 -Ethernet24 25,26,27,28 Ethernet7/1 7 -Ethernet28 29,30,31,32 Ethernet8/1 8 -Ethernet32 37,38,39,40 Ethernet9/1 9 -Ethernet36 33,34,35,36 Ethernet10/1 10 -Ethernet40 45,46,47,48 Ethernet11/1 11 -Ethernet44 41,42,43,44 Ethernet12/1 12 -Ethernet48 53,54,55,56 Ethernet13/1 13 -Ethernet52 49,50,51,52 Ethernet14/1 14 -Ethernet56 69,70,71,72 Ethernet15/1 15 -Ethernet60 65,66,67,68 Ethernet16/1 16 -Ethernet64 77,78,79,80 Ethernet17/1 17 -Ethernet68 73,74,75,76 Ethernet18/1 18 -Ethernet72 93,94,95,96 Ethernet19/1 19 -Ethernet76 89,90,91,92 Ethernet20/1 20 -Ethernet80 101,102,103,104 Ethernet21/1 21 -Ethernet84 97,98,99,100 Ethernet22/1 22 -Ethernet88 109,110,111,112 Ethernet23/1 23 -Ethernet92 105,106,107,108 Ethernet24/1 24 -Ethernet96 61,62,63,64 Ethernet25 25 -Ethernet100 57,58,59,60 Ethernet26 26 -Ethernet104 81,82,83,84 Ethernet27 27 -Ethernet108 85,86,87,88 Ethernet28 28 -Ethernet112 117,118,119,120 Ethernet29 29 -Ethernet116 113,114,115,116 Ethernet30 30 -Ethernet120 5,6,7,8 Ethernet31 31 -Ethernet124 1,2,3,4 Ethernet32 32 +# name lanes alias +Ethernet0 125,126,127,128 Ethernet1/1 +Ethernet4 121,122,123,124 Ethernet2/1 +Ethernet8 13,14,15,16 Ethernet3/1 +Ethernet12 9,10,11,12 Ethernet4/1 +Ethernet16 17,18,19,20 Ethernet5/1 +Ethernet20 21,22,23,24 Ethernet6/1 +Ethernet24 25,26,27,28 Ethernet7/1 +Ethernet28 29,30,31,32 Ethernet8/1 +Ethernet32 37,38,39,40 Ethernet9/1 +Ethernet36 33,34,35,36 Ethernet10/1 +Ethernet40 45,46,47,48 Ethernet11/1 +Ethernet44 41,42,43,44 Ethernet12/1 +Ethernet48 53,54,55,56 Ethernet13/1 +Ethernet52 49,50,51,52 Ethernet14/1 +Ethernet56 69,70,71,72 Ethernet15/1 +Ethernet60 65,66,67,68 Ethernet16/1 +Ethernet64 77,78,79,80 Ethernet17/1 +Ethernet68 73,74,75,76 Ethernet18/1 +Ethernet72 93,94,95,96 Ethernet19/1 +Ethernet76 89,90,91,92 Ethernet20/1 +Ethernet80 101,102,103,104 Ethernet21/1 +Ethernet84 97,98,99,100 Ethernet22/1 +Ethernet88 109,110,111,112 Ethernet23/1 +Ethernet92 105,106,107,108 Ethernet24/1 +Ethernet96 61,62,63,64 Ethernet25 +Ethernet100 57,58,59,60 Ethernet26 +Ethernet104 81,82,83,84 Ethernet27 +Ethernet108 85,86,87,88 Ethernet28 +Ethernet112 117,118,119,120 Ethernet29 +Ethernet116 113,114,115,116 Ethernet30 +Ethernet120 5,6,7,8 Ethernet31 +Ethernet124 1,2,3,4 Ethernet32 diff --git a/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini b/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini index cb36404ac44f..b56d958499d4 100644 --- a/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias port -Ethernet0 9,10,11,12 Ethernet5/1 5 -Ethernet4 13,14,15,16 Ethernet6/1 6 -Ethernet8 17,18,19,20 Ethernet7/1 7 -Ethernet12 21,22,23,24 Ethernet8/1 8 -Ethernet16 29,30,31,32 Ethernet9/1 9 -Ethernet20 25,26,27,28 Ethernet10/1 10 -Ethernet24 33,34,35,36 Ethernet11/1 11 -Ethernet28 37,38,39,40 Ethernet12/1 12 -Ethernet32 45,46,47,48 Ethernet13/1 13 -Ethernet36 41,42,43,44 Ethernet14/1 14 -Ethernet40 49,50,51,52 Ethernet15/1 15 -Ethernet44 53,54,55,56 Ethernet16/1 16 -Ethernet48 69,70,71,72 Ethernet17/1 17 -Ethernet52 65,66,67,68 Ethernet18/1 18 -Ethernet56 73,74,75,76 Ethernet19/1 19 -Ethernet60 77,78,79,80 Ethernet20/1 20 -Ethernet64 93,94,95,96 Ethernet21/1 21 -Ethernet68 89,90,91,92 Ethernet22/1 22 -Ethernet72 97,98,99,100 Ethernet23/1 23 -Ethernet76 101,102,103,104 Ethernet24/1 24 -Ethernet80 109,110,111,112 Ethernet25/1 25 -Ethernet84 105,106,107,108 Ethernet26/1 26 -Ethernet88 121,122,123,124 Ethernet27/1 27 -Ethernet92 125,126,127,128 Ethernet28/1 28 -Ethernet96 61,62,63,64 Ethernet29 29 -Ethernet100 57,58,59,60 Ethernet30 30 -Ethernet104 81,82,83,84 Ethernet31 31 -Ethernet108 85,86,87,88 Ethernet32 32 -Ethernet112 117,118,119,120 Ethernet33 33 -Ethernet116 113,114,115,116 Ethernet34 34 -Ethernet120 1,2,3,4 Ethernet35 35 -Ethernet124 5,6,7,8 Ethernet36 36 +# name lanes alias +Ethernet0 9,10,11,12 Ethernet5/1 +Ethernet4 13,14,15,16 Ethernet6/1 +Ethernet8 17,18,19,20 Ethernet7/1 +Ethernet12 21,22,23,24 Ethernet8/1 +Ethernet16 29,30,31,32 Ethernet9/1 +Ethernet20 25,26,27,28 Ethernet10/1 +Ethernet24 33,34,35,36 Ethernet11/1 +Ethernet28 37,38,39,40 Ethernet12/1 +Ethernet32 45,46,47,48 Ethernet13/1 +Ethernet36 41,42,43,44 Ethernet14/1 +Ethernet40 49,50,51,52 Ethernet15/1 +Ethernet44 53,54,55,56 Ethernet16/1 +Ethernet48 69,70,71,72 Ethernet17/1 +Ethernet52 65,66,67,68 Ethernet18/1 +Ethernet56 73,74,75,76 Ethernet19/1 +Ethernet60 77,78,79,80 Ethernet20/1 +Ethernet64 93,94,95,96 Ethernet21/1 +Ethernet68 89,90,91,92 Ethernet22/1 +Ethernet72 97,98,99,100 Ethernet23/1 +Ethernet76 101,102,103,104 Ethernet24/1 +Ethernet80 109,110,111,112 Ethernet25/1 +Ethernet84 105,106,107,108 Ethernet26/1 +Ethernet88 121,122,123,124 Ethernet27/1 +Ethernet92 125,126,127,128 Ethernet28/1 +Ethernet96 61,62,63,64 Ethernet29 +Ethernet100 57,58,59,60 Ethernet30 +Ethernet104 81,82,83,84 Ethernet31 +Ethernet108 85,86,87,88 Ethernet32 +Ethernet112 117,118,119,120 Ethernet33 +Ethernet116 113,114,115,116 Ethernet34 +Ethernet120 1,2,3,4 Ethernet35 +Ethernet124 5,6,7,8 Ethernet36 diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini index c1dbcfabd9e3..414fb94efbc1 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias port -Ethernet0 33,34,35,36 Ethernet1/1 1 -Ethernet4 37,38,39,40 Ethernet2/1 2 -Ethernet8 41,42,43,44 Ethernet3/1 3 -Ethernet12 45,46,47,48 Ethernet4/1 4 -Ethernet16 49,50,51,52 Ethernet5/1 5 -Ethernet20 53,54,55,56 Ethernet6/1 6 -Ethernet24 57,58,59,60 Ethernet7/1 7 -Ethernet28 61,62,63,64 Ethernet8/1 8 -Ethernet32 65,66,67,68 Ethernet9/1 9 -Ethernet36 69,70,71,72 Ethernet10/1 10 -Ethernet40 73,74,75,76 Ethernet11/1 11 -Ethernet44 77,78,79,80 Ethernet12/1 12 -Ethernet48 81,82,83,84 Ethernet13/1 13 -Ethernet52 85,86,87,88 Ethernet14/1 14 -Ethernet56 89,90,91,92 Ethernet15/1 15 -Ethernet60 93,94,95,96 Ethernet16/1 16 -Ethernet64 97,98,99,100 Ethernet17/1 17 -Ethernet68 101,102,103,104 Ethernet18/1 18 -Ethernet72 105,106,107,108 Ethernet19/1 19 -Ethernet76 109,110,111,112 Ethernet20/1 20 -Ethernet80 113,114,115,116 Ethernet21/1 21 -Ethernet84 117,118,119,120 Ethernet22/1 22 -Ethernet88 121,122,123,124 Ethernet23/1 23 -Ethernet92 125,126,127,128 Ethernet24/1 24 -Ethernet96 1,2,3,4 Ethernet25/1 25 -Ethernet100 5,6,7,8 Ethernet26/1 26 -Ethernet104 9,10,11,12 Ethernet27/1 27 -Ethernet108 13,14,15,16 Ethernet28/1 28 -Ethernet112 17,18,19,20 Ethernet29/1 29 -Ethernet116 21,22,23,24 Ethernet30/1 30 -Ethernet120 25,26,27,28 Ethernet31/1 31 -Ethernet124 29,30,31,32 Ethernet32/1 32 +# name lanes alias +Ethernet0 33,34,35,36 Ethernet1/1 +Ethernet4 37,38,39,40 Ethernet2/1 +Ethernet8 41,42,43,44 Ethernet3/1 +Ethernet12 45,46,47,48 Ethernet4/1 +Ethernet16 49,50,51,52 Ethernet5/1 +Ethernet20 53,54,55,56 Ethernet6/1 +Ethernet24 57,58,59,60 Ethernet7/1 +Ethernet28 61,62,63,64 Ethernet8/1 +Ethernet32 65,66,67,68 Ethernet9/1 +Ethernet36 69,70,71,72 Ethernet10/1 +Ethernet40 73,74,75,76 Ethernet11/1 +Ethernet44 77,78,79,80 Ethernet12/1 +Ethernet48 81,82,83,84 Ethernet13/1 +Ethernet52 85,86,87,88 Ethernet14/1 +Ethernet56 89,90,91,92 Ethernet15/1 +Ethernet60 93,94,95,96 Ethernet16/1 +Ethernet64 97,98,99,100 Ethernet17/1 +Ethernet68 101,102,103,104 Ethernet18/1 +Ethernet72 105,106,107,108 Ethernet19/1 +Ethernet76 109,110,111,112 Ethernet20/1 +Ethernet80 113,114,115,116 Ethernet21/1 +Ethernet84 117,118,119,120 Ethernet22/1 +Ethernet88 121,122,123,124 Ethernet23/1 +Ethernet92 125,126,127,128 Ethernet24/1 +Ethernet96 1,2,3,4 Ethernet25/1 +Ethernet100 5,6,7,8 Ethernet26/1 +Ethernet104 9,10,11,12 Ethernet27/1 +Ethernet108 13,14,15,16 Ethernet28/1 +Ethernet112 17,18,19,20 Ethernet29/1 +Ethernet116 21,22,23,24 Ethernet30/1 +Ethernet120 25,26,27,28 Ethernet31/1 +Ethernet124 29,30,31,32 Ethernet32/1 diff --git a/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py b/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py index 9a6d770d460b..b85e0f53653e 100644 --- a/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py +++ b/device/arista/x86_64-arista_7060_cx32s/plugins/sfputil.py @@ -1,12 +1,9 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# +#!/usr/bin/env python try: import arista.utils.sonic_sfputil as arista_sfputil -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) +except ImportError, e: + raise ImportError (str(e) + "- required module not found") -SfpUtil = arista_sfputil.getSfpUtil() +sfputil = arista_sfputil.getSfpUtil() diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini new file mode 100644 index 000000000000..c0213576d087 --- /dev/null +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/port_config.ini @@ -0,0 +1,67 @@ +# name lanes alias port +Ethernet0 77,78,79,80 Ethernet1/1 1 +Ethernet4 65,66,67,68 Ethernet2/1 2 +Ethernet8 85,86,87,88 Ethernet3/1 3 +Ethernet12 89,90,91,92 Ethernet4/1 4 +Ethernet16 109,110,111,112 Ethernet5/1 5 +Ethernet20 97,98,99,100 Ethernet6/1 6 +Ethernet24 117,118,119,120 Ethernet7/1 7 +Ethernet28 5,6,7,8 Ethernet8/1 8 +Ethernet32 17,18,19,20 Ethernet9/1 9 +Ethernet36 13,14,15,16 Ethernet10/1 10 +Ethernet40 29,30,31,32 Ethernet11/1 11 +Ethernet44 37,38,39,40 Ethernet12/1 12 +Ethernet48 49,50,51,52 Ethernet13/1 13 +Ethernet52 45,46,47,48 Ethernet14/1 14 +Ethernet56 61,62,63,64 Ethernet15/1 15 +Ethernet60 121,122,123,124 Ethernet16/1 16 +Ethernet64 193,194,195,196 Ethernet17/1 17 +Ethernet68 133,134,135,136 Ethernet18/1 18 +Ethernet72 205,206,207,208 Ethernet19/1 19 +Ethernet76 213,214,215,216 Ethernet20/1 20 +Ethernet80 225,226,227,228 Ethernet21/1 21 +Ethernet84 221,222,223,224 Ethernet22/1 22 +Ethernet88 237,238,239,240 Ethernet23/1 23 +Ethernet92 245,246,247,248 Ethernet24/1 24 +Ethernet96 141,142,143,144 Ethernet25/1 25 +Ethernet100 249,250,251,252 Ethernet26/1 26 +Ethernet104 149,150,151,152 Ethernet27/1 27 +Ethernet108 153,154,155,156 Ethernet28/1 28 +Ethernet112 173,174,175,176 Ethernet29/1 29 +Ethernet116 161,162,163,164 Ethernet30/1 30 +Ethernet120 181,182,183,184 Ethernet31/1 31 +Ethernet124 185,186,187,188 Ethernet32/1 32 +Ethernet128 69,70,71,72 Ethernet33/1 33 +Ethernet132 73,74,75,76 Ethernet34/1 34 +Ethernet136 93,94,95,96 Ethernet35/1 35 +Ethernet140 81,82,83,84 Ethernet36/1 36 +Ethernet144 101,102,103,104 Ethernet37/1 37 +Ethernet148 105,106,107,108 Ethernet38/1 38 +Ethernet152 1,2,3,4 Ethernet39/1 39 +Ethernet156 113,114,115,116 Ethernet40/1 40 +Ethernet160 9,10,11,12 Ethernet41/1 41 +Ethernet164 21,22,23,24 Ethernet42/1 42 +Ethernet168 33,34,35,36 Ethernet43/1 43 +Ethernet172 25,26,27,28 Ethernet44/1 44 +Ethernet176 41,42,43,44 Ethernet45/1 45 +Ethernet180 53,54,55,56 Ethernet46/1 46 +Ethernet184 125,126,127,128 Ethernet47/1 47 +Ethernet188 57,58,59,60 Ethernet48/1 48 +Ethernet192 129,130,131,132 Ethernet49/1 49 +Ethernet196 197,198,199,200 Ethernet50/1 50 +Ethernet200 209,210,211,212 Ethernet51/1 51 +Ethernet204 201,202,203,204 Ethernet52/1 52 +Ethernet208 217,218,219,220 Ethernet53/1 53 +Ethernet212 229,230,231,232 Ethernet54/1 54 +Ethernet216 241,242,243,244 Ethernet55/1 55 +Ethernet220 233,234,235,236 Ethernet56/1 56 +Ethernet224 253,254,255,256 Ethernet57/1 57 +Ethernet228 137,138,139,140 Ethernet58/1 58 +Ethernet232 157,158,159,160 Ethernet59/1 59 +Ethernet236 145,146,147,148 Ethernet60/1 60 +Ethernet240 165,166,167,168 Ethernet61/1 61 +Ethernet244 169,170,171,172 Ethernet62/1 62 +Ethernet248 189,190,191,192 Ethernet63/1 63 +Ethernet252 177,178,179,180 Ethernet64/1 64 +Ethernet256 257 Ethernet65 65 +Ethernet260 259 Ethernet66 66 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/sai.profile b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/sai.profile similarity index 100% rename from device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/sai.profile rename to device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-64/sai.profile diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini deleted file mode 100644 index 4f073e46dce3..000000000000 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini +++ /dev/null @@ -1,67 +0,0 @@ -# name lanes alias port -Ethernet0 77,78,79,80 Ethernet1/1 1 -Ethernet4 65,66,67,68 Ethernet2/1 2 -Ethernet8 85,86,87,88 Ethernet3/1 3 -Ethernet12 89,90,91,92 Ethernet4/1 4 -Ethernet16 109,110,111,112 Ethernet5/1 5 -Ethernet20 97,98,99,100 Ethernet6/1 6 -Ethernet24 5,6,7,8 Ethernet7/1 7 -Ethernet28 13,14,15,16 Ethernet8/1 8 -Ethernet32 25,26,27,28 Ethernet9/1 9 -Ethernet36 21,22,23,24 Ethernet10/1 10 -Ethernet40 37,38,39,40 Ethernet11/1 11 -Ethernet44 45,46,47,48 Ethernet12/1 12 -Ethernet48 57,58,59,60 Ethernet13/1 13 -Ethernet52 53,54,55,56 Ethernet14/1 14 -Ethernet56 117,118,119,120 Ethernet15/1 15 -Ethernet60 121,122,123,124 Ethernet16/1 16 -Ethernet64 141,142,143,144 Ethernet17/1 17 -Ethernet68 133,134,135,136 Ethernet18/1 18 -Ethernet72 197,198,199,200 Ethernet19/1 19 -Ethernet76 205,206,207,208 Ethernet20/1 20 -Ethernet80 217,218,219,220 Ethernet21/1 21 -Ethernet84 213,214,215,216 Ethernet22/1 22 -Ethernet88 229,230,231,232 Ethernet23/1 23 -Ethernet92 237,238,239,240 Ethernet24/1 24 -Ethernet96 249,250,251,252 Ethernet25/1 25 -Ethernet100 245,246,247,248 Ethernet26/1 26 -Ethernet104 149,150,151,152 Ethernet27/1 27 -Ethernet108 153,154,155,156 Ethernet28/1 28 -Ethernet112 173,174,175,176 Ethernet29/1 29 -Ethernet116 161,162,163,164 Ethernet30/1 30 -Ethernet120 181,182,183,184 Ethernet31/1 31 -Ethernet124 185,186,187,188 Ethernet32/1 32 -Ethernet128 69,70,71,72 Ethernet33/1 33 -Ethernet132 73,74,75,76 Ethernet34/1 34 -Ethernet136 93,94,95,96 Ethernet35/1 35 -Ethernet140 81,82,83,84 Ethernet36/1 36 -Ethernet144 101,102,103,104 Ethernet37/1 37 -Ethernet148 105,106,107,108 Ethernet38/1 38 -Ethernet152 9,10,11,12 Ethernet39/1 39 -Ethernet156 1,2,3,4 Ethernet40/1 40 -Ethernet160 17,18,19,20 Ethernet41/1 41 -Ethernet164 29,30,31,32 Ethernet42/1 42 -Ethernet168 41,42,43,44 Ethernet43/1 43 -Ethernet172 33,34,35,36 Ethernet44/1 44 -Ethernet176 49,50,51,52 Ethernet45/1 45 -Ethernet180 61,62,63,64 Ethernet46/1 46 -Ethernet184 125,126,127,128 Ethernet47/1 47 -Ethernet188 113,114,115,116 Ethernet48/1 48 -Ethernet192 129,130,131,132 Ethernet49/1 49 -Ethernet196 137,138,139,140 Ethernet50/1 50 -Ethernet200 201,202,203,204 Ethernet51/1 51 -Ethernet204 193,194,195,196 Ethernet52/1 52 -Ethernet208 209,210,211,212 Ethernet53/1 53 -Ethernet212 221,222,223,224 Ethernet54/1 54 -Ethernet216 233,234,235,236 Ethernet55/1 55 -Ethernet220 225,226,227,228 Ethernet56/1 56 -Ethernet224 241,242,243,244 Ethernet57/1 57 -Ethernet228 253,254,255,256 Ethernet58/1 58 -Ethernet232 157,158,159,160 Ethernet59/1 59 -Ethernet236 145,146,147,148 Ethernet60/1 60 -Ethernet240 165,166,167,168 Ethernet61/1 61 -Ethernet244 169,170,171,172 Ethernet62/1 62 -Ethernet248 189,190,191,192 Ethernet63/1 63 -Ethernet252 177,178,179,180 Ethernet64/1 64 -Ethernet256 257 Ethernet65 65 -Ethernet260 259 Ethernet66 66 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini deleted file mode 100644 index b06d1c7575d4..000000000000 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini +++ /dev/null @@ -1,121 +0,0 @@ -# name lanes alias port -Ethernet0 77,78 Ethernet1/1 1 -Ethernet2 79,80 Ethernet1/3 2 -Ethernet4 65,66 Ethernet2/1 3 -Ethernet6 67,68 Ethernet2/3 4 -Ethernet8 85,86 Ethernet3/1 5 -Ethernet10 87,88 Ethernet3/3 6 -Ethernet12 89,90 Ethernet4/1 7 -Ethernet14 91,92 Ethernet4/3 8 -Ethernet16 109,110 Ethernet5/1 9 -Ethernet18 111,112 Ethernet5/3 10 -Ethernet20 97,98 Ethernet6/1 11 -Ethernet22 99,100 Ethernet6/3 12 -Ethernet24 5,6 Ethernet7/1 13 -Ethernet26 7,8 Ethernet7/3 14 -Ethernet28 13,14 Ethernet8/1 15 -Ethernet30 15,16 Ethernet8/3 16 -Ethernet32 25,26 Ethernet9/1 17 -Ethernet34 27,28 Ethernet9/3 18 -Ethernet36 21,22 Ethernet10/1 19 -Ethernet38 23,24 Ethernet10/3 20 -Ethernet40 37,38 Ethernet11/1 21 -Ethernet42 39,40 Ethernet11/3 22 -Ethernet44 45,46 Ethernet12/1 23 -Ethernet46 47,48 Ethernet12/3 24 -Ethernet48 57,58 Ethernet13/1 25 -Ethernet50 59,60 Ethernet13/3 26 -Ethernet52 53,54 Ethernet14/1 27 -Ethernet54 55,56 Ethernet14/3 28 -Ethernet56 117,118 Ethernet15/1 29 -Ethernet58 119,120 Ethernet15/3 30 -Ethernet60 121,122 Ethernet16/1 31 -Ethernet62 123,124 Ethernet16/3 32 -Ethernet64 141,142 Ethernet17/1 33 -Ethernet66 143,144 Ethernet17/3 34 -Ethernet68 133,134,135,136 Ethernet18/1 35 -Ethernet72 197,198 Ethernet19/1 36 -Ethernet74 199,200 Ethernet19/3 37 -Ethernet76 205,206,207,208 Ethernet20/1 38 -Ethernet80 217,218 Ethernet21/1 39 -Ethernet82 219,220 Ethernet21/3 40 -Ethernet84 213,214 Ethernet22/1 41 -Ethernet86 215,216 Ethernet22/3 42 -Ethernet88 229,230 Ethernet23/1 43 -Ethernet90 231,232 Ethernet23/3 44 -Ethernet92 237,238 Ethernet24/1 45 -Ethernet94 239,240 Ethernet24/3 46 -Ethernet96 249,250 Ethernet25/1 47 -Ethernet98 251,252 Ethernet25/3 48 -Ethernet100 245,246 Ethernet26/1 49 -Ethernet102 247,248 Ethernet26/3 50 -Ethernet104 149,150 Ethernet27/1 51 -Ethernet106 151,152 Ethernet27/3 52 -Ethernet108 153,154 Ethernet28/1 53 -Ethernet110 155,156 Ethernet28/3 54 -Ethernet112 173,174 Ethernet29/1 55 -Ethernet114 175,176 Ethernet29/3 56 -Ethernet116 161,162 Ethernet30/1 57 -Ethernet118 163,164 Ethernet30/3 58 -Ethernet120 181,182 Ethernet31/1 59 -Ethernet122 183,184 Ethernet31/3 60 -Ethernet124 185,186 Ethernet32/1 61 -Ethernet126 187,188 Ethernet32/3 62 -Ethernet128 69,70 Ethernet33/1 63 -Ethernet130 71,72 Ethernet33/3 64 -Ethernet132 73,74 Ethernet34/1 65 -Ethernet134 75,76 Ethernet34/3 66 -Ethernet136 93,94 Ethernet35/1 67 -Ethernet138 95,96 Ethernet35/3 68 -Ethernet140 81,82 Ethernet36/1 69 -Ethernet142 83,84 Ethernet36/3 70 -Ethernet144 101,102 Ethernet37/1 71 -Ethernet146 103,104 Ethernet37/3 72 -Ethernet148 105,106 Ethernet38/1 73 -Ethernet150 107,108 Ethernet38/3 74 -Ethernet152 9,10 Ethernet39/1 75 -Ethernet154 11,12 Ethernet39/3 76 -Ethernet156 1,2 Ethernet40/1 77 -Ethernet158 3,4 Ethernet40/3 78 -Ethernet160 17,18 Ethernet41/1 79 -Ethernet162 19,20 Ethernet41/3 80 -Ethernet164 29,30 Ethernet42/1 81 -Ethernet166 31,32 Ethernet42/1 82 -Ethernet168 41,42 Ethernet43/1 83 -Ethernet170 43,44 Ethernet43/3 84 -Ethernet172 33,34 Ethernet44/1 85 -Ethernet174 35,36 Ethernet44/3 86 -Ethernet176 49,50,51,52 Ethernet45/1 87 -Ethernet180 61,62,63,64 Ethernet46/1 88 -Ethernet184 125,126,127,128 Ethernet47/1 89 -Ethernet188 113,114,115,116 Ethernet48/1 90 -Ethernet192 129,130,131,132 Ethernet49/1 91 -Ethernet196 137,138,139,140 Ethernet50/1 92 -Ethernet200 201,202,203,204 Ethernet51/1 93 -Ethernet204 193,194,195,196 Ethernet52/1 94 -Ethernet208 209,210 Ethernet53/1 95 -Ethernet210 211,212 Ethernet53/3 96 -Ethernet212 221,222 Ethernet54/1 97 -Ethernet214 223,224 Ethernet54/3 98 -Ethernet216 233,234 Ethernet55/1 99 -Ethernet218 235,236 Ethernet55/3 100 -Ethernet220 225,226 Ethernet56/1 101 -Ethernet222 227,228 Ethernet56/3 102 -Ethernet224 241,242 Ethernet57/1 103 -Ethernet226 243,244 Ethernet57/3 104 -Ethernet228 253,254 Ethernet58/1 105 -Ethernet230 255,256 Ethernet58/3 106 -Ethernet232 157,158 Ethernet59/1 107 -Ethernet234 159,160 Ethernet59/3 108 -Ethernet236 145,146 Ethernet60/1 109 -Ethernet238 147,148 Ethernet60/3 110 -Ethernet240 165,166 Ethernet61/1 111 -Ethernet242 167,168 Ethernet61/3 112 -Ethernet244 169,170 Ethernet62/1 113 -Ethernet246 171,172 Ethernet62/3 114 -Ethernet248 189,190 Ethernet63/1 115 -Ethernet250 191,192 Ethernet63/3 116 -Ethernet252 177,178 Ethernet64/1 117 -Ethernet254 179,180 Ethernet64/3 118 -Ethernet256 257 Ethernet257 119 -Ethernet260 259 Ethernet259 120 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile deleted file mode 100644 index 030527daf9c0..000000000000 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/sai.profile +++ /dev/null @@ -1 +0,0 @@ -SAI_INIT_CONFIG_FILE=/etc/bcm/th2-a7260cx3-64-108x50G+10x100G.config.bcm diff --git a/device/arista/x86_64-arista_7260cx3_64/minigraph.xml b/device/arista/x86_64-arista_7260cx3_64/minigraph.xml index 2c632dacc471..957b60822ba8 100644 --- a/device/arista/x86_64-arista_7260cx3_64/minigraph.xml +++ b/device/arista/x86_64-arista_7260cx3_64/minigraph.xml @@ -809,7 +809,7 @@ sonic - Arista-7260CX3-C64 + Arista-7260CX3-64 @@ -844,5 +844,5 @@ sonic - Arista-7260CX3-C64 + Arista-7260CX3-64 diff --git a/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py b/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py index 9a6d770d460b..ce60de2b384d 100644 --- a/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py +++ b/device/arista/x86_64-arista_7260cx3_64/plugins/sfputil.py @@ -1,12 +1,8 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# +#!/usr/bin/env python try: - import arista.utils.sonic_sfputil as arista_sfputil -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) + import arista.utils.sonic_sfputil as arista_sfputil +except ImportError, e: + raise ImportError (str(e) + "- required module not found") - -SfpUtil = arista_sfputil.getSfpUtil() +sfputil = arista_sfputil.getSfpUtil() diff --git a/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py index ce0adde71a15..c6628e66e419 100644 --- a/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2100-r0/plugins/sfputil.py @@ -1,62 +1,28 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# +#! /usr/bin/python try: - import time - from sonic_sfp.sfputilbase import SfpUtilBase -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) + from sonic_sfp.sfputilbase import sfputilbase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") -class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" +class sfputil(sfputilbase): + """Platform specific sfputil class""" - PORT_START = 0 - PORT_END = 15 - PORTS_IN_BLOCK = 16 + port_start = 0 + port_end = 15 + ports_in_block = 16 - EEPROM_OFFSET = 1 + eeprom_offset = 1 - _port_to_eeprom_mapping = {} + port_to_eeprom_mapping = {} - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return range(0, self.PORTS_IN_BLOCK + 1) - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping - - def __init__(self): - eeprom_path = "/bsp/qsfp/qsfp{0}" + _qsfp_ports = range(0, ports_in_block + 1) + def __init__(self, port_num): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) - - SfpUtilBase.__init__(self) - - def get_presence(self, port_num): - - raise NotImplementedError - - def get_low_power_mode(self, port_num): - - raise NotImplementedError - - def set_low_power_mode(self, port_num, lpmode): - - raise NotImplementedError - - def reset(self, port_num): - - raise NotImplementedError + self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) + sfputilbase.__init__(self, port_num) + diff --git a/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py index db71cb423503..9d4474ac1ec9 100644 --- a/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py @@ -1,62 +1,28 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# +#! /usr/bin/python try: - import time - from sonic_sfp.sfputilbase import SfpUtilBase -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) + from sonic_sfp.sfputilbase import sfputilbase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") -class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" +class sfputil(sfputilbase): + """Platform specific sfputil class""" - PORT_START = 0 - PORT_END = 55 - PORTS_IN_BLOCK = 56 + port_start = 0 + port_end = 55 + ports_in_block = 56 - EEPROM_OFFSET = 1 + eeprom_offset = 1 - _port_to_eeprom_mapping = {} + port_to_eeprom_mapping = {} - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return range(0, self.PORTS_IN_BLOCK + 1) - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping - - def __init__(self): - eeprom_path = "/bsp/qsfp/qsfp{0}" + _qsfp_ports = range(0, ports_in_block + 1) + def __init__(self, port_num): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) - - SfpUtilBase.__init__(self) - - def get_presence(self, port_num): - - raise NotImplementedError - - def get_low_power_mode(self, port_num): - - raise NotImplementedError - - def set_low_power_mode(self, port_num, lpmode): - - raise NotImplementedError - - def reset(self, port_num): - - raise NotImplementedError + self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) + sfputilbase.__init__(self, port_num) + diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py index b746af219917..04e9a4eff85e 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py @@ -1,62 +1,28 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# +#! /usr/bin/python try: - import time - from sonic_sfp.sfputilbase import SfpUtilBase -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) + from sonic_sfp.sfputilbase import sfputilbase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") -class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" +class sfputil(sfputilbase): + """Platform specific sfputil class""" - PORT_START = 0 - PORT_END = 31 - PORTS_IN_BLOCK = 32 + port_start = 0 + port_end = 31 + ports_in_block = 32 - EEPROM_OFFSET = 1 + eeprom_offset = 1 - _port_to_eeprom_mapping = {} + port_to_eeprom_mapping = {} - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return range(0, self.PORTS_IN_BLOCK + 1) - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping - - def __init__(self): - eeprom_path = "/bsp/qsfp/qsfp{0}" + _qsfp_ports = range(0, ports_in_block + 1) + def __init__(self, port_num): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) - - SfpUtilBase.__init__(self) - - def get_presence(self, port_num): - - raise NotImplementedError - - def get_low_power_mode(self, port_num): - - raise NotImplementedError - - def set_low_power_mode(self, port_num, lpmode): - - raise NotImplementedError - - def reset(self, port_num): - - raise NotImplementedError + self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) + sfputilbase.__init__(self, port_num) + diff --git a/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py index b746af219917..04e9a4eff85e 100644 --- a/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py @@ -1,62 +1,28 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# +#! /usr/bin/python try: - import time - from sonic_sfp.sfputilbase import SfpUtilBase -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) + from sonic_sfp.sfputilbase import sfputilbase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") -class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" +class sfputil(sfputilbase): + """Platform specific sfputil class""" - PORT_START = 0 - PORT_END = 31 - PORTS_IN_BLOCK = 32 + port_start = 0 + port_end = 31 + ports_in_block = 32 - EEPROM_OFFSET = 1 + eeprom_offset = 1 - _port_to_eeprom_mapping = {} + port_to_eeprom_mapping = {} - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return range(0, self.PORTS_IN_BLOCK + 1) - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping - - def __init__(self): - eeprom_path = "/bsp/qsfp/qsfp{0}" + _qsfp_ports = range(0, ports_in_block + 1) + def __init__(self, port_num): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/bsp/qsfp/qsfp{0}' for x in range(0, self.port_end + 1): - self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) - - SfpUtilBase.__init__(self) - - def get_presence(self, port_num): - - raise NotImplementedError - - def get_low_power_mode(self, port_num): - - raise NotImplementedError - - def set_low_power_mode(self, port_num, lpmode): - - raise NotImplementedError - - def reset(self, port_num): - - raise NotImplementedError + self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) + sfputilbase.__init__(self, port_num) + diff --git a/dockers/docker-config-engine/Dockerfile.j2 b/dockers/docker-config-engine/Dockerfile.j2 index b4d924bddfc3..68555d44779b 100644 --- a/dockers/docker-config-engine/Dockerfile.j2 +++ b/dockers/docker-config-engine/Dockerfile.j2 @@ -10,7 +10,7 @@ RUN apt-get install -y python-lxml python-yaml python-bitarray python-pip python RUN pip install --upgrade pip -RUN pip install netaddr ipaddr jinja2 pyangbind==0.5.10 +RUN pip install netaddr ipaddr jinja2 pyangbind {% if docker_config_engine_debs.strip() %} COPY \ diff --git a/dockers/docker-orchagent/Dockerfile.j2 b/dockers/docker-orchagent/Dockerfile.j2 index 587d8f4db2ee..73fb087401ab 100755 --- a/dockers/docker-orchagent/Dockerfile.j2 +++ b/dockers/docker-orchagent/Dockerfile.j2 @@ -30,6 +30,5 @@ COPY ["arp_update", "start.sh", "orchagent.sh", "swssconfig.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["ipinip.json.j2", "/usr/share/sonic/templates/"] COPY ["mirror.json.j2", "/usr/share/sonic/templates/"] -COPY ["ports.json.j2", "/usr/share/sonic/templates/"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-orchagent/ports.json.j2 b/dockers/docker-orchagent/ports.json.j2 deleted file mode 100644 index f59ee993eead..000000000000 --- a/dockers/docker-orchagent/ports.json.j2 +++ /dev/null @@ -1,11 +0,0 @@ -[ -{% for interface in ethernet_interfaces %} - { - "PORT_TABLE:{{ interface['name'] }}": { - "speed": "{{ interface['speed'] }}" - }, - "OP": "SET" - }{% if not loop.last %},{% endif %} - -{% endfor %} -] diff --git a/dockers/docker-orchagent/start.sh b/dockers/docker-orchagent/start.sh index 5f961a8bd294..40ef66441c02 100755 --- a/dockers/docker-orchagent/start.sh +++ b/dockers/docker-orchagent/start.sh @@ -4,7 +4,6 @@ mkdir -p /etc/swss/config.d/ sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/mirror.json.j2 > /etc/swss/config.d/mirror.json -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json export platform=`sonic-cfggen -m /etc/sonic/minigraph.xml -v platform` diff --git a/dockers/docker-orchagent/swssconfig.sh b/dockers/docker-orchagent/swssconfig.sh index 2530aca06bb3..768417779e2d 100755 --- a/dockers/docker-orchagent/swssconfig.sh +++ b/dockers/docker-orchagent/swssconfig.sh @@ -38,7 +38,7 @@ fast_reboot HWSKU=`sonic-cfggen -m /etc/sonic/minigraph.xml -v minigraph_hwsku` -SWSSCONFIG_ARGS="00-copp.config.json ipinip.json mirror.json ports.json " +SWSSCONFIG_ARGS="00-copp.config.json ipinip.json mirror.json " if [ "$HWSKU" == "Force10-S6000" ]; then SWSSCONFIG_ARGS+="td2.32ports.buffers.json td2.32ports.qos.json " diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index eaf188485fed..ec7a34253075 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_2.1.5.1-17_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_2.1.5.1-17_amd64.deb?sv=2015-04-05&sr=b&sig=6sJ4dd%2FF1hqStNQk5Z6d%2BYQGRZxLDihXRl60EeN7agc%3D&se=2031-05-02T09%3A37%3A54Z&sp=r" +BRCM_SAI = libsaibcm_2.1.5.1-16-20170712202323.49_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_2.1.5.1-16-20170712202323.49_amd64.deb?sv=2015-04-05&sr=b&sig=jsPXiAoSyKqZ1SmiyeEj73W8tRlri8ysExnWvc%2BWSi4%3D&se=2031-03-21T22%3A49%3A32Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_2.1.5.1-17_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_2.1.5.1-16-20170712202323.49_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_2.1.5.1-17_amd64.deb?sv=2015-04-05&sr=b&sig=syV0rie0L2Dn4lhmndCTyCTgXQv8DPoWD3IxtlSdeNo%3D&se=2031-05-02T09%3A37%3A18Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_2.1.5.1-16-20170712202323.49_amd64.deb?sv=2015-04-05&sr=b&sig=azYZkCi%2FFGS4eELKhIozOok3qimfH%2FjdXlz%2BS2MRBco%3D&se=2031-03-21T22%3A49%3A57Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV) $(BRCM_SAI)_DEPENDS += $(BRCM_OPENNSL) diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 7c505290bb26..51bbe2cd86af 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 7c505290bb26babdef604a377e71b3df702897a8 +Subproject commit 51bbe2cd86af7df20b27e0cd1f02c2ad08ab2f03 diff --git a/platform/broadcom/sonic-platform-modules-dell b/platform/broadcom/sonic-platform-modules-dell index 5ab014c0d4f9..6cff8248fa8c 160000 --- a/platform/broadcom/sonic-platform-modules-dell +++ b/platform/broadcom/sonic-platform-modules-dell @@ -1 +1 @@ -Subproject commit 5ab014c0d4f9ad71d7791e7d4da0645d2b2d493b +Subproject commit 6cff8248fa8c772a077bf3dcb5c86a376357f261 diff --git a/platform/cavium/cavm-sai.mk b/platform/cavium/cavm-sai.mk index 0008135729c5..c52c4960b9d6 100644 --- a/platform/cavium/cavm-sai.mk +++ b/platform/cavium/cavm-sai.mk @@ -1,6 +1,6 @@ # Cavium SAI -CAVM_SAI_GITHUB = https://github.com/XPliant/OpenXPS/raw/13a7eaf10f523e7887964ca235f19095fcc88537/SAI/cavm-sai/ +CAVM_SAI_GITHUB = https://github.com/XPliant/OpenXPS/raw/eedd0b8bb7e7a09602a24418a462a5c10792a145/SAI/cavm-sai/ CAVM_LIBSAI = libsai.deb CAVM_SAI = sai.deb diff --git a/platform/cavium/cavm-xpnet.mk b/platform/cavium/cavm-xpnet.mk index ed86558a36ae..613fa9433564 100644 --- a/platform/cavium/cavm-xpnet.mk +++ b/platform/cavium/cavm-xpnet.mk @@ -1,4 +1,4 @@ -CAVM_SAI_URL = https://github.com/XPliant/OpenXPS/raw/c26aea6a7098936ab3692e148238d73fa8962585/SAI +CAVM_SAI_URL = https://github.com/XPliant/OpenXPS/raw/092461a1cf57a11132fbf8e74fa79bab3ab00f2a/SAI CAVM_XPNET_DEB = xp80-Pcie-Endpoint.deb $(CAVM_XPNET_DEB)_URL = $(CAVM_SAI_URL)/netdev/$(CAVM_XPNET_DEB) diff --git a/sonic-slave/Dockerfile b/sonic-slave/Dockerfile index f194bf604caa..826a7129a7e0 100644 --- a/sonic-slave/Dockerfile +++ b/sonic-slave/Dockerfile @@ -221,7 +221,7 @@ RUN pip install \ RUN pip install j2cli # For sonic config engine testing -RUN pip install pyangbind==0.5.10 +RUN pip install pyangbind # For supervisor build RUN pip install meld3 mock diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index c0b2e6550a9f..a8bd445ebb20 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -330,19 +330,6 @@ def parse_meta(meta, hname): deployment_id = value return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id -def parse_deviceinfo(meta, hwsku): - ethernet_interfaces = [] - - for device_info in meta.findall(str(QName(ns, "DeviceInfo"))): - dev_sku = device_info.find(str(QName(ns, "HwSku"))).text - if dev_sku == hwsku: - interfaces = device_info.find(str(QName(ns, "EthernetInterfaces"))) - for interface in interfaces.findall(str(QName(ns1, "EthernetInterface"))): - name = interface.find(str(QName(ns, "InterfaceName"))).text - speed = interface.find(str(QName(ns, "Speed"))).text - ethernet_interfaces.append({ 'name':name, 'speed':speed }) - - return ethernet_interfaces def get_console_info(devices, dev, port): for k, v in devices.items(): @@ -429,7 +416,6 @@ def parse_xml(filename, platform=None, port_config_file=None): neighbors = None devices = None hostname = None - ethernet_interfaces = [] syslog_servers = [] dhcp_servers = [] ntp_servers = [] @@ -459,8 +445,6 @@ def parse_xml(filename, platform=None, port_config_file=None): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) - elif child.tag == str(QName(ns, "DeviceInfos")): - ethernet_interfaces = parse_deviceinfo(child, hwsku) results = {} results['minigraph_hwsku'] = hwsku @@ -509,7 +493,6 @@ def parse_xml(filename, platform=None, port_config_file=None): results['forced_mgmt_routes'] = mgmt_routes results['erspan_dst'] = erspan_dst results['deployment_id'] = deployment_id - results['ethernet_interfaces'] = ethernet_interfaces return results diff --git a/src/sonic-config-engine/tests/simple-sample-graph.xml b/src/sonic-config-engine/tests/simple-sample-graph.xml index 7daae24f49a6..20bfb07f00d0 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph.xml @@ -200,68 +200,6 @@ - - - true - - - DeviceInterface - - true - true - 1 - fortyGigE0/0 - - false - 0 - 0 - 10000 - - - DeviceInterface - - true - true - 1 - fortyGigE0/4 - - false - 0 - 0 - 25000 - - - DeviceInterface - - true - true - 1 - fortyGigE0/8 - - false - 0 - 0 - 40000 - - - DeviceInterface - - true - true - 1 - fortyGigE0/12 - - false - 0 - 0 - 1000000 - - - true - 0 - Force10-S6000 - - switch-t0 Force10-S6000 diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 153b0bb14f36..d3ff3e8b9f4e 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -119,8 +119,3 @@ def test_minigraph_deployment_id(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v deployment_id' output = self.run_script(argument) self.assertEqual(output.strip(), "1") - - def test_minigraph_ethernet_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v ethernet_interfaces' - output = self.run_script(argument) - self.assertEqual(output.strip(), "[{'speed': '10000', 'name': 'fortyGigE0/0'}, {'speed': '25000', 'name': 'fortyGigE0/4'}, {'speed': '40000', 'name': 'fortyGigE0/8'}, {'speed': '1000000', 'name': 'fortyGigE0/12'}]") diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index b386d52bd68b..a97c5e416f8d 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit b386d52bd68bdc5facbd837e265f49a8350e14a1 +Subproject commit a97c5e416f8d4c8d6ddd69a7bb6b983527b3c627 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 3f4afbbd9d7e..7e70b4d63020 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 3f4afbbd9d7ed2f077922e0cb0d59df743e34a9a +Subproject commit 7e70b4d63020fc9ea1aa009c264e4effab7bcda0 diff --git a/src/sonic-swss b/src/sonic-swss index eaccf67cabd2..f9b55d30276d 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit eaccf67cabd22df0ff7d0117fe55f4261bc961d9 +Subproject commit f9b55d30276d1a6ab94e7321d9b2a3bf076fd683 From 9c6958773ade5bb46f9a68b4074c720ea8702c73 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 28 Aug 2017 18:07:46 -0700 Subject: [PATCH 05/17] Revert "RR client support in minigraph for FRR" This reverts commit 45ab08731f9247e387b2f439d9a7a72319746cbc. --- dockers/docker-fpm-frr/bgpd.conf.j2 | 6 ------ src/sonic-config-engine/minigraph.py | 5 ----- 2 files changed, 11 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index 1ed09ba9b61d..c66d5bfb232f 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -57,18 +57,12 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if neighbor_addr | ipv4 %} address-family ipv4 neighbor {{ neighbor_addr }} activate -{% if bgp_session['rrclient'] != 0 %} - neighbor {{ bgp_session['addr'] }} route-reflector-client -{% endif %} maximum-paths 64 exit-address-family {% endif %} {% if neighbor_addr | ipv6 %} address-family ipv6 neighbor {{ neighbor_addr }} activate -{% if bgp_session['rrclient'] != 0 %} - neighbor {{ bgp_session['addr'] }} route-reflector-client -{% endif %} maximum-paths 64 exit-address-family {% endif %} diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index a8bd445ebb20..6dbf0d570d47 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -274,10 +274,6 @@ def parse_cpg(cpg, hname): for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): asn = router.find(str(QName(ns1, "ASN"))).text hostname = router.find(str(QName(ns1, "Hostname"))).text - if router.find(str(QName(ns1, "RRClient"))): - rrclient = '1' - else: - rrclient = '0' if hostname == hname: myasn = int(asn) peers = router.find(str(QName(ns1, "Peers"))) @@ -296,7 +292,6 @@ def parse_cpg(cpg, hname): bgp_session = bgp_sessions[peer] if hostname == bgp_session['name']: bgp_session['asn'] = int(asn) - bgp_session['rrclient'] = int(rrclient) return bgp_sessions, myasn, bgp_peers_with_range From 8aa3ef5e2b83c6bfa79d973f618827e647fe4f2f Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 28 Aug 2017 18:17:46 -0700 Subject: [PATCH 06/17] RR client support in minigraph for FRR --- dockers/docker-fpm-frr/bgpd.conf.j2 | 6 ++++++ src/sonic-config-engine/minigraph.py | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index c66d5bfb232f..1ed09ba9b61d 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -57,12 +57,18 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if neighbor_addr | ipv4 %} address-family ipv4 neighbor {{ neighbor_addr }} activate +{% if bgp_session['rrclient'] != 0 %} + neighbor {{ bgp_session['addr'] }} route-reflector-client +{% endif %} maximum-paths 64 exit-address-family {% endif %} {% if neighbor_addr | ipv6 %} address-family ipv6 neighbor {{ neighbor_addr }} activate +{% if bgp_session['rrclient'] != 0 %} + neighbor {{ bgp_session['addr'] }} route-reflector-client +{% endif %} maximum-paths 64 exit-address-family {% endif %} diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 1877e552858e..c0b2e6550a9f 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -274,6 +274,10 @@ def parse_cpg(cpg, hname): for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): asn = router.find(str(QName(ns1, "ASN"))).text hostname = router.find(str(QName(ns1, "Hostname"))).text + if router.find(str(QName(ns1, "RRClient"))): + rrclient = '1' + else: + rrclient = '0' if hostname == hname: myasn = int(asn) peers = router.find(str(QName(ns1, "Peers"))) @@ -292,6 +296,7 @@ def parse_cpg(cpg, hname): bgp_session = bgp_sessions[peer] if hostname == bgp_session['name']: bgp_session['asn'] = int(asn) + bgp_session['rrclient'] = int(rrclient) return bgp_sessions, myasn, bgp_peers_with_range From 6e2ef2cd65d421de88209d5db6a603c8aa24ffe5 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Wed, 30 Aug 2017 18:43:26 -0700 Subject: [PATCH 07/17] Correcting j2 file for rrclient support --- dockers/docker-fpm-frr/bgpd.conf.j2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index 1ed09ba9b61d..09614c965ee6 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -58,7 +58,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} address-family ipv4 neighbor {{ neighbor_addr }} activate {% if bgp_session['rrclient'] != 0 %} - neighbor {{ bgp_session['addr'] }} route-reflector-client + neighbor {{ neighbor_addr }} route-reflector-client {% endif %} maximum-paths 64 exit-address-family @@ -67,7 +67,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} address-family ipv6 neighbor {{ neighbor_addr }} activate {% if bgp_session['rrclient'] != 0 %} - neighbor {{ bgp_session['addr'] }} route-reflector-client + neighbor {{ neighbor_addr }} route-reflector-client {% endif %} maximum-paths 64 exit-address-family From 557bb0881a2ec2d4d17f67733c2fdf2f3fd69e85 Mon Sep 17 00:00:00 2001 From: nikos-li <31227248+nikos-li@users.noreply.github.com> Date: Wed, 4 Oct 2017 01:17:53 -0700 Subject: [PATCH 08/17] Sync to master --- .github/ISSUE_TEMPLATE.md | 60 + .github/PULL_REQUEST_TEMPLATE.md | 26 + .gitmodules | 5 +- Makefile | 40 +- build_debian.sh | 22 +- build_image.sh | 4 - .../led_proc_init.soc | 325 +++-- .../Accton-AS7312-54X/port_config.ini | 55 + .../Accton-AS7312-54X/sai.profile | 1 + .../installer.conf | 3 + .../led_proc_init.soc | 79 ++ .../x86_64-accton_as7312_54x-r0/minigraph.xml | 1184 +++++++++++++++++ .../Arista-7050-Q16S64/port_config.ini | 2 +- .../Arista-7050-QX32/port_config.ini | 2 +- .../Arista-7050-QX-32S/port_config.ini | 2 +- .../Arista-7060-CX32S/port_config.ini | 2 +- .../plugins/led_control.py | 6 + .../Arista-7260CX3-C64/port_config.ini | 2 +- .../Arista-7260CX3-D108C8/port_config.ini | 2 +- .../plugins/led_control.py | 6 + .../x86_64-cel_seastone-r0/led_proc_init.soc | 19 +- .../nos_to_sonic_grub.cfg | 44 - .../nos_to_sonic_grub.cfg | 44 - .../INGRASYS-S8810-32Q/port_config.ini | 66 +- .../x86_64-ingrasys_s8810_32q-r0/fancontrol | 17 +- .../plugins/sfputil.py | 200 ++- .../INGRASYS-S8900-54XC/port_config.ini | 110 +- .../x86_64-ingrasys_s8900_54xc-r0/fancontrol | 17 +- .../minigraph.xml | 242 ++-- .../plugins/sfputil.py | 225 +++- .../INGRASYS-S8900-64XC/port_config.ini | 130 +- .../x86_64-ingrasys_s8900_64xc-r0/fancontrol | 16 +- .../minigraph.xml | 718 +++++----- .../plugins/sfputil.py | 283 +++- .../INGRASYS-S9100-C32/port_config.ini | 66 +- .../x86_64-ingrasys_s9100-r0/fancontrol | 17 +- .../plugins/sfputil.py | 250 +++- .../x86_64-mlnx_msn2410-r0/minigraph.xml | 676 +++++++++- dockers/docker-dhcp-relay/Dockerfile.j2 | 1 + dockers/docker-dhcp-relay/isc-dhcp-relay.j2 | 20 +- dockers/docker-dhcp-relay/start.sh | 34 +- dockers/docker-dhcp-relay/wait_for_intf.sh.j2 | 28 + dockers/docker-fpm-frr/bgpd.conf.j2 | 34 +- dockers/docker-fpm-frr/bgpd.conf.j2~ | 91 ++ dockers/docker-fpm-frr/config.sh | 8 +- dockers/docker-fpm-frr/zebra.conf.j2 | 40 +- dockers/docker-fpm-gobgp/gobgpd.conf.j2 | 4 +- dockers/docker-fpm-gobgp/start.sh | 8 +- dockers/docker-fpm-gobgp/zebra.conf.j2 | 40 +- dockers/docker-fpm-quagga/bgpd.conf.j2 | 59 +- dockers/docker-fpm-quagga/supervisord.conf | 2 +- dockers/docker-fpm-quagga/zebra.conf.j2 | 40 +- dockers/docker-lldp-sv2/lldpd.conf.j2 | 6 +- dockers/docker-lldp-sv2/start.sh | 2 +- dockers/docker-orchagent/arp_update | 2 +- dockers/docker-orchagent/ipinip.json.j2 | 12 +- dockers/docker-orchagent/mirror.json.j2 | 13 +- dockers/docker-orchagent/orchagent.sh | 2 +- dockers/docker-orchagent/ports.json.j2 | 10 +- dockers/docker-orchagent/start.sh | 21 +- dockers/docker-orchagent/supervisord.conf | 3 +- dockers/docker-orchagent/swssconfig.sh | 12 +- dockers/docker-platform-monitor/start.sh | 3 + dockers/docker-snmp-sv2/alias_map.j2 | 4 +- dockers/docker-snmp-sv2/snmpd.conf.j2 | 25 +- dockers/docker-snmp-sv2/start.sh | 6 +- dockers/docker-snmp-sv2/supervisord.conf | 2 +- dockers/docker-snmp-sv2/sysDescription.j2 | 2 +- dockers/docker-teamd/start.sh | 4 +- dockers/docker-teamd/teamd.j2 | 4 +- dockers/docker-teamd/teamd.sh | 14 +- files/build_templates/docker_image_ctl.j2 | 68 +- .../organization_extensions.sh | 52 + files/build_templates/swss.service.j2 | 1 + .../interfaces/interfaces-config.service | 3 +- .../interfaces/interfaces-config.sh | 2 +- files/image_config/interfaces/interfaces.j2 | 94 +- files/image_config/ntp/ntp-config.service | 2 + files/image_config/ntp/ntp-config.sh | 2 +- files/image_config/ntp/ntp.conf.j2 | 6 +- files/image_config/platform/rc.local | 106 +- .../rsyslog/rsyslog-config.service | 2 + files/image_config/rsyslog/rsyslog-config.sh | 2 +- files/image_config/rsyslog/rsyslog.conf.j2 | 12 +- .../updategraph/updategraph.service | 4 +- files/initramfs-tools/arista-convertfs.j2 | 31 +- files/initramfs-tools/union-mount.j2 | 6 + files/initramfs-tools/varlog | 36 + functions.sh | 2 +- installer/x86_64/install.sh | 31 +- platform/broadcom/docker-ptf-brcm.mk | 2 +- platform/broadcom/libsaithrift-dev.mk | 2 +- platform/broadcom/python-saithrift.mk | 2 +- platform/broadcom/rules.mk | 10 +- platform/broadcom/sai.mk | 9 +- platform/broadcom/sdk.mk | 9 +- .../broadcom/sonic-platform-modules-arista | 2 +- platform/broadcom/sonic-platform-modules-dell | 2 +- .../broadcom/sonic-platform-modules-ingrasys | 2 +- platform/mellanox/docker-ptf-mlnx.mk | 2 +- platform/mellanox/docker-syncd-mlnx/start.sh | 4 - platform/mellanox/fw.mk | 2 +- platform/mellanox/libsaithrift-dev.mk | 2 +- platform/mellanox/mlnx-sai.mk | 4 +- platform/mellanox/python-saithrift.mk | 2 +- platform/mellanox/rules.mk | 6 +- platform/mellanox/sdk.mk | 10 +- rules/config | 6 +- rules/docker-platform-monitor.mk | 3 + slave.mk | 30 +- src/SAI | 1 - ...r-will-send-lacp-update-right-after-.patch | 98 ++ src/libteam/Makefile | 1 + src/sonic-config-engine/minigraph.py | 254 ++-- src/sonic-config-engine/minigraph.py~ | 472 +++++++ src/sonic-config-engine/sonic-cfggen | 50 +- .../tests/sample_output/interfaces | 82 +- .../tests/sample_output/ipinip.json | 1 - .../tests/sample_output/lldpd.conf | 5 + .../tests/sample_output/mirror.json | 2 +- src/sonic-config-engine/tests/test_cfggen.py | 53 +- src/sonic-config-engine/tests/test_j2files.py | 12 +- src/sonic-config-engine/translate_acl | 17 +- src/sonic-py-swsssdk | 2 +- src/sonic-sairedis | 2 +- src/sonic-snmpagent | 2 +- src/sonic-swss | 2 +- src/sonic-swss-common | 2 +- src/sonic-utilities | 2 +- 129 files changed, 5364 insertions(+), 1793 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/port_config.ini create mode 100644 device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/sai.profile create mode 100644 device/accton/x86_64-accton_as7312_54x-r0/installer.conf create mode 100755 device/accton/x86_64-accton_as7312_54x-r0/led_proc_init.soc create mode 100644 device/accton/x86_64-accton_as7312_54x-r0/minigraph.xml create mode 100644 device/arista/x86_64-arista_7060_cx32s/plugins/led_control.py create mode 100644 device/arista/x86_64-arista_7260cx3_64/plugins/led_control.py delete mode 100644 device/dell/x86_64-dell_s6100_c2538-r0/nos_to_sonic_grub.cfg delete mode 100644 device/dell/x86_64-dell_z9100_c2538-r0/nos_to_sonic_grub.cfg create mode 100755 dockers/docker-dhcp-relay/wait_for_intf.sh.j2 create mode 100644 dockers/docker-fpm-frr/bgpd.conf.j2~ create mode 100755 files/build_templates/organization_extensions.sh create mode 100644 files/initramfs-tools/varlog delete mode 160000 src/SAI create mode 100644 src/libteam/0003-teamd-lacp-runner-will-send-lacp-update-right-after-.patch create mode 100644 src/sonic-config-engine/minigraph.py~ create mode 100644 src/sonic-config-engine/tests/sample_output/lldpd.conf diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000000..05f39760b195 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,60 @@ + + +**Description** + + + +**Steps to reproduce the issue:** +1. +2. +3. + +**Describe the results you received:** + + +**Describe the results you expected:** + + +**Additional information you deem important (e.g. issue happens only occasionally):** + + **Output of `show version`:** + + ``` + (paste your output here) + ``` + + **Attach debug file `sudo generate_dump`:** + + ``` + (paste your output here) + ``` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000000..2ac7d9e47730 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ + + +**- What I did** + +**- How I did it** + +**- How to verify it** + +**- Description for the changelog** + + + +**- A picture of a cute animal (not mandatory but encouraged)** diff --git a/.gitmodules b/.gitmodules index 5bf6fb5b4a61..4bddfb4a60da 100644 --- a/.gitmodules +++ b/.gitmodules @@ -44,6 +44,7 @@ [submodule "src/sonic-utilities"] path = src/sonic-utilities url = https://github.com/Azure/sonic-utilities + branch = v1.0.3 [submodule "platform/broadcom/sonic-platform-modules-s6000"] path = platform/broadcom/sonic-platform-modules-s6000 url = https://github.com/Azure/sonic-platform-modules-s6000 @@ -56,10 +57,6 @@ [submodule "platform/broadcom/sonic-platform-modules-ingrasys"] path = platform/broadcom/sonic-platform-modules-ingrasys url = https://github.com/Ingrasys-sonic/sonic-platform-modules-ingrasys -[submodule "src/SAI"] - path = src/SAI - url = https://github.com/opencomputeproject/SAI - branch = v0.9.4 [submodule "src/sonic-platform-daemons"] path = src/sonic-platform-daemons url = https://github.com/Azure/sonic-platform-daemons diff --git a/Makefile b/Makefile index d779c30718dc..d672edc6836a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,18 @@ ############################################################################### ## Wrapper for starting make inside sonic-slave container +# +# Supported parameters: +# +# * PLATFORM: Specific platform we wish to build images for. +# * BUILD_NUMBER: Desired version-number to pass to the building-system. +# * ENABLE_DHCP_GRAPH_SERVICE: Enables get-graph service to fetch minigraph files +# through http. +# * SHUTDOWN_BGP_ON_START: Sets admin-down state for all bgp peerings after restart. +# * SONIC_ENABLE_SYNCD_RPC: Enables rpc-based syncd builds. +# * USERNAME: Desired username -- default at rules/config +# * PASSWORD: Desired password -- default at rules/config +# * KEEP_SLAVE_ON: Keeps slave container up after building-process concludes. +# ############################################################################### SHELL = /bin/bash @@ -13,7 +26,7 @@ $(shell rm -f .screen) MAKEFLAGS += -B SLAVE_BASE_TAG = $(shell shasum sonic-slave/Dockerfile | awk '{print substr($$1,0,11);}') -SLAVE_TAG = $(shell shasum sonic-slave/Dockerfile.user | awk '{print substr($$1,0,11);}') +SLAVE_TAG = $(shell cat sonic-slave/Dockerfile.user sonic-slave/Dockerfile | shasum | awk '{print substr($$1,0,11);}') SLAVE_BASE_IMAGE = sonic-slave-base SLAVE_IMAGE = sonic-slave-$(USER) @@ -37,6 +50,16 @@ DOCKER_BUILD = docker build --no-cache \ sonic-slave && \ docker tag $(SLAVE_IMAGE):latest $(SLAVE_IMAGE):$(SLAVE_TAG) +SONIC_BUILD_INSTRUCTION := make \ + -f slave.mk \ + PLATFORM=$(PLATFORM) \ + BUILD_NUMBER=$(BUILD_NUMBER) \ + ENABLE_DHCP_GRAPH_SERVICE=$(ENABLE_DHCP_GRAPH_SERVICE) \ + SHUTDOWN_BGP_ON_START=$(SHUTDOWN_BGP_ON_START) \ + SONIC_ENABLE_SYNCD_RPC=$(ENABLE_SYNCD_RPC) \ + PASSWORD=$(PASSWORD) \ + USERNAME=$(USERNAME) + .PHONY: sonic-slave-build sonic-slave-bash .DEFAULT_GOAL := all @@ -48,16 +71,11 @@ DOCKER_BUILD = docker build --no-cache \ @docker inspect --type image $(SLAVE_IMAGE):$(SLAVE_TAG) &> /dev/null || \ { echo Image $(SLAVE_IMAGE):$(SLAVE_TAG) not found. Building... ; \ $(DOCKER_BUILD) ; } - @$(DOCKER_RUN) $(SLAVE_IMAGE):$(SLAVE_TAG) make \ - -f slave.mk \ - PLATFORM=$(PLATFORM) \ - BUILD_NUMBER=$(BUILD_NUMBER) \ - ENABLE_DHCP_GRAPH_SERVICE=$(ENABLE_DHCP_GRAPH_SERVICE) \ - SHUTDOWN_BGP_ON_START=$(SHUTDOWN_BGP_ON_START) \ - SONIC_ENABLE_SYNCD_RPC=$(ENABLE_SYNCD_RPC) \ - PASSWORD=$(PASSWORD) \ - USERNAME=$(USERNAME) \ - $@ +ifeq "$(KEEP_SLAVE_ON)" "yes" + @$(DOCKER_RUN) $(SLAVE_IMAGE):$(SLAVE_TAG) bash -c "$(SONIC_BUILD_INSTRUCTION) $@; /bin/bash" +else + @$(DOCKER_RUN) $(SLAVE_IMAGE):$(SLAVE_TAG) $(SONIC_BUILD_INSTRUCTION) $@ +endif sonic-slave-build : $(DOCKER_BASE_BUILD) diff --git a/build_debian.sh b/build_debian.sh index 22cbef494f87..a21cdada0243 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -63,6 +63,7 @@ if [[ -d $FILESYSTEM_ROOT ]]; then fi mkdir -p $FILESYSTEM_ROOT mkdir -p $FILESYSTEM_ROOT/$PLATFORM_DIR +mkdir -p $FILESYSTEM_ROOT/$PLATFORM_DIR/x86_64-grub touch $FILESYSTEM_ROOT/$PLATFORM_DIR/firsttime ## Build a basic Debian system by debootstrap @@ -132,6 +133,8 @@ sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-premount/arista- ## 2. Bind-mount docker working directory (docker aufs cannot work over aufs rootfs) sudo cp files/initramfs-tools/union-mount $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/union-mount sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/union-mount +sudo cp files/initramfs-tools/varlog $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/varlog +sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-bottom/varlog sudo cp files/initramfs-tools/union-fsck $FILESYSTEM_ROOT/etc/initramfs-tools/hooks/union-fsck sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/hooks/union-fsck sudo chroot $FILESYSTEM_ROOT update-initramfs -u @@ -203,7 +206,13 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in curl \ kexec-tools \ less \ - unzip + unzip \ + gdisk + +sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y download \ + grub-pc-bin + +sudo mv $FILESYSTEM_ROOT/grub-pc-bin*.deb $FILESYSTEM_ROOT/$PLATFORM_DIR/x86_64-grub ## Disable kexec supported reboot which was installed by default sudo sed -i 's/LOAD_KEXEC=true/LOAD_KEXEC=false/' $FILESYSTEM_ROOT/etc/default/kexec @@ -239,10 +248,11 @@ EOF ## Config sysctl sudo mkdir -p $FILESYSTEM_ROOT/var/core sudo augtool --autosave " -set /files/etc/sysctl.conf/kernel.core_pattern '|/usr/bin/coredump-compress %e %p' +set /files/etc/sysctl.conf/kernel.core_pattern '|/usr/bin/coredump-compress %e %t %p' set /files/etc/sysctl.conf/kernel.softlockup_panic 1 set /files/etc/sysctl.conf/kernel.panic 10 +set /files/etc/sysctl.conf/fs.suid_dumpable 2 set /files/etc/sysctl.conf/net.ipv4.conf.default.forwarding 1 set /files/etc/sysctl.conf/net.ipv4.conf.all.forwarding 1 @@ -312,6 +322,14 @@ if [ -f sonic_debian_extension.sh ]; then ./sonic_debian_extension.sh $FILESYSTEM_ROOT $PLATFORM_DIR fi +## Organization specific extensions such as Configuration & Scripts for features like AAA, ZTP... +if [ "${enable_organization_extensions}" = "y" ]; then + if [ -f files/build_templates/organization_extensions.sh ]; then + sudo chmod 755 files/build_templates/organization_extensions.sh + ./files/build_templates/organization_extensions.sh -f $FILESYSTEM_ROOT -h $HOSTNAME + fi +fi + ## Clean up apt sudo LANG=C chroot $FILESYSTEM_ROOT apt-get autoremove sudo LANG=C chroot $FILESYSTEM_ROOT apt-get autoclean diff --git a/build_image.sh b/build_image.sh index 2d229c2d194b..ee7fb8a75823 100755 --- a/build_image.sh +++ b/build_image.sh @@ -25,10 +25,6 @@ generate_onie_installer_image() cp ./device/$VENDOR/$PLATFORM/installer.conf ./installer/x86_64/platforms/$PLATFORM fi - if [ "$IMAGE_TYPE" = "raw" ] && [ -f ./device/$VENDOR/$PLATFORM/nos_to_sonic_grub.cfg ]; then - sed -i -e "s/%%IMAGE_VERSION%%/$IMAGE_VERSION/g" ./device/$VENDOR/$PLATFORM/nos_to_sonic_grub.cfg - echo "IMAGE_VERSION is $IMAGE_VERSION" - fi done done diff --git a/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc index e27679db9ab0..85030e1db349 100644 --- a/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc +++ b/device/accton/x86_64-accton_as5712_54x-r0/led_proc_init.soc @@ -1,163 +1,162 @@ -# LED setting for active -# ----------------------------------------------------------------------------- -# for as5712_54x (48xg+6qxg) -# -# on green - if link up -# off - if link down -# blink - if active -# ----------------------------------------------------------------------------- -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 -m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 -m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 -m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 -m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 -m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 -m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 -m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 -m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 -m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 -m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 -m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 -m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 -m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 -m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 -m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 -m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 -m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 -m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 -m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 -m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 -m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 -m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 -m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 -m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 -m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 -m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 -m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 -m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 -m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 -m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 -m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 -m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 - -led 0 stop -led 0 prog \ - 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ - 61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \ - D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \ - 06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \ - 96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \ - 04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \ - 0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00 -led 0 start - -led 1 stop -led 1 prog \ - 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ - 61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \ - 67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \ - 67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \ - 67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \ - D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \ - 63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \ - FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \ - 85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \ - A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \ - 57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00 -led 1 start - +# LED setting for active +# ----------------------------------------------------------------------------- +# for as5712_54x (48xg+6qxg) +# +# on green - if link up +# off - if link down +# blink - if active +# ----------------------------------------------------------------------------- +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 + +led 0 stop +led 0 prog \ + 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ + 61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \ + D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \ + 06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \ + 96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \ + 04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \ + 0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00 +led 0 start + +led 1 stop +led 1 prog \ + 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ + 61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \ + 67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \ + 67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \ + 67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \ + D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \ + 63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \ + FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \ + 85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \ + A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \ + 57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00 +led 1 start diff --git a/device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/port_config.ini b/device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/port_config.ini new file mode 100644 index 000000000000..8eeb6a993cb5 --- /dev/null +++ b/device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias +Ethernet0 41 twentyfiveGigE1 +Ethernet1 42 twentyfiveGigE2 +Ethernet2 43 twentyfiveGigE3 +Ethernet3 44 twentyfiveGigE4 +Ethernet4 49 twentyfiveGigE5 +Ethernet5 50 twentyfiveGigE6 +Ethernet6 51 twentyfiveGigE7 +Ethernet7 52 twentyfiveGigE8 +Ethernet8 53 twentyfiveGigE9 +Ethernet9 54 twentyfiveGigE10 +Ethernet10 55 twentyfiveGigE11 +Ethernet11 56 twentyfiveGigE12 +Ethernet12 65 twentyfiveGigE13 +Ethernet13 66 twentyfiveGigE14 +Ethernet14 67 twentyfiveGigE15 +Ethernet15 68 twentyfiveGigE16 +Ethernet16 33 twentyfiveGigE17 +Ethernet17 34 twentyfiveGigE18 +Ethernet18 35 twentyfiveGigE19 +Ethernet19 36 twentyfiveGigE20 +Ethernet20 37 twentyfiveGigE21 +Ethernet21 38 twentyfiveGigE22 +Ethernet22 39 twentyfiveGigE23 +Ethernet23 40 twentyfiveGigE24 +Ethernet24 69 twentyfiveGigE25 +Ethernet25 70 twentyfiveGigE26 +Ethernet26 71 twentyfiveGigE27 +Ethernet27 72 twentyfiveGigE28 +Ethernet28 81 twentyfiveGigE29 +Ethernet29 82 twentyfiveGigE30 +Ethernet30 83 twentyfiveGigE31 +Ethernet31 84 twentyfiveGigE32 +Ethernet32 85 twentyfiveGigE33 +Ethernet33 86 twentyfiveGigE34 +Ethernet34 87 twentyfiveGigE35 +Ethernet35 88 twentyfiveGigE36 +Ethernet36 97 twentyfiveGigE37 +Ethernet37 98 twentyfiveGigE38 +Ethernet38 99 twentyfiveGigE39 +Ethernet39 100 twentyfiveGigE40 +Ethernet40 101 twentyfiveGigE41 +Ethernet41 102 twentyfiveGigE42 +Ethernet42 103 twentyfiveGigE43 +Ethernet43 104 twentyfiveGigE44 +Ethernet44 105 twentyfiveGigE45 +Ethernet45 106 twentyfiveGigE46 +Ethernet46 107 twentyfiveGigE47 +Ethernet47 108 twentyfiveGigE48 +Ethernet48 5,6,7,8 hundredGigE49 +Ethernet52 1,2,3,4 hundredGigE50 +Ethernet56 109,110,111,112 hundredGigE51 +Ethernet60 21,22,23,24 hundredGigE52 +Ethernet64 9,10,11,12 hundredGigE53 +Ethernet68 117,118,119,120 hundredGigE54 diff --git a/device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/sai.profile b/device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/sai.profile new file mode 100644 index 000000000000..f239b822834b --- /dev/null +++ b/device/accton/x86_64-accton_as7312_54x-r0/Accton-AS7312-54X/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/th-as7312-48x25G+6x100G.config.bcm diff --git a/device/accton/x86_64-accton_as7312_54x-r0/installer.conf b/device/accton/x86_64-accton_as7312_54x-r0/installer.conf new file mode 100644 index 000000000000..14404194ef53 --- /dev/null +++ b/device/accton/x86_64-accton_as7312_54x-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x2f8 +CONSOLE_DEV=1 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as7312_54x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as7312_54x-r0/led_proc_init.soc new file mode 100755 index 000000000000..3074649497e0 --- /dev/null +++ b/device/accton/x86_64-accton_as7312_54x-r0/led_proc_init.soc @@ -0,0 +1,79 @@ +# accton_as7312_54x 48x25G+6x100G SDK port LED macro init SOC +s CMIC_LEDUP0_DATA_RAM 0 +s CMIC_LEDUP1_DATA_RAM 0 + +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=63 REMAP_PORT_1=63 REMAP_PORT_2=63 REMAP_PORT_3=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=63 REMAP_PORT_5=63 REMAP_PORT_6=63 REMAP_PORT_7=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=27 REMAP_PORT_9=26 REMAP_PORT_10=25 REMAP_PORT_11=24 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 REMAP_PORT_13=63 REMAP_PORT_14=63 REMAP_PORT_15=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=63 REMAP_PORT_17=63 REMAP_PORT_18=63 REMAP_PORT_19=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=31 REMAP_PORT_21=30 REMAP_PORT_22=29 REMAP_PORT_23=28 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=15 REMAP_PORT_25=14 REMAP_PORT_26=13 REMAP_PORT_27=12 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=19 REMAP_PORT_29=18 REMAP_PORT_30=17 REMAP_PORT_31=16 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=63 REMAP_PORT_33=63 REMAP_PORT_34=63 REMAP_PORT_35=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=63 REMAP_PORT_37=63 REMAP_PORT_38=63 REMAP_PORT_39=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=35 REMAP_PORT_41=34 REMAP_PORT_42=33 REMAP_PORT_43=32 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=63 REMAP_PORT_45=63 REMAP_PORT_46=63 REMAP_PORT_47=63 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=23 REMAP_PORT_49=22 REMAP_PORT_50=21 REMAP_PORT_51=20 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 REMAP_PORT_53=10 REMAP_PORT_54=9 REMAP_PORT_55=8 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 REMAP_PORT_57=6 REMAP_PORT_58=5 REMAP_PORT_59=4 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 REMAP_PORT_61=2 REMAP_PORT_62=1 REMAP_PORT_63=0 + +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=19 REMAP_PORT_1=18 REMAP_PORT_2=17 REMAP_PORT_3=16 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=23 REMAP_PORT_5=22 REMAP_PORT_6=21 REMAP_PORT_7=20 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=3 REMAP_PORT_9=2 REMAP_PORT_10=1 REMAP_PORT_11=0 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 REMAP_PORT_13=63 REMAP_PORT_14=63 REMAP_PORT_15=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=7 REMAP_PORT_17=6 REMAP_PORT_18=5 REMAP_PORT_19=4 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=11 REMAP_PORT_21=10 REMAP_PORT_22=9 REMAP_PORT_23=8 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=63 REMAP_PORT_25=63 REMAP_PORT_26=63 REMAP_PORT_27=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=63 REMAP_PORT_29=63 REMAP_PORT_30=63 REMAP_PORT_31=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=15 REMAP_PORT_33=14 REMAP_PORT_34=13 REMAP_PORT_35=12 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=27 REMAP_PORT_37=26 REMAP_PORT_38=25 REMAP_PORT_39=24 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=63 REMAP_PORT_41=63 REMAP_PORT_42=63 REMAP_PORT_43=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=63 REMAP_PORT_45=63 REMAP_PORT_46=63 REMAP_PORT_47=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=31 REMAP_PORT_49=30 REMAP_PORT_50=29 REMAP_PORT_51=28 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=35 REMAP_PORT_53=34 REMAP_PORT_54=33 REMAP_PORT_55=32 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=63 REMAP_PORT_57=63 REMAP_PORT_58=63 REMAP_PORT_59=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=63 REMAP_PORT_61=63 REMAP_PORT_62=63 REMAP_PORT_63=63 + +led 0 stop +led 0 prog \ + 02 FD 42 80 02 FF 42 00 02 FE 42 00 02 FA 42 7E \ + 02 FB 42 24 06 F9 D2 00 74 1E 02 F9 42 03 67 AC \ + 67 C3 67 52 86 FE 67 C3 67 52 86 FE 67 C3 67 52 \ + 86 FE 67 C3 67 52 86 FE 06 FB D6 FE 74 1E 86 FC \ + 3E FA 06 FE 88 4A 03 71 4C 67 84 57 67 84 57 67 \ + 98 57 06 FE 88 80 4A 00 27 97 75 4F 90 4A 00 27 \ + 4A 01 27 B7 97 71 69 77 42 06 F9 D6 FC 74 7C 02 \ + F9 4A 07 37 4E 07 02 FC 42 00 4E 07 06 F9 0A 07 \ + 71 4F 77 42 16 FF 06 FD 17 4D DA 07 74 95 12 FF \ + 52 00 86 FD 57 86 FF 57 16 FF 06 FD 07 4D DA 07 \ + 74 A9 12 FF 52 00 86 FD 57 86 FF 57 06 FE C2 FC \ + 98 98 12 F4 50 C2 FC 98 98 F2 F0 14 06 F4 C2 03 \ + 88 77 D1 06 FE C2 FC 98 98 F2 E0 14 06 FE C2 03 \ + 88 18 71 E2 80 18 71 DD 67 98 67 98 57 67 98 67 \ + 84 57 80 18 71 EB 67 84 67 98 57 67 84 67 84 57 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +led 0 start +led auto on + +led 1 stop +led 1 prog \ + 02 FD 42 80 02 FF 42 00 02 FE 42 00 02 FA 42 7E \ + 02 FB 42 24 06 F9 D2 00 74 1E 02 F9 42 03 67 AC \ + 67 C3 67 52 86 FE 67 C3 67 52 86 FE 67 C3 67 52 \ + 86 FE 67 C3 67 52 86 FE 06 FB D6 FE 74 1E 86 FC \ + 3E FA 06 FE 88 4A 03 71 4C 67 84 57 67 84 57 67 \ + 98 57 06 FE 88 80 4A 00 27 97 75 4F 90 4A 00 27 \ + 4A 01 27 B7 97 71 69 77 42 06 F9 D6 FC 74 7C 02 \ + F9 4A 07 37 4E 07 02 FC 42 00 4E 07 06 F9 0A 07 \ + 71 4F 77 42 16 FF 06 FD 17 4D DA 07 74 95 12 FF \ + 52 00 86 FD 57 86 FF 57 16 FF 06 FD 07 4D DA 07 \ + 74 A9 12 FF 52 00 86 FD 57 86 FF 57 06 FE C2 FC \ + 98 98 12 F4 50 C2 FC 98 98 F2 F0 14 06 F4 C2 03 \ + 88 77 D1 06 FE C2 FC 98 98 F2 E0 14 06 FE C2 03 \ + 88 18 71 E2 80 18 71 DD 67 98 67 98 57 67 98 67 \ + 84 57 80 18 71 EB 67 84 67 98 57 67 84 67 84 57 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +led 1 start +led auto on diff --git a/device/accton/x86_64-accton_as7312_54x-r0/minigraph.xml b/device/accton/x86_64-accton_as7312_54x-r0/minigraph.xml new file mode 100644 index 000000000000..8547ceacbc58 --- /dev/null +++ b/device/accton/x86_64-accton_as7312_54x-r0/minigraph.xml @@ -0,0 +1,1184 @@ + + + + + + ARISTA01T0 + 10.0.0.33 + switch1 + 10.0.0.32 + 1 + 180 + 60 + + + switch1 + 10.0.0.0 + ARISTA01T2 + 10.0.0.1 + 1 + 180 + 60 + + + ARISTA02T0 + 10.0.0.35 + switch1 + 10.0.0.34 + 1 + 180 + 60 + + + switch1 + 10.0.0.2 + ARISTA02T2 + 10.0.0.3 + 1 + 180 + 60 + + + ARISTA03T0 + 10.0.0.37 + switch1 + 10.0.0.36 + 1 + 180 + 60 + + + switch1 + 10.0.0.4 + ARISTA03T2 + 10.0.0.5 + 1 + 180 + 60 + + + ARISTA04T0 + 10.0.0.39 + switch1 + 10.0.0.38 + 1 + 180 + 60 + + + switch1 + 10.0.0.6 + ARISTA04T2 + 10.0.0.7 + 1 + 180 + 60 + + + ARISTA05T0 + 10.0.0.41 + switch1 + 10.0.0.40 + 1 + 180 + 60 + + + switch1 + 10.0.0.8 + ARISTA05T2 + 10.0.0.9 + 1 + 180 + 60 + + + ARISTA06T0 + 10.0.0.43 + switch1 + 10.0.0.42 + 1 + 180 + 60 + + + switch1 + 10.0.0.10 + ARISTA06T2 + 10.0.0.11 + 1 + 180 + 60 + + + ARISTA07T0 + 10.0.0.45 + switch1 + 10.0.0.44 + 1 + 180 + 60 + + + switch1 + 10.0.0.12 + ARISTA07T2 + 10.0.0.13 + 1 + 180 + 60 + + + ARISTA08T0 + 10.0.0.47 + switch1 + 10.0.0.46 + 1 + 180 + 60 + + + switch1 + 10.0.0.14 + ARISTA08T2 + 10.0.0.15 + 1 + 180 + 60 + + + ARISTA09T0 + 10.0.0.49 + switch1 + 10.0.0.48 + 1 + 180 + 60 + + + switch1 + 10.0.0.16 + ARISTA09T2 + 10.0.0.17 + 1 + 180 + 60 + + + ARISTA10T0 + 10.0.0.51 + switch1 + 10.0.0.50 + 1 + 180 + 60 + + + switch1 + 10.0.0.18 + ARISTA10T2 + 10.0.0.19 + 1 + 180 + 60 + + + ARISTA11T0 + 10.0.0.53 + switch1 + 10.0.0.52 + 1 + 180 + 60 + + + switch1 + 10.0.0.20 + ARISTA11T2 + 10.0.0.21 + 1 + 180 + 60 + + + ARISTA12T0 + 10.0.0.55 + switch1 + 10.0.0.54 + 1 + 180 + 60 + + + switch1 + 10.0.0.22 + ARISTA12T2 + 10.0.0.23 + 1 + 180 + 60 + + + ARISTA13T0 + 10.0.0.57 + switch1 + 10.0.0.56 + 1 + 180 + 60 + + + switch1 + 10.0.0.24 + ARISTA13T2 + 10.0.0.25 + 1 + 180 + 60 + + + ARISTA14T0 + 10.0.0.59 + switch1 + 10.0.0.58 + 1 + 180 + 60 + + + switch1 + 10.0.0.26 + ARISTA14T2 + 10.0.0.27 + 1 + 180 + 60 + + + ARISTA15T0 + 10.0.0.61 + switch1 + 10.0.0.60 + 1 + 180 + 60 + + + switch1 + 10.0.0.28 + ARISTA15T2 + 10.0.0.29 + 1 + 180 + 60 + + + ARISTA16T0 + 10.0.0.63 + switch1 + 10.0.0.62 + 1 + 180 + 60 + + + switch1 + 10.0.0.30 + ARISTA16T2 + 10.0.0.31 + 1 + 180 + 60 + + + + + 65100 + switch1 + + +
10.0.0.33
+ + +
+ +
10.0.0.1
+ + +
+ +
10.0.0.35
+ + +
+ +
10.0.0.3
+ + +
+ +
10.0.0.37
+ + +
+ +
10.0.0.5
+ + +
+ +
10.0.0.39
+ + +
+ +
10.0.0.7
+ + +
+ +
10.0.0.41
+ + +
+ +
10.0.0.9
+ + +
+ +
10.0.0.43
+ + +
+ +
10.0.0.11
+ + +
+ +
10.0.0.45
+ + +
+ +
10.0.0.13
+ + +
+ +
10.0.0.47
+ + +
+ +
10.0.0.15
+ + +
+ +
10.0.0.49
+ + +
+ +
10.0.0.17
+ + +
+ +
10.0.0.51
+ + +
+ +
10.0.0.19
+ + +
+ +
10.0.0.53
+ + +
+ +
10.0.0.21
+ + +
+ +
10.0.0.55
+ + +
+ +
10.0.0.23
+ + +
+ +
10.0.0.57
+ + +
+ +
10.0.0.25
+ + +
+ +
10.0.0.59
+ + +
+ +
10.0.0.27
+ + +
+ +
10.0.0.61
+ + +
+ +
10.0.0.29
+ + +
+ +
10.0.0.63
+ + +
+ +
10.0.0.31
+ + +
+
+ +
+ + 64001 + ARISTA01T0 + + + + 65200 + ARISTA01T2 + + + + 64002 + ARISTA02T0 + + + + 65200 + ARISTA02T2 + + + + 64003 + ARISTA03T0 + + + + 65200 + ARISTA03T2 + + + + 64004 + ARISTA04T0 + + + + 65200 + ARISTA04T2 + + + + 64005 + ARISTA05T0 + + + + 65200 + ARISTA05T2 + + + + 64006 + ARISTA06T0 + + + + 65200 + ARISTA06T2 + + + + 64007 + ARISTA07T0 + + + + 65200 + ARISTA07T2 + + + + 64008 + ARISTA08T0 + + + + 65200 + ARISTA08T2 + + + + 64009 + ARISTA09T0 + + + + 65200 + ARISTA09T2 + + + + 64010 + ARISTA10T0 + + + + 65200 + ARISTA10T2 + + + + 64011 + ARISTA11T0 + + + + 65200 + ARISTA11T2 + + + + 64012 + ARISTA12T0 + + + + 65200 + ARISTA12T2 + + + + 64013 + ARISTA13T0 + + + + 65200 + ARISTA13T2 + + + + 64014 + ARISTA14T0 + + + + 65200 + ARISTA14T2 + + + + 64015 + ARISTA15T0 + + + + 65200 + ARISTA15T2 + + + + 64016 + ARISTA16T0 + + + + 65200 + ARISTA16T2 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + + + + + + switch1 + + + + + + Ethernet0 + 10.0.0.0/31 + + + + Ethernet1 + 10.0.0.2/31 + + + + Ethernet2 + 10.0.0.4/31 + + + + Ethernet3 + 10.0.0.6/31 + + + + Ethernet4 + 10.0.0.8/31 + + + + Ethernet5 + 10.0.0.10/31 + + + + Ethernet6 + 10.0.0.12/31 + + + + Ethernet7 + 10.0.0.14/31 + + + + Ethernet8 + 10.0.0.16/31 + + + + Ethernet9 + 10.0.0.18/31 + + + + Ethernet10 + 10.0.0.20/31 + + + + Ethernet11 + 10.0.0.22/31 + + + + Ethernet12 + 10.0.0.24/31 + + + + Ethernet13 + 10.0.0.26/31 + + + + Ethernet14 + 10.0.0.28/31 + + + + Ethernet15 + 10.0.0.30/31 + + + + Ethernet16 + 10.0.0.32/31 + + + + Ethernet17 + 10.0.0.34/31 + + + + Ethernet18 + 10.0.0.36/31 + + + + Ethernet19 + 10.0.0.38/31 + + + + Ethernet20 + 10.0.0.40/31 + + + + Ethernet21 + 10.0.0.42/31 + + + + Ethernet22 + 10.0.0.44/31 + + + + Ethernet23 + 10.0.0.46/31 + + + + Ethernet24 + 10.0.0.48/31 + + + + Ethernet25 + 10.0.0.50/31 + + + + Ethernet26 + 10.0.0.52/31 + + + + Ethernet27 + 10.0.0.54/31 + + + + Ethernet28 + 10.0.0.56/31 + + + + Ethernet29 + 10.0.0.58/31 + + + + Ethernet30 + 10.0.0.60/31 + + + + Ethernet31 + 10.0.0.62/31 + + + + Ethernet32 + 10.0.0.64/31 + + + + Ethernet33 + 10.0.0.66/31 + + + + Ethernet34 + 10.0.0.68/31 + + + + Ethernet35 + 10.0.0.70/31 + + + + Ethernet36 + 10.0.0.72/31 + + + + Ethernet37 + 10.0.0.74/31 + + + + Ethernet38 + 10.0.0.76/31 + + + + Ethernet39 + 10.0.0.78/31 + + + + Ethernet40 + 10.0.0.80/31 + + + + Ethernet41 + 10.0.0.82/31 + + + + Ethernet42 + 10.0.0.84/31 + + + + Ethernet43 + 10.0.0.86/31 + + + + Ethernet44 + 10.0.0.88/31 + + + + Ethernet45 + 10.0.0.90/31 + + + + Ethernet46 + 10.0.0.92/31 + + + + Ethernet47 + 10.0.0.94/31 + + + + Ethernet48 + 10.0.0.96/31 + + + + Ethernet52 + 10.0.0.98/31 + + + + Ethernet56 + 10.0.0.100/31 + + + + Ethernet60 + 10.0.0.102/31 + + + + Ethernet64 + 10.0.0.104/31 + + + + Ethernet68 + 10.0.0.106/31 + + + + + + + + + + + + DeviceInterfaceLink + switch1 + Ethernet0 + ARISTA01T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet1 + ARISTA02T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet2 + ARISTA03T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet3 + ARISTA04T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet4 + ARISTA05T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet5 + ARISTA06T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet6 + ARISTA07T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet7 + ARISTA08T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet8 + ARISTA09T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet9 + ARISTA10T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet10 + ARISTA11T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet11 + ARISTA12T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet12 + ARISTA13T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet13 + ARISTA14T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet14 + ARISTA15T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet15 + ARISTA16T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet16 + ARISTA01T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet17 + ARISTA02T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet18 + ARISTA03T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet19 + ARISTA04T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet20 + ARISTA05T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet21 + ARISTA06T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet22 + ARISTA07T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet23 + ARISTA08T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet24 + ARISTA09T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet25 + ARISTA10T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet26 + ARISTA11T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet27 + ARISTA12T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet28 + ARISTA13T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet29 + ARISTA14T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet30 + ARISTA15T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet31 + ARISTA16T0 + Ethernet1 + + + + + switch1 + Accton-AS7312-54X + + + + + + + switch1 + + + DhcpResources + + + + + NtpResources + + 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org + + + SyslogResources + + + + + + + + + switch1 + Accton-AS7312-54X +
diff --git a/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini b/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini index dea477b26152..1cc6c91b1308 100644 --- a/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32/Arista-7050-Q16S64/port_config.ini @@ -1,4 +1,4 @@ -# name lanes alias port +# name lanes alias index Ethernet0 125,126,127,128 Ethernet1/1 1 Ethernet4 121,122,123,124 Ethernet2/1 2 Ethernet8 13,14,15,16 Ethernet3/1 3 diff --git a/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini b/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini index 32fa6885fa93..b57f14497e39 100644 --- a/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32/Arista-7050-QX32/port_config.ini @@ -1,4 +1,4 @@ -# name lanes alias port +# name lanes alias index Ethernet0 125,126,127,128 Ethernet1/1 1 Ethernet4 121,122,123,124 Ethernet2/1 2 Ethernet8 13,14,15,16 Ethernet3/1 3 diff --git a/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini b/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini index cb36404ac44f..fda62e998c1a 100644 --- a/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini +++ b/device/arista/x86_64-arista_7050_qx32s/Arista-7050-QX-32S/port_config.ini @@ -1,4 +1,4 @@ -# name lanes alias port +# name lanes alias index Ethernet0 9,10,11,12 Ethernet5/1 5 Ethernet4 13,14,15,16 Ethernet6/1 6 Ethernet8 17,18,19,20 Ethernet7/1 7 diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini index c1dbcfabd9e3..bfe4a721141d 100644 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini @@ -1,4 +1,4 @@ -# name lanes alias port +# name lanes alias index Ethernet0 33,34,35,36 Ethernet1/1 1 Ethernet4 37,38,39,40 Ethernet2/1 2 Ethernet8 41,42,43,44 Ethernet3/1 3 diff --git a/device/arista/x86_64-arista_7060_cx32s/plugins/led_control.py b/device/arista/x86_64-arista_7060_cx32s/plugins/led_control.py new file mode 100644 index 000000000000..8d387e513c6c --- /dev/null +++ b/device/arista/x86_64-arista_7060_cx32s/plugins/led_control.py @@ -0,0 +1,6 @@ +try: + import arista.utils.sonic_leds as arista_leds +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +LedControl = arista_leds.getLedControl() diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini index 4f073e46dce3..1119dfd231c6 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-C64/port_config.ini @@ -1,4 +1,4 @@ -# name lanes alias port +# name lanes alias index Ethernet0 77,78,79,80 Ethernet1/1 1 Ethernet4 65,66,67,68 Ethernet2/1 2 Ethernet8 85,86,87,88 Ethernet3/1 3 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini index b06d1c7575d4..35a2175cf21d 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini @@ -1,4 +1,4 @@ -# name lanes alias port +# name lanes alias index Ethernet0 77,78 Ethernet1/1 1 Ethernet2 79,80 Ethernet1/3 2 Ethernet4 65,66 Ethernet2/1 3 diff --git a/device/arista/x86_64-arista_7260cx3_64/plugins/led_control.py b/device/arista/x86_64-arista_7260cx3_64/plugins/led_control.py new file mode 100644 index 000000000000..8d387e513c6c --- /dev/null +++ b/device/arista/x86_64-arista_7260cx3_64/plugins/led_control.py @@ -0,0 +1,6 @@ +try: + import arista.utils.sonic_leds as arista_leds +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +LedControl = arista_leds.getLedControl() diff --git a/device/celestica/x86_64-cel_seastone-r0/led_proc_init.soc b/device/celestica/x86_64-cel_seastone-r0/led_proc_init.soc index fb898fcadfc1..450533c0dc68 100755 --- a/device/celestica/x86_64-cel_seastone-r0/led_proc_init.soc +++ b/device/celestica/x86_64-cel_seastone-r0/led_proc_init.soc @@ -1,11 +1,8 @@ - -# Download LED code into LED processor and enable (if applicable). - -led 0 load /usr/share/sonic/platform/led-code/ledcode0; -led 0 auto on; led 0 start; -led 1 load /usr/share/sonic/platform/led-code/ledcode1; -led 1 auto on; led 1 start; -led 2 load /usr/share/sonic/platform/led-code/ledcode2; -led 2 auto on; led 2 start - - +# Download LED code into LED processor and enable (if applicable). + +led 0 load /usr/share/sonic/platform/led-code/ledcode0; +led 0 auto on; led 0 start; +led 1 load /usr/share/sonic/platform/led-code/ledcode1; +led 1 auto on; led 1 start; +led 2 load /usr/share/sonic/platform/led-code/ledcode2; +led 2 auto on; led 2 start diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/nos_to_sonic_grub.cfg b/device/dell/x86_64-dell_s6100_c2538-r0/nos_to_sonic_grub.cfg deleted file mode 100644 index 058b1a9ea118..000000000000 --- a/device/dell/x86_64-dell_s6100_c2538-r0/nos_to_sonic_grub.cfg +++ /dev/null @@ -1,44 +0,0 @@ -# -# Grub config to launch SONiC -# with ONIE boot option - -insmod serial -# Initialize USB-Serial com2 port -serial --unit=1 --speed=9600 -#Serial port config;Defaults: COM1,9600 -serial --unit=0 --speed=9600 -terminal_output serial_com0 -terminal_input serial_com0 -#terminfo added to prevent text wrap issue. -terminfo -g 80x100 serial_com0 -terminfo -g 80x100 serial_com1 - -echo -n "Press Esc to stop autoboot ... " -if sleep --verbose --interruptible 5 ; then - insmod gzio - insmod part_msdos - insmod ext2 - set root='(hd0,gpt8)' - linux /image-%%IMAGE_VERSION%%/boot/vmlinuz-3.16.0-4-amd64 root=/dev/sda8 rw console=tty0 console=ttyS1,9600n8 loop=image-%%IMAGE_VERSION%%/fs.squashfs loopfstype=squashfs apparmor=1 security=apparmor - initrd /image-%%IMAGE_VERSION%%/boot/initrd.img-3.16.0-4-amd64 - boot -else - menuentry 'SONiC' { - insmod gzio - insmod part_msdos - insmod ext2 - set root='(hd0,gpt8)' - linux /image-%%IMAGE_VERSION%%/boot/vmlinuz-3.16.0-4-amd64 root=/dev/sda8 rw console=tty0 console=ttyS1,9600n8 loop=image-%%IMAGE_VERSION%%/fs.squashfs loopfstype=squashfs apparmor=1 security=apparmor - initrd /image-%%IMAGE_VERSION%%/boot/initrd.img-3.16.0-4-amd64 - boot - } - - menuentry 'ONIE' { - insmod force10 - onieboot - } - - menuentry 'DELL-DIAG' { - delldiagboot - } -fi diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/nos_to_sonic_grub.cfg b/device/dell/x86_64-dell_z9100_c2538-r0/nos_to_sonic_grub.cfg deleted file mode 100644 index 058b1a9ea118..000000000000 --- a/device/dell/x86_64-dell_z9100_c2538-r0/nos_to_sonic_grub.cfg +++ /dev/null @@ -1,44 +0,0 @@ -# -# Grub config to launch SONiC -# with ONIE boot option - -insmod serial -# Initialize USB-Serial com2 port -serial --unit=1 --speed=9600 -#Serial port config;Defaults: COM1,9600 -serial --unit=0 --speed=9600 -terminal_output serial_com0 -terminal_input serial_com0 -#terminfo added to prevent text wrap issue. -terminfo -g 80x100 serial_com0 -terminfo -g 80x100 serial_com1 - -echo -n "Press Esc to stop autoboot ... " -if sleep --verbose --interruptible 5 ; then - insmod gzio - insmod part_msdos - insmod ext2 - set root='(hd0,gpt8)' - linux /image-%%IMAGE_VERSION%%/boot/vmlinuz-3.16.0-4-amd64 root=/dev/sda8 rw console=tty0 console=ttyS1,9600n8 loop=image-%%IMAGE_VERSION%%/fs.squashfs loopfstype=squashfs apparmor=1 security=apparmor - initrd /image-%%IMAGE_VERSION%%/boot/initrd.img-3.16.0-4-amd64 - boot -else - menuentry 'SONiC' { - insmod gzio - insmod part_msdos - insmod ext2 - set root='(hd0,gpt8)' - linux /image-%%IMAGE_VERSION%%/boot/vmlinuz-3.16.0-4-amd64 root=/dev/sda8 rw console=tty0 console=ttyS1,9600n8 loop=image-%%IMAGE_VERSION%%/fs.squashfs loopfstype=squashfs apparmor=1 security=apparmor - initrd /image-%%IMAGE_VERSION%%/boot/initrd.img-3.16.0-4-amd64 - boot - } - - menuentry 'ONIE' { - insmod force10 - onieboot - } - - menuentry 'DELL-DIAG' { - delldiagboot - } -fi diff --git a/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/INGRASYS-S8810-32Q/port_config.ini b/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/INGRASYS-S8810-32Q/port_config.ini index fb9235101108..bf87e1402ab1 100644 --- a/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/INGRASYS-S8810-32Q/port_config.ini +++ b/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/INGRASYS-S8810-32Q/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias -Ethernet0 37,38,39,40 -Ethernet4 33,34,35,36 -Ethernet8 45,46,47,48 -Ethernet12 41,42,43,44 -Ethernet16 53,54,55,56 -Ethernet20 49,50,51,52 -Ethernet24 61,62,63,64 -Ethernet28 57,58,59,60 -Ethernet32 69,70,71,72 -Ethernet36 65,66,67,68 -Ethernet40 77,78,79,80 -Ethernet44 73,74,75,76 -Ethernet48 85,86,87,88 -Ethernet52 81,82,83,84 -Ethernet56 93,94,95,96 -Ethernet60 89,90,91,92 -Ethernet64 101,102,103,104 -Ethernet68 97,98,99,100 -Ethernet72 109,110,111,112 -Ethernet76 105,106,107,108 -Ethernet80 117,118,119,120 -Ethernet84 113,114,115,116 -Ethernet88 125,126,127,128 -Ethernet92 121,122,123,124 -Ethernet96 5,6,7,8 -Ethernet100 1,2,3,4 -Ethernet104 13,14,15,16 -Ethernet108 9,10,11,12 -Ethernet112 21,22,23,24 -Ethernet116 17,18,19,20 -Ethernet120 29,30,31,32 -Ethernet124 25,26,27,28 +# name lanes alias index +Ethernet0 37,38,39,40 Ethernet1/1 0 +Ethernet4 33,34,35,36 Ethernet2/1 1 +Ethernet8 45,46,47,48 Ethernet3/1 2 +Ethernet12 41,42,43,44 Ethernet4/1 3 +Ethernet16 53,54,55,56 Ethernet5/1 4 +Ethernet20 49,50,51,52 Ethernet6/1 5 +Ethernet24 61,62,63,64 Ethernet7/1 6 +Ethernet28 57,58,59,60 Ethernet8/1 7 +Ethernet32 69,70,71,72 Ethernet9/1 8 +Ethernet36 65,66,67,68 Ethernet10/1 9 +Ethernet40 77,78,79,80 Ethernet11/1 10 +Ethernet44 73,74,75,76 Ethernet12/1 11 +Ethernet48 85,86,87,88 Ethernet13/1 12 +Ethernet52 81,82,83,84 Ethernet14/1 13 +Ethernet56 93,94,95,96 Ethernet15/1 14 +Ethernet60 89,90,91,92 Ethernet16/1 15 +Ethernet64 101,102,103,104 Ethernet17/1 16 +Ethernet68 97,98,99,100 Ethernet18/1 17 +Ethernet72 109,110,111,112 Ethernet19/1 18 +Ethernet76 105,106,107,108 Ethernet20/1 19 +Ethernet80 117,118,119,120 Ethernet21/1 20 +Ethernet84 113,114,115,116 Ethernet22/1 21 +Ethernet88 125,126,127,128 Ethernet23/1 22 +Ethernet92 121,122,123,124 Ethernet24/1 23 +Ethernet96 5,6,7,8 Ethernet25/1 24 +Ethernet100 1,2,3,4 Ethernet26/1 25 +Ethernet104 13,14,15,16 Ethernet27/1 26 +Ethernet108 9,10,11,12 Ethernet28/1 27 +Ethernet112 21,22,23,24 Ethernet29/1 28 +Ethernet116 17,18,19,20 Ethernet30/1 29 +Ethernet120 29,30,31,32 Ethernet31/1 30 +Ethernet124 25,26,27,28 Ethernet32/1 31 diff --git a/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/fancontrol b/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/fancontrol index 05a71e8d999c..8c378371a9a2 100644 --- a/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/fancontrol +++ b/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/fancontrol @@ -1,12 +1,11 @@ # Configuration file generated by pwmconfig, changes will be lost INTERVAL=10 -DEVPATH=hwmon2=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f -DEVNAME=hwmon2=w83795adg -FCTEMPS=hwmon2/device/pwm2=hwmon2/device/temp2_input hwmon2/device/pwm1=hwmon2/device/temp2_input -#FCFANS=hwmon2/device/pwm2=hwmon2/device/fan8_input+hwmon2/device/fan7_input+hwmon2/device/fan6_input+hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input+hwmon2/device/fan3_input+hwmon2/device/fan2_input+hwmon2/device/fan1_input -FCFANS=hwmon2/device/pwm2=hwmon2/device/fan8_input hwmon2/device/pwm2=hwmon2/device/fan7_input hwmon2/device/pwm2=hwmon2/device/fan6_input hwmon2/device/pwm2=hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input hwmon2/device/pwm1=hwmon2/device/fan3_input hwmon2/device/pwm1=hwmon2/device/fan2_input hwmon2/device/pwm1=hwmon2/device/fan1_input -MINTEMP=hwmon2/device/pwm2=20 hwmon2/device/pwm1=20 -MAXTEMP=hwmon2/device/pwm2=60 hwmon2/device/pwm1=60 -MINSTART=hwmon2/device/pwm2=75 hwmon2/device/pwm1=75 -MINSTOP=hwmon2/device/pwm2=22 hwmon2/device/pwm1=22 +DEVPATH=hwmon1=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f +DEVNAME=hwmon1=w83795adg +FCTEMPS=hwmon1/device/pwm2=hwmon1/device/temp2_input hwmon1/device/pwm1=hwmon1/device/temp2_input +FCFANS=hwmon1/device/pwm2=hwmon1/device/fan8_input hwmon1/device/pwm2=hwmon1/device/fan7_input hwmon1/device/pwm2=hwmon1/device/fan6_input hwmon1/device/pwm2=hwmon1/device/fan5_input hwmon1/device/pwm1=hwmon1/device/fan4_input hwmon1/device/pwm1=hwmon1/device/fan3_input hwmon1/device/pwm1=hwmon1/device/fan2_input hwmon1/device/pwm1=hwmon1/device/fan1_input +MINTEMP=hwmon1/device/pwm2=20 hwmon1/device/pwm1=20 +MAXTEMP=hwmon1/device/pwm2=60 hwmon1/device/pwm1=60 +MINSTART=hwmon1/device/pwm2=75 hwmon1/device/pwm1=75 +MINSTOP=hwmon1/device/pwm2=22 hwmon1/device/pwm1=22 diff --git a/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/plugins/sfputil.py b/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/plugins/sfputil.py index 7bc71c27eeb6..bef254484ac4 100644 --- a/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/plugins/sfputil.py +++ b/device/ingrasys/x86_64-ingrasys_s8810_32q-r0/plugins/sfputil.py @@ -1,61 +1,147 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") - - -class sfputil(sfputilbase): - """Platform specific sfputil class""" - - port_start = 0 - port_end = 31 - ports_in_block = 32 - - port_to_eeprom_mapping = {} - #FIXME - port_to_i2c_mapping = { - 0: 18, - 1: 19, - 2: 20, - 3: 21, - 4: 22, - 5: 23, - 6: 24, - 7: 25, - 8: 26, - 9: 27, - 10: 28, - 11: 29, - 12: 30, - 13: 31, - 14: 32, - 15: 33, - 16: 34, - 17: 35, - 18: 36, - 19: 37, - 20: 38, - 21: 39, - 22: 40, - 23: 41, - 24: 42, - 25: 43, - 26: 44, - 27: 45, - 28: 46, - 29: 47, - 30: 48, - 31: 49 - } - - _qsfp_ports = range(0, ports_in_block + 1) - - def __init__(self, port_num): + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 + + EEPROM_OFFSET = 18 + + ABS_GPIO_BASE = 224 + #INT_GPIO_BASE = 192 + LP_GPIO_BASE = 160 + RST_GPIO_BASE = 128 + + BASE_DIR_PATH = "/sys/class/gpio/gpio{0}/direction" + BASE_VAL_PATH = "/sys/class/gpio/gpio{0}/value" + + _port_to_eeprom_mapping = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom' + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + for x in range(self.port_start, self.port_end + 1): - port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) - self.port_to_eeprom_mapping[x] = port_eeprom_path - sfputilbase.__init__(self, port_num) + self._port_to_eeprom_mapping[x] = eeprom_path.format(x + self.EEPROM_OFFSET) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + abs_device_file = self.BASE_VAL_PATH.format( + port_num + self.ABS_GPIO_BASE) + val_file = open(abs_device_file) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + lpmode_val_device_file = self.BASE_VAL_PATH.format( + port_num + self.LP_GPIO_BASE) + val_file = open(lpmode_val_device_file) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + lpmode_val_device_file = self.BASE_VAL_PATH.format( + port_num + self.LP_GPIO_BASE) + val_file = open(lpmode_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("1" if lpmode is True else "0") + val_file.close() + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reset_val_device_file = self.BASE_VAL_PATH.format( + port_num + self.RST_GPIO_BASE) + val_file = open(reset_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("1") + val_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + try: + reset_val_device_file = self.BASE_VAL_PATH.format( + port_num + self.RST_GPIO_BASE) + val_file = open(reset_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("0") + val_file.close() + + return True diff --git a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/INGRASYS-S8900-54XC/port_config.ini b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/INGRASYS-S8900-54XC/port_config.ini index 24a2b8e29222..3350b68172cb 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/INGRASYS-S8900-54XC/port_config.ini +++ b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/INGRASYS-S8900-54XC/port_config.ini @@ -1,55 +1,55 @@ -# name lanes alias -Ethernet0 1 -Ethernet1 2 -Ethernet2 3 -Ethernet3 4 -Ethernet4 5 -Ethernet5 6 -Ethernet6 7 -Ethernet7 8 -Ethernet8 9 -Ethernet9 10 -Ethernet10 11 -Ethernet11 12 -Ethernet12 21 -Ethernet13 22 -Ethernet14 23 -Ethernet15 24 -Ethernet16 33 -Ethernet17 34 -Ethernet18 35 -Ethernet19 36 -Ethernet20 37 -Ethernet21 38 -Ethernet22 39 -Ethernet23 40 -Ethernet24 41 -Ethernet25 42 -Ethernet26 43 -Ethernet27 44 -Ethernet28 49 -Ethernet29 50 -Ethernet30 51 -Ethernet31 52 -Ethernet32 53 -Ethernet33 54 -Ethernet34 55 -Ethernet35 56 -Ethernet36 65 -Ethernet37 66 -Ethernet38 67 -Ethernet39 68 -Ethernet40 69 -Ethernet41 70 -Ethernet42 71 -Ethernet43 72 -Ethernet44 81 -Ethernet45 82 -Ethernet46 83 -Ethernet47 84 -Ethernet48 85,86,87,88 -Ethernet52 97,98,99,100 -Ethernet56 101,102,103,104 -Ethernet60 105,106,107,108 -Ethernet64 109,110,111,112 -Ethernet68 117,118,119,120 +# name lanes alias index +Ethernet0 1 Ethernet1 0 +Ethernet1 2 Ethernet2 1 +Ethernet2 3 Ethernet3 2 +Ethernet3 4 Ethernet4 3 +Ethernet4 5 Ethernet5 4 +Ethernet5 6 Ethernet6 5 +Ethernet6 7 Ethernet7 6 +Ethernet7 8 Ethernet8 7 +Ethernet8 9 Ethernet9 8 +Ethernet9 10 Ethernet10 9 +Ethernet10 11 Ethernet11 10 +Ethernet11 12 Ethernet12 11 +Ethernet12 21 Ethernet13 12 +Ethernet13 22 Ethernet14 13 +Ethernet14 23 Ethernet15 14 +Ethernet15 24 Ethernet16 15 +Ethernet16 33 Ethernet17 16 +Ethernet17 34 Ethernet18 17 +Ethernet18 35 Ethernet19 18 +Ethernet19 36 Ethernet20 19 +Ethernet20 37 Ethernet21 20 +Ethernet21 38 Ethernet22 21 +Ethernet22 39 Ethernet23 22 +Ethernet23 40 Ethernet24 23 +Ethernet24 41 Ethernet25 24 +Ethernet25 42 Ethernet26 25 +Ethernet26 43 Ethernet27 26 +Ethernet27 44 Ethernet28 27 +Ethernet28 49 Ethernet29 28 +Ethernet29 50 Ethernet30 29 +Ethernet30 51 Ethernet31 30 +Ethernet31 52 Ethernet32 31 +Ethernet32 53 Ethernet33 32 +Ethernet33 54 Ethernet34 33 +Ethernet34 55 Ethernet35 34 +Ethernet35 56 Ethernet36 35 +Ethernet36 65 Ethernet37 36 +Ethernet37 66 Ethernet38 37 +Ethernet38 67 Ethernet39 38 +Ethernet39 68 Ethernet40 39 +Ethernet40 69 Ethernet41 40 +Ethernet41 70 Ethernet42 41 +Ethernet42 71 Ethernet43 42 +Ethernet43 72 Ethernet44 43 +Ethernet44 81 Ethernet45 44 +Ethernet45 82 Ethernet46 45 +Ethernet46 83 Ethernet47 46 +Ethernet47 84 Ethernet48 47 +Ethernet48 85,86,87,88 Ethernet49/1 48 +Ethernet52 97,98,99,100 Ethernet50/1 49 +Ethernet56 101,102,103,104 Ethernet51/1 50 +Ethernet60 105,106,107,108 Ethernet52/1 51 +Ethernet64 109,110,111,112 Ethernet53/1 52 +Ethernet68 117,118,119,120 Ethernet54/1 53 diff --git a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/fancontrol b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/fancontrol index 827b0539546f..e1f88f6b79c5 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/fancontrol +++ b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/fancontrol @@ -1,11 +1,10 @@ # Configuration file generated by pwmconfig, changes will be lost INTERVAL=10 -DEVPATH=hwmon2=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f -DEVNAME=hwmon2=w83795adg -FCTEMPS=hwmon2/device/pwm2=hwmon2/device/temp2_input hwmon2/device/pwm1=hwmon2/device/temp2_input -#FCFANS=hwmon2/device/pwm2=hwmon2/device/fan8_input+hwmon2/device/fan7_input+hwmon2/device/fan6_input+hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input+hwmon2/device/fan3_input+hwmon2/device/fan2_input+hwmon2/device/fan1_input -FCFANS=hwmon2/device/pwm2=hwmon2/device/fan8_input hwmon2/device/pwm2=hwmon2/device/fan7_input hwmon2/device/pwm2=hwmon2/device/fan6_input hwmon2/device/pwm2=hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input hwmon2/device/pwm1=hwmon2/device/fan3_input hwmon2/device/pwm1=hwmon2/device/fan2_input hwmon2/device/pwm1=hwmon2/device/fan1_input -MINTEMP=hwmon2/device/pwm2=20 hwmon2/device/pwm1=20 -MAXTEMP=hwmon2/device/pwm2=60 hwmon2/device/pwm1=60 -MINSTART=hwmon2/device/pwm2=75 hwmon2/device/pwm1=75 -MINSTOP=hwmon2/device/pwm2=22 hwmon2/device/pwm1=22 +DEVPATH=hwmon1=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f +DEVNAME=hwmon1=w83795adg +FCTEMPS=hwmon1/device/pwm2=hwmon1/device/temp2_input hwmon1/device/pwm1=hwmon1/device/temp2_input +FCFANS=hwmon1/device/pwm2=hwmon1/device/fan8_input hwmon1/device/pwm2=hwmon1/device/fan7_input hwmon1/device/pwm2=hwmon1/device/fan6_input hwmon1/device/pwm2=hwmon1/device/fan5_input hwmon1/device/pwm1=hwmon1/device/fan4_input hwmon1/device/pwm1=hwmon1/device/fan3_input hwmon1/device/pwm1=hwmon1/device/fan2_input hwmon1/device/pwm1=hwmon1/device/fan1_input +MINTEMP=hwmon1/device/pwm2=20 hwmon1/device/pwm1=20 +MAXTEMP=hwmon1/device/pwm2=60 hwmon1/device/pwm1=60 +MINSTART=hwmon1/device/pwm2=75 hwmon1/device/pwm1=75 +MINSTOP=hwmon1/device/pwm2=22 hwmon1/device/pwm1=22 diff --git a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/minigraph.xml b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/minigraph.xml index 470b07922b9d..98c87eb8af0e 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/minigraph.xml +++ b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/minigraph.xml @@ -1,121 +1,121 @@ - - - - - - OCPSCH0104001MS - 10.10.1.30 - OCPSCH01040HHLF - 10.10.1.29 - 1 - 10 - 3 - - - OCPSCH0104002MS - 10.10.2.30 - OCPSCH01040HHLF - 10.10.2.29 - 1 - 10 - 3 - - - - - 64536 - OCPSCH01040HHLF - - -
10.10.1.30
- - -
- -
10.10.2.30
- - -
-
- -
- - 64542 - OCPSCH0104001MS - - - - 64543 - OCPSCH0104002MS - - -
-
- - - - - - HostIP - Loopback0 - - 100.0.0.10/32 - - 100.0.0.10/32 - - - - - - - - OCPSCH01040HHLF - - - - - - Ethernet48 - 10.10.1.29/30 - - - - Ethernet52 - 10.10.2.29/30 - - - - - - - - - - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet48 - OCPSCH01040HHLF - Ethernet48 - - - 40000 - DeviceInterfaceLink - OCPSCH0104002MS - Ethernet0 - OCPSCH01040HHLF - Ethernet52 - - - - - OCPSCH01040HHLF - INGRASYS-S8900-54XC - - - - OCPSCH01040HHLF - INGRASYS-S8900-54XC -
+ + + + + + OCPSCH0104001MS + 10.10.1.30 + OCPSCH01040HHLF + 10.10.1.29 + 1 + 10 + 3 + + + OCPSCH0104002MS + 10.10.2.30 + OCPSCH01040HHLF + 10.10.2.29 + 1 + 10 + 3 + + + + + 64536 + OCPSCH01040HHLF + + +
10.10.1.30
+ + +
+ +
10.10.2.30
+ + +
+
+ +
+ + 64542 + OCPSCH0104001MS + + + + 64543 + OCPSCH0104002MS + + +
+
+ + + + + + HostIP + Loopback0 + + 100.0.0.10/32 + + 100.0.0.10/32 + + + + + + + + OCPSCH01040HHLF + + + + + + Ethernet48 + 10.10.1.29/30 + + + + Ethernet52 + 10.10.2.29/30 + + + + + + + + + + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet48 + OCPSCH01040HHLF + Ethernet48 + + + 40000 + DeviceInterfaceLink + OCPSCH0104002MS + Ethernet0 + OCPSCH01040HHLF + Ethernet52 + + + + + OCPSCH01040HHLF + INGRASYS-S8900-54XC + + + + OCPSCH01040HHLF + INGRASYS-S8900-54XC +
diff --git a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/plugins/sfputil.py b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/plugins/sfputil.py index 96fa0fca86ce..0bb52e88616a 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/plugins/sfputil.py +++ b/device/ingrasys/x86_64-ingrasys_s8900_54xc-r0/plugins/sfputil.py @@ -1,19 +1,27 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 53 - ports_in_block = 54 + PORT_START = 0 + PORT_END = 53 + QSFP_PORT_START = 48 + PORTS_IN_BLOCK = 54 + + BASE_DIR_PATH = "/sys/class/gpio/gpio{0}/direction" + BASE_VAL_PATH = "/sys/class/gpio/gpio{0}/value" - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} port_to_i2c_mapping = { 0: 18, 1: 19, @@ -71,12 +79,201 @@ class sfputil(sfputilbase): 53: 71 } - _qsfp_ports = range(0, ports_in_block + 1) + abs_to_gpio_mapping = { + 0: 192, + 1: 193, + 2: 194, + 3: 195, + 4: 196, + 5: 197, + 6: 198, + 7: 199, + 8: 200, + 9: 201, + 10: 202, + 11: 203, + 12: 204, + 13: 205, + 14: 206, + 15: 207, + 16: 176, + 17: 177, + 18: 178, + 19: 179, + 20: 180, + 21: 181, + 22: 182, + 23: 183, + 24: 184, + 25: 185, + 26: 186, + 27: 187, + 28: 188, + 29: 189, + 30: 190, + 31: 191, + 32: 160, + 33: 161, + 34: 162, + 35: 163, + 36: 164, + 37: 165, + 38: 166, + 39: 167, + 40: 168, + 41: 169, + 42: 170, + 43: 171, + 44: 172, + 45: 173, + 46: 174, + 47: 175, + 48: 240, + 49: 241, + 50: 242, + 51: 243, + 52: 244, + 53: 245 + } + + lpmode_to_gpio_mapping = { + 48: 224, + 49: 225, + 50: 226, + 51: 227, + 52: 228, + 53: 229 + } + + reset_to_gpio_mapping = { + 48: 208, + 49: 209, + 50: 210, + 51: 211, + 52: 212, + 53: 213 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START - def __init__(self, port_num): + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom' + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + for x in range(self.port_start, self.port_end + 1): port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) self.port_to_eeprom_mapping[x] = port_eeprom_path - sfputilbase.__init__(self, port_num) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + abs_device_file = self.BASE_VAL_PATH.format( + self.abs_to_gpio_mapping[port_num]) + val_file = open(abs_device_file) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + return False + + try: + lpmode_val_device_file = self.BASE_VAL_PATH.format( + self.lpmode_to_gpio_mapping[port_num]) + val_file = open(lpmode_val_device_file) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + return False + + try: + lpmode_val_device_file = self.BASE_VAL_PATH.format( + self.lpmode_to_gpio_mapping[port_num]) + val_file = open(lpmode_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("1" if lpmode is True else "0") + val_file.close() + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + print "Error: unable to reset non-QSFP module: port %s" % str(port_num) + return False + + try: + print "port %s" % str(port_num) + reset_val_device_file = self.BASE_VAL_PATH.format( + self.reset_to_gpio_mapping[port_num]) + val_file = open(reset_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("1") + val_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + try: + reset_val_device_file = self.BASE_VAL_PATH.format( + self.reset_to_gpio_mapping[port_num]) + val_file = open(reset_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("0") + val_file.close() + + return True diff --git a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/INGRASYS-S8900-64XC/port_config.ini b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/INGRASYS-S8900-64XC/port_config.ini index 3e5c7be570e1..b950538edba7 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/INGRASYS-S8900-64XC/port_config.ini +++ b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/INGRASYS-S8900-64XC/port_config.ini @@ -1,65 +1,65 @@ -# name lanes alias -Ethernet0 17 -Ethernet1 18 -Ethernet2 19 -Ethernet3 20 -Ethernet4 24 -Ethernet5 23 -Ethernet6 22 -Ethernet7 21 -Ethernet8 28 -Ethernet9 27 -Ethernet10 26 -Ethernet11 25 -Ethernet12 32 -Ethernet13 31 -Ethernet14 30 -Ethernet15 29 -Ethernet16 1 -Ethernet17 2 -Ethernet18 3 -Ethernet19 4 -Ethernet20 8 -Ethernet21 7 -Ethernet22 6 -Ethernet23 5 -Ethernet24 12 -Ethernet25 11 -Ethernet26 10 -Ethernet27 9 -Ethernet28 13 -Ethernet29 14 -Ethernet30 15 -Ethernet31 16 -Ethernet32 33 -Ethernet33 34 -Ethernet34 35 -Ethernet35 36 -Ethernet36 38 -Ethernet37 39 -Ethernet38 40 -Ethernet39 37 -Ethernet40 41 -Ethernet41 42 -Ethernet42 43 -Ethernet43 44 -Ethernet44 48 -Ethernet45 45 -Ethernet46 46 -Ethernet47 47 -Ethernet48 49,50,51,52 -Ethernet52 53,54,55,56 -Ethernet56 57,58,59,60 -Ethernet60 61,62,63,64 -Ethernet64 65,66,67,68 -Ethernet68 69,70,71,72 -Ethernet72 73,74,75,76 -Ethernet76 77,78,79,80 -Ethernet80 81,82,83,84 -Ethernet84 85,86,87,88 -Ethernet88 89,90,91,92 -Ethernet92 93,94,95,96 -Ethernet96 97,98,99,100 -Ethernet100 101,102,103,104 -Ethernet104 105,106,107,108 -Ethernet108 109,110,111,112 +# name lanes alias index +Ethernet0 17 Ethernet1 0 +Ethernet1 18 Ethernet2 1 +Ethernet2 19 Ethernet3 2 +Ethernet3 20 Ethernet4 3 +Ethernet4 24 Ethernet5 4 +Ethernet5 23 Ethernet6 5 +Ethernet6 22 Ethernet7 6 +Ethernet7 21 Ethernet8 7 +Ethernet8 28 Ethernet9 8 +Ethernet9 27 Ethernet10 9 +Ethernet10 26 Ethernet11 10 +Ethernet11 25 Ethernet12 11 +Ethernet12 32 Ethernet13 12 +Ethernet13 31 Ethernet14 13 +Ethernet14 30 Ethernet15 14 +Ethernet15 29 Ethernet16 15 +Ethernet16 1 Ethernet17 16 +Ethernet17 2 Ethernet18 17 +Ethernet18 3 Ethernet19 18 +Ethernet19 4 Ethernet20 19 +Ethernet20 8 Ethernet21 20 +Ethernet21 7 Ethernet22 21 +Ethernet22 6 Ethernet23 22 +Ethernet23 5 Ethernet24 23 +Ethernet24 12 Ethernet25 24 +Ethernet25 11 Ethernet26 25 +Ethernet26 10 Ethernet27 26 +Ethernet27 9 Ethernet28 27 +Ethernet28 13 Ethernet29 28 +Ethernet29 14 Ethernet30 29 +Ethernet30 15 Ethernet31 30 +Ethernet31 16 Ethernet32 31 +Ethernet32 33 Ethernet33 32 +Ethernet33 34 Ethernet34 33 +Ethernet34 35 Ethernet35 34 +Ethernet35 36 Ethernet36 35 +Ethernet36 38 Ethernet37 36 +Ethernet37 39 Ethernet38 37 +Ethernet38 40 Ethernet39 38 +Ethernet39 37 Ethernet40 39 +Ethernet40 41 Ethernet41 40 +Ethernet41 42 Ethernet42 41 +Ethernet42 43 Ethernet43 42 +Ethernet43 44 Ethernet44 43 +Ethernet44 48 Ethernet45 44 +Ethernet45 45 Ethernet46 45 +Ethernet46 46 Ethernet47 46 +Ethernet47 47 Ethernet48 47 +Ethernet48 49,50,51,52 Ethernet49/1 48 +Ethernet52 53,54,55,56 Ethernet50/1 49 +Ethernet56 57,58,59,60 Ethernet51/1 50 +Ethernet60 61,62,63,64 Ethernet52/1 51 +Ethernet64 65,66,67,68 Ethernet53/1 52 +Ethernet68 69,70,71,72 Ethernet54/1 53 +Ethernet72 73,74,75,76 Ethernet55/1 54 +Ethernet76 77,78,79,80 Ethernet56/1 55 +Ethernet80 81,82,83,84 Ethernet57/1 56 +Ethernet84 85,86,87,88 Ethernet58/1 57 +Ethernet88 89,90,91,92 Ethernet59/1 58 +Ethernet92 93,94,95,96 Ethernet60/1 59 +Ethernet96 97,98,99,100 Ethernet61/1 60 +Ethernet100 101,102,103,104 Ethernet62/1 61 +Ethernet104 105,106,107,108 Ethernet63/1 62 +Ethernet108 109,110,111,112 Ethernet64/1 63 diff --git a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/fancontrol b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/fancontrol index cb07a7a07f4a..4819fe113172 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/fancontrol +++ b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/fancontrol @@ -1,10 +1,10 @@ # Configuration file generated by pwmconfig, changes will be lost INTERVAL=10 -DEVPATH=hwmon2=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f -DEVNAME=hwmon2=w83795adg -FCTEMPS=hwmon2/device/pwm1=hwmon2/device/temp2_input hwmon2/device/pwm2=hwmon2/device/temp2_input -FCFANS=hwmon2/device/pwm2=hwmon2/device/fan10_input hwmon2/device/pwm2=hwmon2/device/fan9_input hwmon2/device/pwm2=hwmon2/device/fan8_input hwmon2/device/pwm2=hwmon2/device/fan7_input hwmon2/device/pwm2=hwmon2/device/fan6_input hwmon2/device/pwm2=hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input hwmon2/device/pwm1=hwmon2/device/fan3_input hwmon2/device/pwm1=hwmon2/device/fan2_input hwmon2/device/pwm1=hwmon2/device/fan1_input -MINTEMP=hwmon2/device/pwm1=20 hwmon2/device/pwm2=20 -MAXTEMP=hwmon2/device/pwm1=60 hwmon2/device/pwm2=60 -MINSTART=hwmon2/device/pwm1=150 hwmon2/device/pwm2=150 -MINSTOP=hwmon2/device/pwm1=0 hwmon2/device/pwm2=0 +DEVPATH=hwmon1=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f +DEVNAME=hwmon1=w83795adg +FCTEMPS=hwmon1/device/pwm1=hwmon1/device/temp2_input hwmon1/device/pwm2=hwmon1/device/temp2_input +FCFANS=hwmon1/device/pwm2=hwmon1/device/fan10_input hwmon1/device/pwm2=hwmon1/device/fan9_input hwmon1/device/pwm2=hwmon1/device/fan8_input hwmon1/device/pwm2=hwmon1/device/fan7_input hwmon1/device/pwm2=hwmon1/device/fan6_input hwmon1/device/pwm2=hwmon1/device/fan5_input hwmon1/device/pwm1=hwmon1/device/fan4_input hwmon1/device/pwm1=hwmon1/device/fan3_input hwmon1/device/pwm1=hwmon1/device/fan2_input hwmon1/device/pwm1=hwmon1/device/fan1_input +MINTEMP=hwmon1/device/pwm1=20 hwmon1/device/pwm2=20 +MAXTEMP=hwmon1/device/pwm1=60 hwmon1/device/pwm2=60 +MINSTART=hwmon1/device/pwm1=150 hwmon1/device/pwm2=150 +MINSTOP=hwmon1/device/pwm1=0 hwmon1/device/pwm2=0 diff --git a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/minigraph.xml b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/minigraph.xml index fe96dc87acf6..8a7d765cefc1 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/minigraph.xml +++ b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/minigraph.xml @@ -1,359 +1,359 @@ - - - - - - BGPSession - OCPSCH0104001MS - 10.10.1.2 - OCPSCH01040AALF - 10.10.1.1 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.6 - OCPSCH01040BBLF - 10.10.1.5 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.10 - OCPSCH01040CCLF - 10.10.1.9 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.14 - OCPSCH01040DDLF - 10.10.1.13 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.18 - OCPSCH01040EELF - 10.10.1.17 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.22 - OCPSCH01040FFLF - 10.10.1.21 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.26 - OCPSCH01040GGLF - 10.10.1.25 - 1 - 10 - 3 - - - BGPSession - OCPSCH0104001MS - 10.10.1.30 - OCPSCH01040HHLF - 10.10.1.29 - 1 - 10 - 3 - - - - - 64542 - OCPSCH0104001MS - - - BGPPeer -
10.10.1.2
- - -
- - BGPPeer -
10.10.1.6
- - -
- - BGPPeer -
10.10.1.10
- - -
- - BGPPeer -
10.10.1.14
- - -
- - BGPPeer -
10.10.1.18
- - -
- - BGPPeer -
10.10.1.22
- - -
- - BGPPeer -
10.10.1.26
- - -
- - BGPPeer -
10.10.1.30
- - -
-
- -
- - 64536 - OCPSCH01040AALF - - - - 64536 - OCPSCH01040BBLF - - - - 64536 - OCPSCH01040CCLF - - - - 64536 - OCPSCH01040DDLF - - - - 64536 - OCPSCH01040EELF - - - - 64536 - OCPSCH01040FFLF - - - - 64536 - OCPSCH01040GGLF - - - - 64536 - OCPSCH01040HHLF - - -
-
- - - - - - LoopbackInterface - HostIP - Loopback0 - - 100.0.0.1/32 - - 100.0.0.1/32 - - - - - - - - OCPSCH0104001MS - - - - VlanInterface - Vlan851 - Ethernet0;Ethernet1;Ethernet2;Ethernet3;Ethernet96;Ethernet100;Ethernet104;Ethernet108 - False - 0.0.0.0/0 - - 851 - 10.20.1.0/24 - - - - - IPInterface - - Vlan851 - 10.20.1.1/24 - - - IPInterface - - Ethernet48 - 10.10.1.2/30 - - - IPInterface - - Ethernet52 - 10.10.1.6/30 - - - IPInterface - - Ethernet56 - 10.10.1.10/30 - - - IPInterface - - Ethernet60 - 10.10.1.14/30 - - - IPInterface - - Ethernet64 - 10.10.1.18/30 - - - IPInterface - - Ethernet68 - 10.10.1.22/30 - - - IPInterface - - Ethernet72 - 10.10.1.26/30 - - - IPInterface - - Ethernet76 - 10.10.1.30/30 - - - - - - - - - - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet48 - OCPSCH01040AALF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet52 - OCPSCH01040BBLF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet56 - OCPSCH01040CCLF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet60 - OCPSCH01040DDLF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet64 - OCPSCH01040EELF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet68 - OCPSCH01040FFLF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet72 - OCPSCH01040GGLF - Ethernet0 - - - 40000 - DeviceInterfaceLink - OCPSCH0104001MS - Ethernet76 - OCPSCH01040HHLF - Ethernet48 - - - - - OCPSCH0104001MS - INGRASYS-S8900-64XC - - - - - - - - OCPSCH0104001MS - INGRASYS-S8900-64XC -
+ + + + + + BGPSession + OCPSCH0104001MS + 10.10.1.2 + OCPSCH01040AALF + 10.10.1.1 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.6 + OCPSCH01040BBLF + 10.10.1.5 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.10 + OCPSCH01040CCLF + 10.10.1.9 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.14 + OCPSCH01040DDLF + 10.10.1.13 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.18 + OCPSCH01040EELF + 10.10.1.17 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.22 + OCPSCH01040FFLF + 10.10.1.21 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.26 + OCPSCH01040GGLF + 10.10.1.25 + 1 + 10 + 3 + + + BGPSession + OCPSCH0104001MS + 10.10.1.30 + OCPSCH01040HHLF + 10.10.1.29 + 1 + 10 + 3 + + + + + 64542 + OCPSCH0104001MS + + + BGPPeer +
10.10.1.2
+ + +
+ + BGPPeer +
10.10.1.6
+ + +
+ + BGPPeer +
10.10.1.10
+ + +
+ + BGPPeer +
10.10.1.14
+ + +
+ + BGPPeer +
10.10.1.18
+ + +
+ + BGPPeer +
10.10.1.22
+ + +
+ + BGPPeer +
10.10.1.26
+ + +
+ + BGPPeer +
10.10.1.30
+ + +
+
+ +
+ + 64536 + OCPSCH01040AALF + + + + 64536 + OCPSCH01040BBLF + + + + 64536 + OCPSCH01040CCLF + + + + 64536 + OCPSCH01040DDLF + + + + 64536 + OCPSCH01040EELF + + + + 64536 + OCPSCH01040FFLF + + + + 64536 + OCPSCH01040GGLF + + + + 64536 + OCPSCH01040HHLF + + +
+
+ + + + + + LoopbackInterface + HostIP + Loopback0 + + 100.0.0.1/32 + + 100.0.0.1/32 + + + + + + + + OCPSCH0104001MS + + + + VlanInterface + Vlan851 + Ethernet0;Ethernet1;Ethernet2;Ethernet3;Ethernet96;Ethernet100;Ethernet104;Ethernet108 + False + 0.0.0.0/0 + + 851 + 10.20.1.0/24 + + + + + IPInterface + + Vlan851 + 10.20.1.1/24 + + + IPInterface + + Ethernet48 + 10.10.1.2/30 + + + IPInterface + + Ethernet52 + 10.10.1.6/30 + + + IPInterface + + Ethernet56 + 10.10.1.10/30 + + + IPInterface + + Ethernet60 + 10.10.1.14/30 + + + IPInterface + + Ethernet64 + 10.10.1.18/30 + + + IPInterface + + Ethernet68 + 10.10.1.22/30 + + + IPInterface + + Ethernet72 + 10.10.1.26/30 + + + IPInterface + + Ethernet76 + 10.10.1.30/30 + + + + + + + + + + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet48 + OCPSCH01040AALF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet52 + OCPSCH01040BBLF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet56 + OCPSCH01040CCLF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet60 + OCPSCH01040DDLF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet64 + OCPSCH01040EELF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet68 + OCPSCH01040FFLF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet72 + OCPSCH01040GGLF + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet76 + OCPSCH01040HHLF + Ethernet48 + + + + + OCPSCH0104001MS + INGRASYS-S8900-64XC + + + + + + + + OCPSCH0104001MS + INGRASYS-S8900-64XC +
diff --git a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/plugins/sfputil.py b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/plugins/sfputil.py index d6573d20d72f..0b1ae8d3bc8e 100644 --- a/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/plugins/sfputil.py +++ b/device/ingrasys/x86_64-ingrasys_s8900_64xc-r0/plugins/sfputil.py @@ -1,24 +1,30 @@ -#!/usr/bin/env python - -import subprocess +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + import subprocess + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + i2c_set = 'i2cset' +i2c_get = 'i2cget' cpld_addr = '0x33' mux_reg = '0x4A' -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 63 - ports_in_block = 64 + PORT_START = 0 + PORT_END = 63 + QSFP_PORT_START = 48 + PORTS_IN_BLOCK = 64 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} port_to_i2c_mapping = { 0: [2,1], 1: [2,2], @@ -44,64 +50,207 @@ class sfputil(sfputilbase): 21: [2,22], 22: [2,23], 23: [2,24], - 24: [3,1], - 25: [3,2], - 26: [3,3], - 27: [3,4], - 28: [3,5], - 29: [3,6], - 30: [3,7], - 31: [3,8], - 32: [3,9], - 33: [3,10], - 34: [3,11], - 35: [3,12], - 36: [3,13], - 37: [3,14], - 38: [3,15], - 39: [3,16], - 40: [3,17], - 41: [3,18], - 42: [3,19], - 43: [3,20], - 44: [3,21], - 45: [3,22], - 46: [3,23], - 47: [3,24], - 48: [4,1], - 49: [4,2], - 50: [4,3], - 51: [4,4], - 52: [4,5], - 53: [4,6], - 54: [4,7], - 55: [4,8], - 56: [4,9], - 57: [4,10], - 58: [4,11], - 59: [4,12], - 60: [4,13], - 61: [4,14], - 62: [4,15], - 63: [4,16] + 24: [3,25], + 25: [3,26], + 26: [3,27], + 27: [3,28], + 28: [3,29], + 29: [3,30], + 30: [3,31], + 31: [3,32], + 32: [3,33], + 33: [3,34], + 34: [3,35], + 35: [3,36], + 36: [3,37], + 37: [3,38], + 38: [3,39], + 39: [3,40], + 40: [3,41], + 41: [3,42], + 42: [3,43], + 43: [3,44], + 44: [3,45], + 45: [3,46], + 46: [3,47], + 47: [3,48], + 48: [4,49], + 49: [4,50], + 50: [4,51], + 51: [4,52], + 52: [4,53], + 53: [4,54], + 54: [4,55], + 55: [4,56], + 56: [4,57], + 57: [4,58], + 58: [4,59], + 59: [4,60], + 60: [4,61], + 61: [4,62], + 62: [4,63], + 63: [4,64] } + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END - _qsfp_ports = range(0, ports_in_block + 1) + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - i2c_bus = self.port_to_i2c_mapping[port_num][0] - sfp_idx = self.port_to_i2c_mapping[port_num][1] - proc = subprocess.Popen([i2c_set, '-y', str(i2c_bus), cpld_addr, mux_reg, str(sfp_idx)], - stdout=subprocess.PIPE, - shell=False, - stderr=subprocess.STDOUT) - stdout = proc.communicate()[0] - proc.wait() + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping - eeprom_path = '/sys/class/i2c-adapter/i2c-{0[0]}/{0[0]}-0050/eeprom' - for x in range(self.port_start, self.port_end + 1): - port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + def __init__(self): + + sfp_eeprom_path = '/sys/bus/i2c/devices/{0[0]}-0050/sfp{0[1]}' + qsfp_eeprom_path = '/sys/bus/i2c/devices/{0[0]}-0050/qsfp{0[1]}' + for x in range(self.port_start, self.qsfp_port_start): + port_eeprom_path = sfp_eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + for x in range(self.qsfp_port_start, self.port_end + 1): + port_eeprom_path = qsfp_eeprom_path.format(self.port_to_i2c_mapping[x]) self.port_to_eeprom_mapping[x] = port_eeprom_path - sfputilbase.__init__(self, port_num) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/ingrasys-s8900-64xc-cpld.0/qsfp_modprs") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # content is a string, either "0" or "1" + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/ingrasys-s8900-64xc-cpld.0/qsfp_lpmode") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << (port_num - self.qsfp_port_start) ) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/devices/platform/ingrasys-s8900-64xc-cpld.0/qsfp_lpmode", "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << (port_num - self.qsfp_port_start) ) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def reset(self, port_num): + QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/devices/platform/ingrasys-s8900-64xc-cpld.0/qsfp_reset" + + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + return False + + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # File content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Mask off the bit corresponding to our port + mask = (1 << (port_num - self.qsfp_port_start)) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + # Flip the bit back high and write back to the register to take port out of reset + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + return True diff --git a/device/ingrasys/x86_64-ingrasys_s9100-r0/INGRASYS-S9100-C32/port_config.ini b/device/ingrasys/x86_64-ingrasys_s9100-r0/INGRASYS-S9100-C32/port_config.ini index d70c717fe4e2..ab0202011576 100644 --- a/device/ingrasys/x86_64-ingrasys_s9100-r0/INGRASYS-S9100-C32/port_config.ini +++ b/device/ingrasys/x86_64-ingrasys_s9100-r0/INGRASYS-S9100-C32/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias -Ethernet0 5,6,7,8 -Ethernet4 1,2,3,4 -Ethernet8 13,14,15,16 -Ethernet12 9,10,11,12 -Ethernet16 21,22,23,24 -Ethernet20 17,18,19,20 -Ethernet24 29,30,31,32 -Ethernet28 25,26,27,28 -Ethernet32 37,38,39,40 -Ethernet36 33,34,35,36 -Ethernet40 45,46,47,48 -Ethernet44 41,42,43,44 -Ethernet48 53,54,55,56 -Ethernet52 49,50,51,52 -Ethernet56 61,62,63,64 -Ethernet60 57,58,59,60 -Ethernet64 69,70,71,72 -Ethernet68 65,66,67,68 -Ethernet72 77,78,79,80 -Ethernet76 73,74,75,76 -Ethernet80 85,86,87,88 -Ethernet84 81,82,83,84 -Ethernet88 93,94,95,96 -Ethernet92 89,90,91,92 -Ethernet96 101,102,103,104 -Ethernet100 97,98,99,100 -Ethernet104 109,110,111,112 -Ethernet108 105,106,107,108 -Ethernet112 117,118,119,120 -Ethernet116 113,114,115,116 -Ethernet120 125,126,127,128 -Ethernet124 121,122,123,124 +# name lanes alias index +Ethernet0 5,6,7,8 Ethernet1/1 0 +Ethernet4 1,2,3,4 Ethernet2/1 1 +Ethernet8 13,14,15,16 Ethernet3/1 2 +Ethernet12 9,10,11,12 Ethernet4/1 3 +Ethernet16 21,22,23,24 Ethernet5/1 4 +Ethernet20 17,18,19,20 Ethernet6/1 5 +Ethernet24 29,30,31,32 Ethernet7/1 6 +Ethernet28 25,26,27,28 Ethernet8/1 7 +Ethernet32 37,38,39,40 Ethernet9/1 8 +Ethernet36 33,34,35,36 Ethernet10/1 9 +Ethernet40 45,46,47,48 Ethernet11/1 10 +Ethernet44 41,42,43,44 Ethernet12/1 11 +Ethernet48 53,54,55,56 Ethernet13/1 12 +Ethernet52 49,50,51,52 Ethernet14/1 13 +Ethernet56 61,62,63,64 Ethernet15/1 14 +Ethernet60 57,58,59,60 Ethernet16/1 15 +Ethernet64 69,70,71,72 Ethernet17/1 16 +Ethernet68 65,66,67,68 Ethernet18/1 17 +Ethernet72 77,78,79,80 Ethernet19/1 18 +Ethernet76 73,74,75,76 Ethernet20/1 19 +Ethernet80 85,86,87,88 Ethernet21/1 20 +Ethernet84 81,82,83,84 Ethernet22/1 21 +Ethernet88 93,94,95,96 Ethernet23/1 22 +Ethernet92 89,90,91,92 Ethernet24/1 23 +Ethernet96 101,102,103,104 Ethernet25/1 24 +Ethernet100 97,98,99,100 Ethernet26/1 25 +Ethernet104 109,110,111,112 Ethernet27/1 26 +Ethernet108 105,106,107,108 Ethernet28/1 27 +Ethernet112 117,118,119,120 Ethernet29/1 28 +Ethernet116 113,114,115,116 Ethernet30/1 29 +Ethernet120 125,126,127,128 Ethernet31/1 30 +Ethernet124 121,122,123,124 Ethernet32/1 31 diff --git a/device/ingrasys/x86_64-ingrasys_s9100-r0/fancontrol b/device/ingrasys/x86_64-ingrasys_s9100-r0/fancontrol index 827b0539546f..e1f88f6b79c5 100644 --- a/device/ingrasys/x86_64-ingrasys_s9100-r0/fancontrol +++ b/device/ingrasys/x86_64-ingrasys_s9100-r0/fancontrol @@ -1,11 +1,10 @@ # Configuration file generated by pwmconfig, changes will be lost INTERVAL=10 -DEVPATH=hwmon2=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f -DEVNAME=hwmon2=w83795adg -FCTEMPS=hwmon2/device/pwm2=hwmon2/device/temp2_input hwmon2/device/pwm1=hwmon2/device/temp2_input -#FCFANS=hwmon2/device/pwm2=hwmon2/device/fan8_input+hwmon2/device/fan7_input+hwmon2/device/fan6_input+hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input+hwmon2/device/fan3_input+hwmon2/device/fan2_input+hwmon2/device/fan1_input -FCFANS=hwmon2/device/pwm2=hwmon2/device/fan8_input hwmon2/device/pwm2=hwmon2/device/fan7_input hwmon2/device/pwm2=hwmon2/device/fan6_input hwmon2/device/pwm2=hwmon2/device/fan5_input hwmon2/device/pwm1=hwmon2/device/fan4_input hwmon2/device/pwm1=hwmon2/device/fan3_input hwmon2/device/pwm1=hwmon2/device/fan2_input hwmon2/device/pwm1=hwmon2/device/fan1_input -MINTEMP=hwmon2/device/pwm2=20 hwmon2/device/pwm1=20 -MAXTEMP=hwmon2/device/pwm2=60 hwmon2/device/pwm1=60 -MINSTART=hwmon2/device/pwm2=75 hwmon2/device/pwm1=75 -MINSTOP=hwmon2/device/pwm2=22 hwmon2/device/pwm1=22 +DEVPATH=hwmon1=devices/pci0000:00/0000:00:1f.3/i2c-0/0-002f +DEVNAME=hwmon1=w83795adg +FCTEMPS=hwmon1/device/pwm2=hwmon1/device/temp2_input hwmon1/device/pwm1=hwmon1/device/temp2_input +FCFANS=hwmon1/device/pwm2=hwmon1/device/fan8_input hwmon1/device/pwm2=hwmon1/device/fan7_input hwmon1/device/pwm2=hwmon1/device/fan6_input hwmon1/device/pwm2=hwmon1/device/fan5_input hwmon1/device/pwm1=hwmon1/device/fan4_input hwmon1/device/pwm1=hwmon1/device/fan3_input hwmon1/device/pwm1=hwmon1/device/fan2_input hwmon1/device/pwm1=hwmon1/device/fan1_input +MINTEMP=hwmon1/device/pwm2=20 hwmon1/device/pwm1=20 +MAXTEMP=hwmon1/device/pwm2=60 hwmon1/device/pwm1=60 +MINSTART=hwmon1/device/pwm2=75 hwmon1/device/pwm1=75 +MINSTOP=hwmon1/device/pwm2=22 hwmon1/device/pwm1=22 diff --git a/device/ingrasys/x86_64-ingrasys_s9100-r0/plugins/sfputil.py b/device/ingrasys/x86_64-ingrasys_s9100-r0/plugins/sfputil.py index f45502ab9ab4..f4ffc29bebc6 100644 --- a/device/ingrasys/x86_64-ingrasys_s9100-r0/plugins/sfputil.py +++ b/device/ingrasys/x86_64-ingrasys_s9100-r0/plugins/sfputil.py @@ -1,19 +1,26 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 31 - ports_in_block = 32 + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 - port_to_eeprom_mapping = {} + BASE_DIR_PATH = "/sys/class/gpio/gpio{0}/direction" + BASE_VAL_PATH = "/sys/class/gpio/gpio{0}/value" + + _port_to_eeprom_mapping = {} port_to_i2c_mapping = { 0: 11, 1: 10, @@ -49,12 +56,227 @@ class sfputil(sfputilbase): 31: 40 } - _qsfp_ports = range(0, ports_in_block + 1) + abs_to_gpio_mapping = { + 0: 241, + 1: 240, + 2: 243, + 3: 242, + 4: 245, + 5: 244, + 6: 247, + 7: 246, + 8: 249, + 9: 248, + 10: 251, + 11: 250, + 12: 253, + 13: 252, + 14: 255, + 15: 254, + 16: 225, + 17: 224, + 18: 227, + 19: 226, + 20: 229, + 21: 228, + 22: 231, + 23: 230, + 24: 233, + 25: 232, + 26: 235, + 27: 234, + 28: 237, + 29: 236, + 30: 239, + 31: 238 + } + + lpmode_to_gpio_mapping = { + 0: 177, + 1: 176, + 2: 179, + 3: 178, + 4: 181, + 5: 180, + 6: 183, + 7: 182, + 8: 185, + 9: 184, + 10: 187, + 11: 186, + 12: 189, + 13: 188, + 14: 191, + 15: 190, + 16: 161, + 17: 160, + 18: 163, + 19: 162, + 20: 165, + 21: 164, + 22: 167, + 23: 166, + 24: 169, + 25: 168, + 26: 171, + 27: 170, + 28: 173, + 29: 172, + 30: 175, + 31: 174 + } + + reset_to_gpio_mapping = { + 0: 145, + 1: 144, + 2: 147, + 3: 146, + 4: 149, + 5: 148, + 6: 151, + 7: 150, + 8: 153, + 9: 152, + 10: 155, + 11: 154, + 12: 157, + 13: 156, + 14: 159, + 15: 158, + 16: 129, + 17: 128, + 18: 131, + 19: 130, + 20: 133, + 21: 132, + 22: 135, + 23: 134, + 24: 137, + 25: 136, + 26: 139, + 27: 138, + 28: 141, + 29: 140, + 30: 143, + 31: 142 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) - def __init__(self, port_num): + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom' + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + for x in range(self.port_start, self.port_end + 1): port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) self.port_to_eeprom_mapping[x] = port_eeprom_path - sfputilbase.__init__(self, port_num) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + abs_device_file = self.BASE_VAL_PATH.format( + self.abs_to_gpio_mapping[port_num]) + val_file = open(abs_device_file) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + lpmode_val_device_file = self.BASE_VAL_PATH.format( + self.lpmode_to_gpio_mapping[port_num]) + val_file = open(lpmode_val_device_file) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + lpmode_val_device_file = self.BASE_VAL_PATH.format( + self.lpmode_to_gpio_mapping[port_num]) + val_file = open(lpmode_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("1" if lpmode is True else "0") + val_file.close() + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reset_val_device_file = self.BASE_VAL_PATH.format( + self.reset_to_gpio_mapping[port_num]) + val_file = open(reset_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("1") + val_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + try: + reset_val_device_file = self.BASE_VAL_PATH.format( + self.reset_to_gpio_mapping[port_num]) + val_file = open(reset_val_device_file, "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + val_file.write("0") + val_file.close() + + return True diff --git a/device/mellanox/x86_64-mlnx_msn2410-r0/minigraph.xml b/device/mellanox/x86_64-mlnx_msn2410-r0/minigraph.xml index ed21b8d6eeb9..ea765fab814d 100644 --- a/device/mellanox/x86_64-mlnx_msn2410-r0/minigraph.xml +++ b/device/mellanox/x86_64-mlnx_msn2410-r0/minigraph.xml @@ -2,11 +2,461 @@ + + ARISTA01T0 + 10.0.0.33 + switch2 + 10.0.0.32 + 1 + 180 + 60 + + + switch2 + 10.0.0.0 + ARISTA01T2 + 10.0.0.1 + 1 + 180 + 60 + + + ARISTA02T0 + 10.0.0.35 + switch2 + 10.0.0.34 + 1 + 180 + 60 + + + switch2 + 10.0.0.2 + ARISTA02T2 + 10.0.0.3 + 1 + 180 + 60 + + + ARISTA03T0 + 10.0.0.37 + switch2 + 10.0.0.36 + 1 + 180 + 60 + + + switch2 + 10.0.0.4 + ARISTA03T2 + 10.0.0.5 + 1 + 180 + 60 + + + ARISTA04T0 + 10.0.0.39 + switch2 + 10.0.0.38 + 1 + 180 + 60 + + + switch2 + 10.0.0.6 + ARISTA04T2 + 10.0.0.7 + 1 + 180 + 60 + + + ARISTA05T0 + 10.0.0.41 + switch2 + 10.0.0.40 + 1 + 180 + 60 + + + switch2 + 10.0.0.8 + ARISTA05T2 + 10.0.0.9 + 1 + 180 + 60 + + + ARISTA06T0 + 10.0.0.43 + switch2 + 10.0.0.42 + 1 + 180 + 60 + + + switch2 + 10.0.0.10 + ARISTA06T2 + 10.0.0.11 + 1 + 180 + 60 + + + ARISTA07T0 + 10.0.0.45 + switch2 + 10.0.0.44 + 1 + 180 + 60 + + + switch2 + 10.0.0.12 + ARISTA07T2 + 10.0.0.13 + 1 + 180 + 60 + + + ARISTA08T0 + 10.0.0.47 + switch2 + 10.0.0.46 + 1 + 180 + 60 + + + switch2 + 10.0.0.14 + ARISTA08T2 + 10.0.0.15 + 1 + 180 + 60 + + + ARISTA09T0 + 10.0.0.49 + switch2 + 10.0.0.48 + 1 + 180 + 60 + + + switch2 + 10.0.0.16 + ARISTA09T2 + 10.0.0.17 + 1 + 180 + 60 + + + ARISTA10T0 + 10.0.0.51 + switch2 + 10.0.0.50 + 1 + 180 + 60 + + + switch2 + 10.0.0.18 + ARISTA10T2 + 10.0.0.19 + 1 + 180 + 60 + + + ARISTA11T0 + 10.0.0.53 + switch2 + 10.0.0.52 + 1 + 180 + 60 + + + switch2 + 10.0.0.20 + ARISTA11T2 + 10.0.0.21 + 1 + 180 + 60 + + + ARISTA12T0 + 10.0.0.55 + switch2 + 10.0.0.54 + 1 + 180 + 60 + + + switch2 + 10.0.0.22 + ARISTA12T2 + 10.0.0.23 + 1 + 180 + 60 + + + ARISTA13T0 + 10.0.0.57 + switch2 + 10.0.0.56 + 1 + 180 + 60 + + + switch2 + 10.0.0.24 + ARISTA13T2 + 10.0.0.25 + 1 + 180 + 60 + + + ARISTA14T0 + 10.0.0.59 + switch2 + 10.0.0.58 + 1 + 180 + 60 + + + switch2 + 10.0.0.26 + ARISTA14T2 + 10.0.0.27 + 1 + 180 + 60 + + + ARISTA15T0 + 10.0.0.61 + switch2 + 10.0.0.60 + 1 + 180 + 60 + + + switch2 + 10.0.0.28 + ARISTA15T2 + 10.0.0.29 + 1 + 180 + 60 + + + ARISTA16T0 + 10.0.0.63 + switch2 + 10.0.0.62 + 1 + 180 + 60 + + + switch2 + 10.0.0.30 + ARISTA16T2 + 10.0.0.31 + 1 + 180 + 60 + 65100 switch2 + + +
10.0.0.33
+ + +
+ +
10.0.0.1
+ + +
+ +
10.0.0.35
+ + +
+ +
10.0.0.3
+ + +
+ +
10.0.0.37
+ + +
+ +
10.0.0.5
+ + +
+ +
10.0.0.39
+ + +
+ +
10.0.0.7
+ + +
+ +
10.0.0.41
+ + +
+ +
10.0.0.9
+ + +
+ +
10.0.0.43
+ + +
+ +
10.0.0.11
+ + +
+ +
10.0.0.45
+ + +
+ +
10.0.0.13
+ + +
+ +
10.0.0.47
+ + +
+ +
10.0.0.15
+ + +
+ +
10.0.0.49
+ + +
+ +
10.0.0.17
+ + +
+ +
10.0.0.51
+ + +
+ +
10.0.0.19
+ + +
+ +
10.0.0.53
+ + +
+ +
10.0.0.21
+ + +
+ +
10.0.0.55
+ + +
+ +
10.0.0.23
+ + +
+ +
10.0.0.57
+ + +
+ +
10.0.0.25
+ + +
+ +
10.0.0.59
+ + +
+ +
10.0.0.27
+ + +
+ +
10.0.0.61
+ + +
+ +
10.0.0.29
+ + +
+ +
10.0.0.63
+ + +
+ +
10.0.0.31
+ + +
+
@@ -482,13 +932,237 @@ + + DeviceInterfaceLink + switch2 + Ethernet0 + ARISTA01T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet4 + ARISTA02T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet8 + ARISTA03T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet12 + ARISTA04T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet16 + ARISTA05T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet20 + ARISTA06T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet24 + ARISTA07T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet28 + ARISTA08T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet32 + ARISTA09T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet36 + ARISTA10T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet40 + ARISTA11T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet44 + ARISTA12T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet48 + ARISTA13T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet52 + ARISTA14T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet56 + ARISTA15T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet60 + ARISTA16T2 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet64 + ARISTA01T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet68 + ARISTA02T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet72 + ARISTA03T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet76 + ARISTA04T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet80 + ARISTA05T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet84 + ARISTA06T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet88 + ARISTA07T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet92 + ARISTA08T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet96 + ARISTA09T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet100 + ARISTA10T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet104 + ARISTA11T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet108 + ARISTA12T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet112 + ARISTA13T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet116 + ARISTA14T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet120 + ARISTA15T0 + Ethernet1 + + + DeviceInterfaceLink + switch2 + Ethernet124 + ARISTA16T0 + Ethernet1 + switch2 ACS-MSN2410 - ` + diff --git a/dockers/docker-dhcp-relay/Dockerfile.j2 b/dockers/docker-dhcp-relay/Dockerfile.j2 index a7e1a1cffb9d..3c6614c4921f 100644 --- a/dockers/docker-dhcp-relay/Dockerfile.j2 +++ b/dockers/docker-dhcp-relay/Dockerfile.j2 @@ -25,5 +25,6 @@ RUN rm -rf /debs COPY ["start.sh", "isc-dhcp-relay.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["isc-dhcp-relay.j2", "/usr/share/sonic/templates/"] +COPY ["wait_for_intf.sh.j2", "/usr/share/sonic/templates/"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 b/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 index 1c50b685ebda..cdedfcf9692b 100644 --- a/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 +++ b/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 @@ -1,25 +1,25 @@ -SERVERS="{{ dhcp_servers | join(' ') }}" +SERVERS="{{ DHCP_SERVER | join(' ') }}" INTERFACES=" {%- set add_preceding_space = { 'flag': False } %} -{%- for interface in minigraph_interfaces %} -{%- if interface['addr'] | ipv4 %} +{%- for (name, prefix) in INTERFACE %} +{%- if prefix | ipv4 %} {%- if add_preceding_space.flag %} {% endif %} -{{ interface['attachto'] }} +{{ name }} {%- set _dummy = add_preceding_space.update({'flag': True}) %} {%- endif %} {%- endfor %} -{%- for vlan_interface in minigraph_vlan_interfaces %} -{%- if vlan_interface['addr'] | ipv4 %} +{%- for (name, prefix) in VLAN_INTERFACE %} +{%- if prefix | ipv4 %} {%- if add_preceding_space.flag %} {% endif %} -{{ vlan_interface['attachto'] }} +{{ name }} {%- set _dummy = add_preceding_space.update({'flag': True}) %} {%- endif %} {%- endfor %} -{%- for pc_interface in minigraph_portchannel_interfaces %} -{%- if pc_interface['addr'] | ipv4 %} +{%- for (name, prefix) in PORTCHANNEL_INTERFACE %} +{%- if prefix | ipv4 %} {%- if add_preceding_space.flag %} {% endif %} -{{ pc_interface['attachto'] }} +{{ name }} {%- set _dummy = add_preceding_space.update({'flag': True}) %} {%- endif %} {%- endfor %}" diff --git a/dockers/docker-dhcp-relay/start.sh b/dockers/docker-dhcp-relay/start.sh index 5c2e9de09703..37c3f488a5c7 100755 --- a/dockers/docker-dhcp-relay/start.sh +++ b/dockers/docker-dhcp-relay/start.sh @@ -1,42 +1,16 @@ #!/usr/bin/env bash -function wait_until_iface_exists -{ - IFACE=$1 - - echo "Waiting for interface ${IFACE}..." - - # Wait for the interface to come up (i.e., 'ip link show' returns 0) - until ip link show $IFACE > /dev/null 2>&1; do - sleep 1 - done - - echo "Interface ${IFACE} is created" -} - # Create isc-dhcp-relay config file -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/isc-dhcp-relay.j2 > /etc/default/isc-dhcp-relay +sonic-cfggen -d -t /usr/share/sonic/templates/isc-dhcp-relay.j2 > /etc/default/isc-dhcp-relay rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd # Wait for all interfaces to come up before starting the DHCP relay - -FRONT_PANEL_IFACES=$(sonic-cfggen -m /etc/sonic/minigraph.xml --var-json "minigraph_interfaces" | grep "\"attachto\":" | sed 's/^\s*"attachto":\s"\(.*\)".*$/\1/') -for IFACE in $FRONT_PANEL_IFACES; do - wait_until_iface_exists $IFACE -done - -VLAN_IFACES=$(sonic-cfggen -m /etc/sonic/minigraph.xml --var-json "minigraph_vlan_interfaces" | grep "\"attachto\":" | sed 's/^\s*"attachto":\s"\(.*\)".*$/\1/') -for IFACE in $VLAN_IFACES; do - wait_until_iface_exists $IFACE -done - -PORTCHANNEL_IFACES=$(sonic-cfggen -m /etc/sonic/minigraph.xml --var-json "minigraph_portchannel_interfaces" | grep "\"attachto\":" | sed 's/^\s*"attachto":\s"\(.*\)".*$/\1/') -for IFACE in $PORTCHANNEL_IFACES; do - wait_until_iface_exists $IFACE -done +sonic-cfggen -d -t /usr/share/sonic/templates/wait_for_intf.sh.j2 > /usr/bin/wait_for_intf.sh +chmod +x /usr/bin/wait_for_intf.sh +/usr/bin/wait_for_intf.sh # Start the DHCP relay supervisorctl start isc-dhcp-relay diff --git a/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 b/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 new file mode 100755 index 000000000000..b859a43b07b1 --- /dev/null +++ b/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +function wait_until_iface_exists +{ + IFACE=$1 + + echo "Waiting for interface ${IFACE}..." + + # Wait for the interface to come up (i.e., 'ip link show' returns 0) + until ip link show $IFACE > /dev/null 2>&1; do + sleep 1 + done + + echo "Interface ${IFACE} is created" +} + + +# Wait for all interfaces to come up before starting the DHCP relay +{% for (name, prefix) in INTERFACE %} +wait_until_iface_exists {{ name }} +{% endfor %} +{% for (name, prefix) in VLAN_INTERFACE %} +wait_until_iface_exists {{ name }} +{% endfor %} +{% for (name, prefix) in PORTCHANNEL_INTERFACE %} +wait_until_iface_exists {{ name }} +{% endfor %} + diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index 09614c965ee6..5452a976368a 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -1,13 +1,13 @@ ! {% block banner %} ! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/quagga/bgpd.conf.j2 using minigraph_facts.py +! generated by templates/quagga/bgpd.conf.j2 with config DB data ! file: bgpd.conf ! {% endblock banner %} ! {% block system_init %} -hostname {{ inventory_hostname }} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} password zebra log syslog informational log facility local4 @@ -23,41 +23,41 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp bestpath as-path multipath-relax no bgp default ipv4-unicast {# TODO: use lo[0] for backward compatibility, will revisit the case with multiple lo interfaces #} - bgp router-id {{ minigraph_lo_interfaces[0]['addr'] }} + bgp router-id {{ LOOPBACK_INTERFACE.keys()[0][1] }} {# advertise loopback #} -{% for lo in minigraph_lo_interfaces %} -{% if lo['addr'] | ipv4 %} - network {{ lo['addr'] }}/32 -{% elif lo['addr'] | ipv6 %} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv4 %} + network {{ prefix | ip }}/32 +{% elif prefix | ipv6 %} address-family ipv6 - network {{ lo['addr'] }}/128 + network {{ prefix | ip }}/128 exit-address-family {% endif %} {% endfor %} {% endblock bgp_init %} {% block vlan_advertisement %} -{% for vlan_interface in minigraph_vlan_interfaces %} -{% if vlan_interface['addr'] | ipv4 %} - network {{ vlan_interface['subnet'] }} -{% elif vlan_interface['addr'] | ipv6 %} +{% for (name, prefix) in VLAN_INTERFACE %} +{% if prefix | ipv4 %} + network {{ prefix }} +{% elif prefix | ipv6 %} address-family ipv6 - network {{ vlan_interface['subnet'] }} + network {{ prefix }} exit-address-family {% endif %} {% endfor %} {% endblock vlan_advertisement %} {% block bgp_sessions %} {% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if bgp_session['asn'] != 0 %} +{% if bgp_session['asn'] | int != 0 %} neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{% if minigraph_devices[inventory_hostname]['type'] == 'ToRRouter' %} +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} neighbor {{ neighbor_addr }} allowas-in 1 {% endif %} {% if neighbor_addr | ipv4 %} address-family ipv4 neighbor {{ neighbor_addr }} activate -{% if bgp_session['rrclient'] != 0 %} +{% if bgp_session['rrclient'] | int != 0 %} neighbor {{ neighbor_addr }} route-reflector-client {% endif %} maximum-paths 64 @@ -66,7 +66,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if neighbor_addr | ipv6 %} address-family ipv6 neighbor {{ neighbor_addr }} activate -{% if bgp_session['rrclient'] != 0 %} +{% if bgp_session['rrclient'] | int != 0 %} neighbor {{ neighbor_addr }} route-reflector-client {% endif %} maximum-paths 64 diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2~ b/dockers/docker-fpm-frr/bgpd.conf.j2~ new file mode 100644 index 000000000000..08dd93c8dabe --- /dev/null +++ b/dockers/docker-fpm-frr/bgpd.conf.j2~ @@ -0,0 +1,91 @@ +! +{% 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 %} +! +{% block system_init %} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} +password zebra +log syslog informational +log facility local4 +! enable password {# {{ en_passwd }} TODO: param needed #} +{% endblock system_init %} +! +{% block bgp_init %} +! +! bgp multiple-instance +! +router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} + bgp log-neighbor-changes + bgp bestpath as-path multipath-relax + no bgp default ipv4-unicast +{# TODO: use lo[0] for backward compatibility, will revisit the case with multiple lo interfaces #} + bgp router-id {{ LOOPBACK_INTERFACE.keys()[0][1] }} +{# advertise loopback #} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv4 %} + network {{ prefix | ip }}/32 +{% elif prefix | ipv6 %} + address-family ipv6 + network {{ prefix | ip }}/128 + exit-address-family +{% endif %} +{% endfor %} +{% endblock bgp_init %} +{% block vlan_advertisement %} +{% for (name, prefix) in VLAN_INTERFACE %} +{% if prefix | ipv4 %} + network {{ prefix }} +{% elif prefix | ipv6 %} + address-family ipv6 + network {{ prefix }} + exit-address-family +{% endif %} +{% endfor %} +{% endblock vlan_advertisement %} +{% block bgp_sessions %} +{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} +{% if bgp_session['asn'] | int != 0 %} + neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} + neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + neighbor {{ neighbor_addr }} allowas-in 1 +{% endif %} +{% if neighbor_addr | ipv4 %} + address-family ipv4 + neighbor {{ neighbor_addr }} activate +<<<<<<< HEAD +{% if bgp_session['rrclient'] != 0 %} +======= +{% if bgp_session['rrclient'] | int != 0 %} +>>>>>>> 554114cfaa4b55a85e3a74b169bfcf1a394accdd + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} + maximum-paths 64 + exit-address-family +{% endif %} +{% if neighbor_addr | ipv6 %} + address-family ipv6 + neighbor {{ neighbor_addr }} activate +<<<<<<< HEAD +{% if bgp_session['rrclient'] != 0 %} +======= +{% if bgp_session['rrclient'] | int != 0 %} +>>>>>>> 554114cfaa4b55a85e3a74b169bfcf1a394accdd + neighbor {{ neighbor_addr }} route-reflector-client +{% endif %} + maximum-paths 64 + exit-address-family +{% endif %} +{% endif %} +{% endfor %} +{% endblock bgp_sessions %} +! +maximum-paths 64 +! +route-map ISOLATE permit 10 +set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} +! diff --git a/dockers/docker-fpm-frr/config.sh b/dockers/docker-fpm-frr/config.sh index 0636a6dc413c..ef7a13a214f4 100755 --- a/dockers/docker-fpm-frr/config.sh +++ b/dockers/docker-fpm-frr/config.sh @@ -1,14 +1,14 @@ #!/bin/bash mkdir -p /etc/frr -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/bgpd.conf.j2 >/etc/frr/bgpd.conf -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/zebra.conf.j2 >/etc/frr/zebra.conf +sonic-cfggen -d -t /usr/share/sonic/templates/bgpd.conf.j2 >/etc/frr/bgpd.conf +sonic-cfggen -d -t /usr/share/sonic/templates/zebra.conf.j2 >/etc/frr/zebra.conf -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/isolate.j2 >/usr/sbin/bgp-isolate +sonic-cfggen -d -t /usr/share/sonic/templates/isolate.j2 >/usr/sbin/bgp-isolate chown root:root /usr/sbin/bgp-isolate chmod 0755 /usr/sbin/bgp-isolate -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/unisolate.j2 >/usr/sbin/bgp-unisolate +sonic-cfggen -d -t /usr/share/sonic/templates/unisolate.j2 >/usr/sbin/bgp-unisolate chown root:root /usr/sbin/bgp-unisolate chmod 0755 /usr/sbin/bgp-unisolate diff --git a/dockers/docker-fpm-frr/zebra.conf.j2 b/dockers/docker-fpm-frr/zebra.conf.j2 index 1ce06eecd2d9..8b967f98671c 100644 --- a/dockers/docker-fpm-frr/zebra.conf.j2 +++ b/dockers/docker-fpm-frr/zebra.conf.j2 @@ -1,26 +1,26 @@ ! {% block banner %} ! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/quagga/zebra.conf.j2 using minigraph_facts.py +! generated by templates/quagga/zebra.conf.j2 using config DB data ! file: zebra.conf ! {% endblock banner %} ! {% block sys_init %} -hostname {{ inventory_hostname }} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} password zebra enable password zebra {% endblock sys_init %} ! {% block interfaces %} ! Enable link-detect (default disabled) -{% for interface in minigraph_interfaces %} -interface {{ interface['attachto'] }} +{% for (name, prefix) in INTERFACE %} +interface {{ name }} link-detect ! {% endfor %} -{% for interface in minigraph_portchannels.keys() %} -interface {{ interface }} +{% for pc in PORTCHANNEL %} +interface {{ pc }} link-detect ! {% endfor %} @@ -28,26 +28,34 @@ link-detect ! {% block default_route %} ! set static default route to mgmt gateway as a backup to learned default -ip route 0.0.0.0/0 {{ minigraph_mgmt_interface['gwaddr'] }} 200 +{% for (name, prefix) in MGMT_INTERFACE %} +{% if prefix | ipv4 %} +ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 +{% endif %} +{% endfor %} {% endblock default_route %} ! {% block source_loopback %} -! Set ip source to loopback for bgp learned routes -route-map RM_SET_SRC permit 10 - set src {{ minigraph_lo_interfaces[0]['addr'] }} -! +{% set lo_ipv4_addrs = [] %} {% set lo_ipv6_addrs = [] %} -{% if minigraph_lo_interfaces is defined %} -{% for interface in minigraph_lo_interfaces %} -{% if interface['addr'] is defined and interface['addr']|ipv6 %} -{% if lo_ipv6_addrs.append(interface['addr']) %} +{% if LOOPBACK_INTERFACE %} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv6 %} +{% if lo_ipv6_addrs.append(prefix) %} +{% endif %} +{% else %} +{% if lo_ipv4_addrs.append(prefix) %} {% endif %} {% endif %} {% endfor %} {% endif %} +! Set ip source to loopback for bgp learned routes +route-map RM_SET_SRC permit 10 + set src {{ lo_ipv4_addrs[0] | ip }} +! {% if lo_ipv6_addrs|length > 0 %} route-map RM_SET_SRC6 permit 10 - set src {{ lo_ipv6_addrs[0] }} + set src {{ lo_ipv6_addrs[0] | ip }} ! {% endif %} ip protocol bgp route-map RM_SET_SRC diff --git a/dockers/docker-fpm-gobgp/gobgpd.conf.j2 b/dockers/docker-fpm-gobgp/gobgpd.conf.j2 index c6ec7a4fd166..a4fb80bf11ca 100644 --- a/dockers/docker-fpm-gobgp/gobgpd.conf.j2 +++ b/dockers/docker-fpm-gobgp/gobgpd.conf.j2 @@ -1,8 +1,8 @@ [global.config] as = {{ DEVICE_METADATA['localhost']['bgp_asn'] }} - router-id = "{{ minigraph_lo_interfaces[0]['addr'] }}" + router-id = "{{ LOOPBACK_INTERFACE.keys()[0][1] }}" {% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if bgp_session['asn'] != 0 %} +{% if bgp_session['asn'] | int != 0 %} [[neighbors]] [neighbors.config] peer-as = {{ bgp_session['asn'] }} diff --git a/dockers/docker-fpm-gobgp/start.sh b/dockers/docker-fpm-gobgp/start.sh index 636fceea0cbd..83afbda4f736 100755 --- a/dockers/docker-fpm-gobgp/start.sh +++ b/dockers/docker-fpm-gobgp/start.sh @@ -1,14 +1,14 @@ #!/usr/bin/env bash mkdir -p /etc/quagga -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/gobgpd.conf.j2 > /etc/gobgp/gobgpd.conf -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/zebra.conf.j2 > /etc/quagga/zebra.conf +sonic-cfggen -d -t /usr/share/sonic/templates/gobgpd.conf.j2 > /etc/gobgp/gobgpd.conf +sonic-cfggen -d -t /usr/share/sonic/templates/zebra.conf.j2 > /etc/quagga/zebra.conf -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/isolate.j2 > /usr/sbin/bgp-isolate +sonic-cfggen -d -t /usr/share/sonic/templates/isolate.j2 > /usr/sbin/bgp-isolate chown root:root /usr/sbin/bgp-isolate chmod 0755 /usr/sbin/bgp-isolate -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/unisolate.j2 > /usr/sbin/bgp-unisolate +sonic-cfggen -d -t /usr/share/sonic/templates/unisolate.j2 > /usr/sbin/bgp-unisolate chown root:root /usr/sbin/bgp-unisolate chmod 0755 /usr/sbin/bgp-unisolate diff --git a/dockers/docker-fpm-gobgp/zebra.conf.j2 b/dockers/docker-fpm-gobgp/zebra.conf.j2 index 1ce06eecd2d9..8b967f98671c 100644 --- a/dockers/docker-fpm-gobgp/zebra.conf.j2 +++ b/dockers/docker-fpm-gobgp/zebra.conf.j2 @@ -1,26 +1,26 @@ ! {% block banner %} ! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/quagga/zebra.conf.j2 using minigraph_facts.py +! generated by templates/quagga/zebra.conf.j2 using config DB data ! file: zebra.conf ! {% endblock banner %} ! {% block sys_init %} -hostname {{ inventory_hostname }} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} password zebra enable password zebra {% endblock sys_init %} ! {% block interfaces %} ! Enable link-detect (default disabled) -{% for interface in minigraph_interfaces %} -interface {{ interface['attachto'] }} +{% for (name, prefix) in INTERFACE %} +interface {{ name }} link-detect ! {% endfor %} -{% for interface in minigraph_portchannels.keys() %} -interface {{ interface }} +{% for pc in PORTCHANNEL %} +interface {{ pc }} link-detect ! {% endfor %} @@ -28,26 +28,34 @@ link-detect ! {% block default_route %} ! set static default route to mgmt gateway as a backup to learned default -ip route 0.0.0.0/0 {{ minigraph_mgmt_interface['gwaddr'] }} 200 +{% for (name, prefix) in MGMT_INTERFACE %} +{% if prefix | ipv4 %} +ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 +{% endif %} +{% endfor %} {% endblock default_route %} ! {% block source_loopback %} -! Set ip source to loopback for bgp learned routes -route-map RM_SET_SRC permit 10 - set src {{ minigraph_lo_interfaces[0]['addr'] }} -! +{% set lo_ipv4_addrs = [] %} {% set lo_ipv6_addrs = [] %} -{% if minigraph_lo_interfaces is defined %} -{% for interface in minigraph_lo_interfaces %} -{% if interface['addr'] is defined and interface['addr']|ipv6 %} -{% if lo_ipv6_addrs.append(interface['addr']) %} +{% if LOOPBACK_INTERFACE %} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv6 %} +{% if lo_ipv6_addrs.append(prefix) %} +{% endif %} +{% else %} +{% if lo_ipv4_addrs.append(prefix) %} {% endif %} {% endif %} {% endfor %} {% endif %} +! Set ip source to loopback for bgp learned routes +route-map RM_SET_SRC permit 10 + set src {{ lo_ipv4_addrs[0] | ip }} +! {% if lo_ipv6_addrs|length > 0 %} route-map RM_SET_SRC6 permit 10 - set src {{ lo_ipv6_addrs[0] }} + set src {{ lo_ipv6_addrs[0] | ip }} ! {% endif %} ip protocol bgp route-map RM_SET_SRC diff --git a/dockers/docker-fpm-quagga/bgpd.conf.j2 b/dockers/docker-fpm-quagga/bgpd.conf.j2 index eb1da1f1a3ea..0ef144016246 100644 --- a/dockers/docker-fpm-quagga/bgpd.conf.j2 +++ b/dockers/docker-fpm-quagga/bgpd.conf.j2 @@ -1,13 +1,13 @@ ! {% block banner %} ! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/quagga/bgpd.conf.j2 using minigraph_facts.py +! generated by templates/quagga/bgpd.conf.j2 with config DB data ! file: bgpd.conf ! {% endblock banner %} ! {% block system_init %} -hostname {{ inventory_hostname }} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} password zebra log syslog informational log facility local4 @@ -26,51 +26,60 @@ route-map TO_BGP_SPEAKER_V4 deny 10 router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp log-neighbor-changes bgp bestpath as-path multipath-relax + no bgp default ipv4-unicast {# Advertise graceful restart capability for ToR #} -{% if minigraph_devices[inventory_hostname]['type'] == 'ToRRouter' %} +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} bgp graceful-restart {% endif %} -{# TODO: use lo[0] for backward compatibility, will revisit the case with multiple lo interfaces #} - bgp router-id {{ minigraph_lo_interfaces[0]['addr'] }} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{# TODO: use v4 lo for backward compatibility, will revisit the case with multiple lo interfaces #} +{% if prefix | ipv4 %} + bgp router-id {{ prefix | ip }} +{% endif %} +{% endfor %} {# advertise loopback #} -{% for lo in minigraph_lo_interfaces %} -{% if lo['addr'] | ipv4 %} - network {{ lo['addr'] }}/32 -{% elif lo['addr'] | ipv6 %} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv4 %} + network {{ prefix | ip }}/32 +{% elif prefix | ipv6 %} address-family ipv6 - network {{ lo['addr'] }}/128 + network {{ prefix | ip }}/128 exit-address-family {% endif %} {% endfor %} {% endblock bgp_init %} {% endif %} {% block vlan_advertisement %} -{% for vlan_interface in minigraph_vlan_interfaces %} -{% if vlan_interface['addr'] | ipv4 %} - network {{ vlan_interface['subnet'] }} -{% elif vlan_interface['addr'] | ipv6 %} +{% for (name, prefix) in VLAN_INTERFACE %} +{% if prefix | ipv4 %} + network {{ prefix }} +{% elif prefix | ipv6 %} address-family ipv6 - network {{ vlan_interface['subnet'] }} + network {{ prefix }} exit-address-family {% endif %} {% endfor %} {% endblock vlan_advertisement %} {% block bgp_sessions %} {% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if bgp_session['asn'] != 0 %} +{% if bgp_session['asn'] | int != 0 %} neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} {% 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 %} -{% if minigraph_devices[inventory_hostname]['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 + address-family ipv4 +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} + neighbor {{ neighbor_addr }} allowas-in 1 {% endif %} + neighbor {{ neighbor_addr }} activate + maximum-paths 64 + exit-address-family {% endif %} {% if neighbor_addr | ipv6 %} address-family ipv6 -{% if minigraph_devices[inventory_hostname]['type'] == 'ToRRouter' %} +{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} neighbor {{ neighbor_addr }} allowas-in 1 {% endif %} neighbor {{ neighbor_addr }} activate @@ -81,10 +90,11 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% endfor %} {% endblock bgp_sessions %} {% block bgp_peers_with_range %} +{% if BGP_PEER_RANGE %} {% for bgp_peer in BGP_PEER_RANGE.values() %} neighbor {{ bgp_peer['name'] }} peer-group neighbor {{ bgp_peer['name'] }} passive - neighbor {{ bgp_peer['name'] }} remote-as {{deployment_id_asn_map[deployment_id] }} + neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} neighbor {{ bgp_peer['name'] }} ebgp-multihop 255 neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound neighbor {{ bgp_peer['name'] }} update-source Loopback0 @@ -93,7 +103,16 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% for ip_range in bgp_peer['ip_range'] %} bgp listen range {{ip_range}} peer-group {{ bgp_peer['name'] }} {% endfor %} + address-family ipv4 + neighbor {{ bgp_peer['name'] }} activate + maximum-paths 64 + exit-address-family + address-family ipv6 + neighbor {{ bgp_peer['name'] }} activate + maximum-paths 64 + exit-address-family {% endfor %} +{% endif %} {% endblock bgp_peers_with_range %} ! {% if DEVICE_METADATA['localhost'].has_key('bgp_asn') %} diff --git a/dockers/docker-fpm-quagga/supervisord.conf b/dockers/docker-fpm-quagga/supervisord.conf index 5a310a790f18..92d806ff281c 100644 --- a/dockers/docker-fpm-quagga/supervisord.conf +++ b/dockers/docker-fpm-quagga/supervisord.conf @@ -36,7 +36,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:bgpd] -command=/usr/lib/quagga/bgpd -A 127.0.0.1 +command=/usr/lib/quagga/bgpd -A 127.0.0.1 -F priority=5 autostart=false autorestart=false diff --git a/dockers/docker-fpm-quagga/zebra.conf.j2 b/dockers/docker-fpm-quagga/zebra.conf.j2 index 1ce06eecd2d9..8b967f98671c 100644 --- a/dockers/docker-fpm-quagga/zebra.conf.j2 +++ b/dockers/docker-fpm-quagga/zebra.conf.j2 @@ -1,26 +1,26 @@ ! {% block banner %} ! =========== Managed by sonic-cfggen DO NOT edit manually! ==================== -! generated by templates/quagga/zebra.conf.j2 using minigraph_facts.py +! generated by templates/quagga/zebra.conf.j2 using config DB data ! file: zebra.conf ! {% endblock banner %} ! {% block sys_init %} -hostname {{ inventory_hostname }} +hostname {{ DEVICE_METADATA['localhost']['hostname'] }} password zebra enable password zebra {% endblock sys_init %} ! {% block interfaces %} ! Enable link-detect (default disabled) -{% for interface in minigraph_interfaces %} -interface {{ interface['attachto'] }} +{% for (name, prefix) in INTERFACE %} +interface {{ name }} link-detect ! {% endfor %} -{% for interface in minigraph_portchannels.keys() %} -interface {{ interface }} +{% for pc in PORTCHANNEL %} +interface {{ pc }} link-detect ! {% endfor %} @@ -28,26 +28,34 @@ link-detect ! {% block default_route %} ! set static default route to mgmt gateway as a backup to learned default -ip route 0.0.0.0/0 {{ minigraph_mgmt_interface['gwaddr'] }} 200 +{% for (name, prefix) in MGMT_INTERFACE %} +{% if prefix | ipv4 %} +ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 +{% endif %} +{% endfor %} {% endblock default_route %} ! {% block source_loopback %} -! Set ip source to loopback for bgp learned routes -route-map RM_SET_SRC permit 10 - set src {{ minigraph_lo_interfaces[0]['addr'] }} -! +{% set lo_ipv4_addrs = [] %} {% set lo_ipv6_addrs = [] %} -{% if minigraph_lo_interfaces is defined %} -{% for interface in minigraph_lo_interfaces %} -{% if interface['addr'] is defined and interface['addr']|ipv6 %} -{% if lo_ipv6_addrs.append(interface['addr']) %} +{% if LOOPBACK_INTERFACE %} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv6 %} +{% if lo_ipv6_addrs.append(prefix) %} +{% endif %} +{% else %} +{% if lo_ipv4_addrs.append(prefix) %} {% endif %} {% endif %} {% endfor %} {% endif %} +! Set ip source to loopback for bgp learned routes +route-map RM_SET_SRC permit 10 + set src {{ lo_ipv4_addrs[0] | ip }} +! {% if lo_ipv6_addrs|length > 0 %} route-map RM_SET_SRC6 permit 10 - set src {{ lo_ipv6_addrs[0] }} + set src {{ lo_ipv6_addrs[0] | ip }} ! {% endif %} ip protocol bgp route-map RM_SET_SRC diff --git a/dockers/docker-lldp-sv2/lldpd.conf.j2 b/dockers/docker-lldp-sv2/lldpd.conf.j2 index 4cfe48065e11..eb7202df7c67 100644 --- a/dockers/docker-lldp-sv2/lldpd.conf.j2 +++ b/dockers/docker-lldp-sv2/lldpd.conf.j2 @@ -1,5 +1,3 @@ -{% for member in minigraph_ports.keys() %} -{% if member in minigraph_neighbors %} -configure ports {{ member }} lldp portidsubtype local {{ minigraph_ports[member]['alias'] }} description {{ minigraph_neighbors[member]['name'] }}:{{ minigraph_neighbors[member]['port'] }} -{% endif %} +{% for local_port in DEVICE_NEIGHBOR %} +configure ports {{ local_port }} lldp portidsubtype local {{ PORT[local_port]['alias'] }} description {{ DEVICE_NEIGHBOR[local_port]['name'] }}:{{ DEVICE_NEIGHBOR[local_port]['port'] }} {% endfor %} diff --git a/dockers/docker-lldp-sv2/start.sh b/dockers/docker-lldp-sv2/start.sh index 63c8d32c34e6..3a765c6f5482 100755 --- a/dockers/docker-lldp-sv2/start.sh +++ b/dockers/docker-lldp-sv2/start.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/lldpd.conf.j2 > /etc/lldpd.conf +sonic-cfggen -d -t /usr/share/sonic/templates/lldpd.conf.j2 > /etc/lldpd.conf mkdir -p /var/sonic echo "# Config files managed by sonic-config-engine" > /var/sonic/config_status diff --git a/dockers/docker-orchagent/arp_update b/dockers/docker-orchagent/arp_update index 8291818e50fb..cfd87c1dc51f 100755 --- a/dockers/docker-orchagent/arp_update +++ b/dockers/docker-orchagent/arp_update @@ -4,7 +4,7 @@ # arp_update: Send gratuitous ARP requests to VLAN member neighbors to refresh # the neighbors state. -VLAN=`sonic-cfggen -m /etc/sonic/minigraph.xml -v 'minigraph_vlans.keys() | join(" ")'` +VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'` for vlan in $VLAN; do # generate a list of arping commands: # arping -q -w 0 -c 1 -i ; diff --git a/dockers/docker-orchagent/ipinip.json.j2 b/dockers/docker-orchagent/ipinip.json.j2 index 6ffafd297496..2554755c701d 100644 --- a/dockers/docker-orchagent/ipinip.json.j2 +++ b/dockers/docker-orchagent/ipinip.json.j2 @@ -1,9 +1,16 @@ +{# only IPv4 decapsulation is supported #} +{% set ipv4_loopback_addresses = [] %} +{% for (name, prefix) in LOOPBACK_INTERFACE %} + {%- if prefix | ipv4 %} + {%- set ipv4_loopback_addresses = ipv4_loopback_addresses.append(prefix) %} + {%- endif %} +{% endfor %} [ { "TUNNEL_DECAP_TABLE:IPINIP_TUNNEL" : { "tunnel_type":"IPINIP", - "src_ip":"{{ minigraph_lo_interfaces[0]['addr'] }}", - "dst_ip":"{{ minigraph_lo_interfaces[0]['addr'] }}", + "src_ip":"{{ ipv4_loopback_addresses | first | ip }}", + "dst_ip":"{% for prefix in ipv4_loopback_addresses %}{{ prefix | ip }}{% if not loop.last %},{% endif %}{% endfor %}", {% if onie_switch_asic == "mlnx" %} "dscp_mode":"uniform", "ecn_mode":"standard", @@ -16,4 +23,3 @@ "OP": "SET" } ] - diff --git a/dockers/docker-orchagent/mirror.json.j2 b/dockers/docker-orchagent/mirror.json.j2 index 4aa710cfcb71..3a3fc6eed079 100644 --- a/dockers/docker-orchagent/mirror.json.j2 +++ b/dockers/docker-orchagent/mirror.json.j2 @@ -1,9 +1,10 @@ [ -{% if erspan_dst %} +{% if MIRROR_SESSION %} +{% for session in MIRROR_SESSION %} { - "MIRROR_SESSION_TABLE:everflow": { - "src_ip": "{{ minigraph_lo_interfaces[0]['addr'] }}", - "dst_ip": "{{ erspan_dst[0] }}", + "MIRROR_SESSION_TABLE:{{session}}": { + "src_ip": "{{ MIRROR_SESSION[session]['src_ip'] }}", + "dst_ip": "{{ MIRROR_SESSION[session]['dst_ip'] }}", {% if onie_switch_asic == "mlnx" %} "gre_type": "0x6558", "queue": "1", @@ -15,7 +16,9 @@ "ttl": "255" }, "OP": "SET" - } + }{% if not loop.last %},{% endif %} + +{% endfor %} {% endif %} ] diff --git a/dockers/docker-orchagent/orchagent.sh b/dockers/docker-orchagent/orchagent.sh index 328ce8fc053d..7103afcb81e9 100755 --- a/dockers/docker-orchagent/orchagent.sh +++ b/dockers/docker-orchagent/orchagent.sh @@ -2,7 +2,7 @@ # Export platform information. Required to be able to write # vendor specific code. -export platform=`sonic-cfggen -m /etc/sonic/minigraph.xml -v onie_switch_asic` +export platform=`sonic-cfggen -v onie_switch_asic` ASIC=`sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type` diff --git a/dockers/docker-orchagent/ports.json.j2 b/dockers/docker-orchagent/ports.json.j2 index f59ee993eead..48be831025f8 100644 --- a/dockers/docker-orchagent/ports.json.j2 +++ b/dockers/docker-orchagent/ports.json.j2 @@ -1,11 +1,15 @@ [ -{% for interface in ethernet_interfaces %} +{% if PORT %} +{% for port in PORT %} +{% if PORT[port].has_key('speed') %} { - "PORT_TABLE:{{ interface['name'] }}": { - "speed": "{{ interface['speed'] }}" + "PORT_TABLE:{{ port }}": { + "speed": "{{ PORT[port]['speed'] }}" }, "OP": "SET" }{% if not loop.last %},{% endif %} +{% endif %} {% endfor %} +{% endif %} ] diff --git a/dockers/docker-orchagent/start.sh b/dockers/docker-orchagent/start.sh index 5f961a8bd294..0931321a9436 100755 --- a/dockers/docker-orchagent/start.sh +++ b/dockers/docker-orchagent/start.sh @@ -2,27 +2,16 @@ mkdir -p /etc/swss/config.d/ -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/mirror.json.j2 > /etc/swss/config.d/mirror.json -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json +sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json +sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/mirror.json.j2 > /etc/swss/config.d/mirror.json +sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json -export platform=`sonic-cfggen -m /etc/sonic/minigraph.xml -v platform` +export platform=`sonic-cfggen -v platform` rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd -# Wait for syncd to start -while true; do - RESULT=$(echo -en "SELECT 1\nHLEN HIDDEN" | redis-cli | sed -n 2p) - - if [ "$RESULT" != "0" ]; then - break - fi - - sleep 1 -done - supervisorctl start orchagent supervisorctl start portsyncd @@ -34,7 +23,7 @@ supervisorctl start neighsyncd supervisorctl start swssconfig # Start arp_update when VLAN exists -VLAN=`sonic-cfggen -m /etc/sonic/minigraph.xml -v 'minigraph_vlans.keys() | join(" ")'` +VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'` if [ "$VLAN" != "" ]; then supervisorctl start arp_update fi diff --git a/dockers/docker-orchagent/supervisord.conf b/dockers/docker-orchagent/supervisord.conf index a04238472c4c..09850b13d4a1 100644 --- a/dockers/docker-orchagent/supervisord.conf +++ b/dockers/docker-orchagent/supervisord.conf @@ -55,7 +55,8 @@ stderr_logfile=syslog command=/usr/bin/swssconfig.sh priority=7 autostart=false -autorestart=false +autorestart=unexpected +startretries=0 stdout_logfile=syslog stderr_logfile=syslog diff --git a/dockers/docker-orchagent/swssconfig.sh b/dockers/docker-orchagent/swssconfig.sh index 2530aca06bb3..55a22c5353c8 100755 --- a/dockers/docker-orchagent/swssconfig.sh +++ b/dockers/docker-orchagent/swssconfig.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -e + function config_acl { if [ -f "/etc/sonic/acl.json" ]; then mkdir -p /etc/swss/config.d/acl @@ -32,11 +34,10 @@ function fast_reboot { esac } - # Restore FDB and ARP table ASAP fast_reboot -HWSKU=`sonic-cfggen -m /etc/sonic/minigraph.xml -v minigraph_hwsku` +HWSKU=`sonic-cfggen -m /etc/sonic/minigraph.xml -d -v "DEVICE_METADATA['localhost']['hwsku']"` SWSSCONFIG_ARGS="00-copp.config.json ipinip.json mirror.json ports.json " @@ -46,10 +47,9 @@ elif [ "$HWSKU" == "Force10-S6000-Q32" ]; then SWSSCONFIG_ARGS+="td2.32ports.buffers.json td2.32ports.qos.json " elif [ "$HWSKU" == "Arista-7050-QX32" ]; then SWSSCONFIG_ARGS+="td2.32ports.buffers.json td2.32ports.qos.json " -elif [ "$HWSKU" == "ACS-MSN2700" ]; then - SWSSCONFIG_ARGS+="msn2700.32ports.buffers.json msn2700.32ports.qos.json " -elif [ "$HWSKU" == "ACS-MSN2740" ]; then - SWSSCONFIG_ARGS+="msn2740.32ports.buffers.json msn2740.32ports.qos.json " +elif [[ "$HWSKU" == "ACS-MSN27"* ]]; then + sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/msn27xx.32ports.buffers.json.j2 > /etc/swss/config.d/msn27xx.32ports.buffers.json + SWSSCONFIG_ARGS+="msn27xx.32ports.buffers.json msn2700.32ports.qos.json " fi for file in $SWSSCONFIG_ARGS; do diff --git a/dockers/docker-platform-monitor/start.sh b/dockers/docker-platform-monitor/start.sh index fb87083f5cc6..b4023c16367a 100755 --- a/dockers/docker-platform-monitor/start.sh +++ b/dockers/docker-platform-monitor/start.sh @@ -18,6 +18,9 @@ fi # If this platform has a fancontrol config file, copy it to it's proper place # and start fancontrol if [ -e /usr/share/sonic/platform/fancontrol ]; then + # Remove stale pid file if it exists + rm -f /var/run/fancontrol.pid + /bin/cp -f /usr/share/sonic/platform/fancontrol /etc/ supervisorctl start fancontrol fi diff --git a/dockers/docker-snmp-sv2/alias_map.j2 b/dockers/docker-snmp-sv2/alias_map.j2 index 0f91fa26eabe..bd68353a91e3 100644 --- a/dockers/docker-snmp-sv2/alias_map.j2 +++ b/dockers/docker-snmp-sv2/alias_map.j2 @@ -1,5 +1,5 @@ { -{% for member in minigraph_ports.keys() %} - "{{member}}": "{{minigraph_ports[member]['alias']}}"{% if not loop.last %},{% endif %} +{% for member in PORT %} + "{{member}}": "{{PORT[member]['alias']}}"{% if not loop.last %},{% endif %} {% endfor %} } diff --git a/dockers/docker-snmp-sv2/snmpd.conf.j2 b/dockers/docker-snmp-sv2/snmpd.conf.j2 index c5d299af05ef..b46871dfd6f8 100644 --- a/dockers/docker-snmp-sv2/snmpd.conf.j2 +++ b/dockers/docker-snmp-sv2/snmpd.conf.j2 @@ -13,18 +13,22 @@ # AGENT BEHAVIOUR # -{% if minigraph_mgmt_interface.addr | ipv4 %} +{% if MGMT_INTERFACE %} # Listen for connections on localhost, loopback ip and mgmt (eth0) ip agentAddress udp:127.0.0.1:161 -agentAddress udp:{{ minigraph_mgmt_interface.addr }}:161 -{% for minigraph_lo_interface in minigraph_lo_interfaces %} +{% for (name, prefix) in MGMT_INTERFACE %} +{% if prefix | ipv4 %} +agentAddress udp:{{ prefix | ip }}:161 +{% endif %} +{% endfor %} # TODO: only support ipv4 lo addresses, add ipv6 support later -{% if minigraph_lo_interface.addr | ipv4 %} -agentAddress udp:{{ minigraph_lo_interface.addr }}:161 +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if prefix | ipv4 %} +agentAddress udp:{{ prefix | ip }}:161 {% endif %} {% endfor %} {% else %} -# Listen on all addresses as mgmt ip not specified in minigraph +# Listen on all addresses as mgmt ip not specified agentAddress udp:161 {% endif %} @@ -57,7 +61,7 @@ sysServices 72 # # Process Monitoring # -# TODO: should we enable snmp based monitoring of sswsyncd and other processes? +# todo: should we enable snmp based monitoring of sswsyncd and other processes? # At least one 'sendmail' process, but no more than 10 #proc sendmail 10 1 @@ -72,12 +76,7 @@ sysServices 72 # 10MBs required on root disk, 5% free on /var, 10% free on all other disks disk / 10000 disk /var 5% - -# Note: includeAllDisks will conflict with ignoredisk -# TODO: /root/* are introduced by aufs union mount, happening in initramfs stage. Clean them in the mount list. -ignoredisk /root/host -ignoredisk /root/dev -ignoredisk /root/dev/pts +includeAllDisks 10% # Walk the UCD-SNMP-MIB::dskTable to see the resulting output # Note that this table will be empty if there are no "disk" entries in the snmpd.conf file diff --git a/dockers/docker-snmp-sv2/start.sh b/dockers/docker-snmp-sv2/start.sh index ffbe8f196722..201239b1e7db 100755 --- a/dockers/docker-snmp-sv2/start.sh +++ b/dockers/docker-snmp-sv2/start.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash mkdir -p /etc/ssw -sonic-cfggen -m /etc/sonic/minigraph.xml -y /etc/sonic/sonic_version.yml -t /usr/share/sonic/templates/sysDescription.j2 > /etc/ssw/sysDescription +sonic-cfggen -d -y /etc/sonic/sonic_version.yml -t /usr/share/sonic/templates/sysDescription.j2 > /etc/ssw/sysDescription mkdir -p /etc/snmp -sonic-cfggen -m /etc/sonic/minigraph.xml -y /etc/sonic/snmp.yml -t /usr/share/sonic/templates/snmpd.conf.j2 > /etc/snmp/snmpd.conf -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/alias_map.j2 > /etc/snmp/alias_map.json +sonic-cfggen -d -y /etc/sonic/snmp.yml -t /usr/share/sonic/templates/snmpd.conf.j2 > /etc/snmp/snmpd.conf +sonic-cfggen -d -t /usr/share/sonic/templates/alias_map.j2 > /etc/snmp/alias_map.json mkdir -p /var/sonic echo "# Config files managed by sonic-config-engine" > /var/sonic/config_status diff --git a/dockers/docker-snmp-sv2/supervisord.conf b/dockers/docker-snmp-sv2/supervisord.conf index 60313c57f813..d80579506100 100644 --- a/dockers/docker-snmp-sv2/supervisord.conf +++ b/dockers/docker-snmp-sv2/supervisord.conf @@ -20,7 +20,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:snmpd] -command=/usr/sbin/snmpd -f -LS4d -u Debian-snmp -g Debian-snmp -I -smux,mteTrigger,mteTriggerConf,ifTable,ifXTable,inetCidrRouteTable,ipCidrRouteTable,ip -p /run/snmpd.pid +command=/usr/sbin/snmpd -f -LS4d -u Debian-snmp -g Debian-snmp -I -smux,mteTrigger,mteTriggerConf,ifTable,ifXTable,inetCidrRouteTable,ipCidrRouteTable,ip,disk_hw -p /run/snmpd.pid priority=3 autostart=false autorestart=false diff --git a/dockers/docker-snmp-sv2/sysDescription.j2 b/dockers/docker-snmp-sv2/sysDescription.j2 index 648ed161046e..207a8bf7de9a 100644 --- a/dockers/docker-snmp-sv2/sysDescription.j2 +++ b/dockers/docker-snmp-sv2/sysDescription.j2 @@ -1 +1 @@ -SONiC Software Version: SONiC.{{ build_version }} - HwSku: {{ minigraph_hwsku }} - Distribution: Debian {{ debian_version }} - Kernel: {{ kernel_version }} +SONiC Software Version: SONiC.{{ build_version }} - HwSku: {{ DEVICE_METADATA['localhost']['hwsku'] }} - Distribution: Debian {{ debian_version }} - Kernel: {{ kernel_version }} diff --git a/dockers/docker-teamd/start.sh b/dockers/docker-teamd/start.sh index fe4bfe1c584f..6b0a3d785894 100755 --- a/dockers/docker-teamd/start.sh +++ b/dockers/docker-teamd/start.sh @@ -15,8 +15,8 @@ if [ "$SONIC_ASIC_TYPE" == "mellanox" -o "$SONIC_ASIC_TYPE" == "centec" ]; then MAC_ADDRESS=$(python -c "print '$MAC_ADDRESS'[:-2] + '$aligned_last_byte'") # put aligned byte into the end of MAC fi -for pc in `sonic-cfggen -m /etc/sonic/minigraph.xml -v "minigraph_portchannels.keys() | join(' ')"`; do - sonic-cfggen -m /etc/sonic/minigraph.xml -a '{"pc":"'$pc'","hwaddr":"'$MAC_ADDRESS'"}' -t /usr/share/sonic/templates/teamd.j2 > $TEAMD_CONF_PATH/$pc.conf +for pc in `sonic-cfggen -d -v "PORTCHANNEL.keys() | join(' ') if PORTCHANNEL"`; do + sonic-cfggen -d -a '{"pc":"'$pc'","hwaddr":"'$MAC_ADDRESS'"}' -t /usr/share/sonic/templates/teamd.j2 > $TEAMD_CONF_PATH/$pc.conf done mkdir -p /var/sonic diff --git a/dockers/docker-teamd/teamd.j2 b/dockers/docker-teamd/teamd.j2 index d6693719f1ad..d9ea1b790f89 100644 --- a/dockers/docker-teamd/teamd.j2 +++ b/dockers/docker-teamd/teamd.j2 @@ -5,14 +5,14 @@ "name": "lacp", "active": true, {# Use 75% links upperbound as min-links #} - "min_ports": {{ (minigraph_portchannels[pc]['members'] | length * 0.75) | round(0, 'ceil') | int }}, + "min_ports": {{ (PORTCHANNEL[pc]['members'] | length * 0.75) | round(0, 'ceil') | int }}, "tx_hash": ["eth", "ipv4", "ipv6"] }, "link_watch": { "name": "ethtool" }, "ports": { -{% for member in minigraph_portchannels[pc]['members'] %} +{% for member in PORTCHANNEL[pc]['members'] %} "{{ member }}": {}{% if not loop.last %},{% endif %} {% endfor %} diff --git a/dockers/docker-teamd/teamd.sh b/dockers/docker-teamd/teamd.sh index 37b617150a04..2b6d9fb53970 100755 --- a/dockers/docker-teamd/teamd.sh +++ b/dockers/docker-teamd/teamd.sh @@ -24,15 +24,5 @@ function clean_up { trap clean_up SIGTERM SIGKILL -# Before teamd could automatically add newly created host interfaces into the -# LAG, this workaround will wait until the host interfaces are created and then -# the processes will be started. -while true; do - # Check if front-panel ports are configured - result=`echo -en "SELECT 0\nHGETALL PORT_TABLE:ConfigDone" | redis-cli | sed -n 3p` - if [ "$result" == "0" ]; then - start_app - read - fi - sleep 1 -done +start_app +read diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 3ae3acaed33b..a7aee83c70e6 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -1,24 +1,68 @@ #!/bin/bash -# Obtain our platform and HWSKU as we will mount directories with these names in each docker +function getMountPoint() +{ + echo $1 | python -c "import sys, json, os; mnts = [x for x in json.load(sys.stdin)[0]['Mounts'] if x['Destination'] == '/usr/share/sonic/hwsku']; print '' if len(mnts) == 0 else os.path.basename(mnts[0]['Source'])" 2>/dev/null +} + +function postStartAction() +{ +{%- if docker_container_name != "database" %} + : +{%- else %} + while true; do + if [[ "$(docker exec -i database redis-cli ping)" =~ PONG.* ]]; then + break + fi + sleep 1 + done +{%- endif %} +} + +# Obtain our platform as we will mount directories with these names in each docker PLATFORM=`sonic-cfggen -v platform` -HWSKU=`sonic-cfggen -m /etc/sonic/minigraph.xml -v minigraph_hwsku` + +{%- if docker_container_name == "database" %} +# Don't mount HWSKU in {{docker_container_name}} container. +HWSKU="" +{%- else %} +# Obtain our HWSKU as we will mount directories with these names in each docker +HWSKU=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["hwsku"]'` +{%- endif %} start() { - docker inspect --type container {{docker_container_name}} &>/dev/null + DOCKERCHECK=`docker inspect --type container {{docker_container_name}} 2>/dev/null` if [ "$?" -eq "0" ]; then - docker start {{docker_container_name}} - else + DOCKERMOUNT=`getMountPoint "$DOCKERCHECK"` + if [ "$DOCKERMOUNT" == "$HWSKU" ]; then + echo "Starting existing {{docker_container_name}} container with HWSKU $HWSKU" + docker start {{docker_container_name}} + postStartAction + exit 0 + fi - docker run -d {{docker_image_run_opt}} \ + # docker created with a different HWSKU, remove and recreate + echo "Removing obsolete {{docker_container_name}} container with HWSKU $DOCKERMOUNT" + docker rm {{docker_container_name}} + fi + +{%- if docker_container_name == "database" %} + echo "Starting new {{docker_container_name}} container" +{%- else %} + echo "Starting new {{docker_container_name}} container with HWSKU $HWSKU" +{%- endif %} + docker run -d {{docker_image_run_opt}} \ {%- if '--log-driver=json-file' in docker_image_run_opt or '--log-driver' not in docker_image_run_opt %} - --log-opt max-size=2M --log-opt max-file=5 \ + --log-opt max-size=2M --log-opt max-file=5 \ {%- endif %} - -v /var/run/redis:/var/run/redis:rw \ - -v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \ - -v /usr/share/sonic/device/$PLATFORM/$HWSKU:/usr/share/sonic/hwsku:ro \ - --name={{docker_container_name}} {{docker_image_name}}:latest - fi + -v /var/run/redis:/var/run/redis:rw \ + -v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \ +{%- if docker_container_name != "database" %} + -v /usr/share/sonic/device/$PLATFORM/$HWSKU:/usr/share/sonic/hwsku:ro \ +{%- endif %} + --name={{docker_container_name}} {{docker_image_name}}:latest + + postStartAction } attach() { diff --git a/files/build_templates/organization_extensions.sh b/files/build_templates/organization_extensions.sh new file mode 100755 index 000000000000..db05a4e3f59d --- /dev/null +++ b/files/build_templates/organization_extensions.sh @@ -0,0 +1,52 @@ +#!/bin/bash +######################################################################### +## This script is to automate Orignaization specific extensions # +## such as Configuration & Scripts for features like AAA, ZTP, etc. # +## to include in ONIE installer image # +## # +## USAGE: # +## ./organization_extensions.sh -f -n # +## ./organization_extensions.sh \ # +## --fsroot \ # +## --hostname # +## PARAMETERS: # +## -f FILESYSTEM_ROOT # +## The location of the root file system # +## -h HOSTNAME # +## The hostname of the target system # +######################################################################### + +## Initialize the arguments to default values. +## The values get updated to user provided value, if supplied +FILESYSTEM_ROOT=./fsroot +HOSTNAME=sonic + +# read the options +TEMP=`getopt -o f:h: --long fsroot:,hostname: -- "$@"` +eval set -- "$TEMP" + +# extract options and their arguments into variables. +while true ; do + case "$1" in + -f|--fsroot) + case "$2" in + "") shift 2 ;; + *) FILESYSTEM_ROOT=$2 ; shift 2 ;; + esac ;; + -h|--hostname) + case "$2" in + "") shift 2 ;; + *) HOSTNAME=$2 ; shift 2 ;; + esac ;; + --) shift ; break ;; + *) echo "Internal error!" ; exit 1 ;; + esac +done + +echo "Executing SONIC Organization Extensions" + +## Place your Organization specific code / scipts here ... + + +echo "SONIC Organization Extensions - Done" + diff --git a/files/build_templates/swss.service.j2 b/files/build_templates/swss.service.j2 index ed6b852f18f9..af922530d8a2 100644 --- a/files/build_templates/swss.service.j2 +++ b/files/build_templates/swss.service.j2 @@ -5,6 +5,7 @@ Requires=database.service Requires=opennsl-modules-3.16.0-4-amd64.service {% endif %} After=database.service +After=interfaces-config.service {% if sonic_asic_platform == 'broadcom' %} After=opennsl-modules-3.16.0-4-amd64.service {% endif %} diff --git a/files/image_config/interfaces/interfaces-config.service b/files/image_config/interfaces/interfaces-config.service index 0cc7f2981505..86706da22518 100644 --- a/files/image_config/interfaces/interfaces-config.service +++ b/files/image_config/interfaces/interfaces-config.service @@ -1,6 +1,7 @@ [Unit] Description=Update interfaces configuration -Before=database.service +Requires=database.service +After=database.service [Service] Type=oneshot diff --git a/files/image_config/interfaces/interfaces-config.sh b/files/image_config/interfaces/interfaces-config.sh index d2b42051cc8d..400b89a594c7 100755 --- a/files/image_config/interfaces/interfaces-config.sh +++ b/files/image_config/interfaces/interfaces-config.sh @@ -1,6 +1,6 @@ #!/bin/bash -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/interfaces.j2 >/etc/network/interfaces +sonic-cfggen -d -t /usr/share/sonic/templates/interfaces.j2 >/etc/network/interfaces [ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid service networking restart ifdown lo && ifup lo diff --git a/files/image_config/interfaces/interfaces.j2 b/files/image_config/interfaces/interfaces.j2 index 425badf7f21f..6521eb7a67e1 100644 --- a/files/image_config/interfaces/interfaces.j2 +++ b/files/image_config/interfaces/interfaces.j2 @@ -10,34 +10,36 @@ auto lo iface lo inet loopback # Use command 'ip addr list dev lo' to check all addresses -{% for minigraph_lo_interface in minigraph_lo_interfaces %} -iface lo {{ 'inet' if minigraph_lo_interface['addr'] | ipv4 else 'inet6' }} static - address {{ minigraph_lo_interface['addr'] }} - netmask {{ minigraph_lo_interface['mask'] }} +{% for (name, prefix) in LOOPBACK_INTERFACE %} +iface lo {{ 'inet' if prefix | ipv4 else 'inet6' }} static + address {{ prefix | ip }} + netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} # {% endfor %} {% endblock loopback %} {% block mgmt_interface %} # The management network interface auto eth0 -{% if minigraph_mgmt_interface['addr'] %} -iface eth0 inet static - address {{ minigraph_mgmt_interface['addr'] }} - netmask {{ minigraph_mgmt_interface['mask'] }} +{% if MGMT_INTERFACE %} +{% for (name, prefix) in MGMT_INTERFACE %} +iface eth0 {{ 'inet' if prefix | ipv4 else 'inet6' }} static + address {{ prefix | ip }} + netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} ########## management network policy routing rules # management port up rules - up ip route add default via {{ minigraph_mgmt_interface['gwaddr'] }} dev eth0 table default - up ip rule add from {{ minigraph_mgmt_interface['addr'] }}/32 table default -{% for prefix in forced_mgmt_routes %} - up ip rule add to {{ prefix }} table default + up ip {{ '-4' if prefix | ipv4 else '-6' }} route add default via {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} dev eth0 table default + up ip {{ '-4' if prefix | ipv4 else '-6' }} rule add from {{ prefix | ip }}/{{ '32' if prefix | ipv4 else '128' }} table default +{% for route in MGMT_INTERFACE[(name, prefix)]['forced_mgmt_routes'] %} + up ip rule add to {{ route }} table default {% endfor %} # management port down rules - down ip route delete default via {{ minigraph_mgmt_interface['gwaddr'] }} dev eth0 table default - down ip rule delete from {{ minigraph_mgmt_interface['addr'] }}/32 table default -{% for prefix in forced_mgmt_routes %} - down ip rule delete to {{ prefix }} table default + down ip {{ '-4' if prefix | ipv4 else '-6' }} route delete default via {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} dev eth0 table default + down ip {{ '-4' if prefix | ipv4 else '-6' }} rule delete from {{ prefix | ip }}/{{ '32' if prefix | ipv4 else '128' }} table default +{% for route in MGMT_INTERFACE[(name, prefix)]['forced_mgmt_routes'] %} + down ip rule delete to {{ route }} table default {% endfor %} {# TODO: COPP policy type rules #} +{% endfor %} {% else %} iface eth0 inet dhcp {% endif %} @@ -45,33 +47,32 @@ iface eth0 inet dhcp {% endblock mgmt_interface %} {% block front_panel_interfaces %} # The switch front panel interfaces -{% for interface in minigraph_interfaces %} -allow-hotplug {{ interface['attachto'] }} -iface {{ interface['attachto'] }} {{ 'inet' if interface['addr'] | ipv4 else 'inet6' }} static - mtu 9216 - address {{ interface['addr'] }} - netmask {{ interface['mask'] }} +{% for (name, prefix) in INTERFACE %} +allow-hotplug {{ name }} +iface {{ name }} {{ 'inet' if prefix | ipv4 else 'inet6' }} static + mtu 9100 + address {{ prefix | ip }} + netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} # {% endfor %} -{% if minigraph_vlans.keys() | length %} +{% if VLAN %} # "|| true" is added to suppress the error when interface is already a member of VLAN -{% endif %} -{% for vlan in minigraph_vlans.keys()|sort %} -{% for member in minigraph_vlans[vlan]['members'] %} +{% for vlan in VLAN.keys()|sort %} +{% for member in VLAN[vlan]['members'] %} allow-hotplug {{ member }} iface {{ member }} inet manual - pre-up ifconfig {{ member }} up mtu 9216 + pre-up ifconfig {{ member }} up mtu 9100 post-up brctl addif {{ vlan }} {{ member }} || true post-down ifconfig {{ member }} down # {% endfor %} {% endfor %} -{% if minigraph_portchannels.keys() | length %} +{% endif %} +{% if PORTCHANNEL %} # "|| true" is added to suppress the error when interface is already a member of LAG # "ip link show | grep -q master" is added to ensure interface is enslaved -{% endif %} -{% for pc in minigraph_portchannels.keys()|sort %} -{% for member in minigraph_portchannels[pc]['members'] %} +{% for pc in PORTCHANNEL.keys()|sort %} +{% for member in PORTCHANNEL[pc]['members'] %} allow-hotplug {{ member }} iface {{ member }} inet manual pre-up teamdctl {{ pc }} port add {{ member }} || true @@ -80,30 +81,31 @@ iface {{ member }} inet manual # {% endfor %} {% endfor %} +{% endif %} {% endblock front_panel_interfaces %} -{% if minigraph_vlans.keys() | length %} {% block vlan_interfaces %} +{% if VLAN_INTERFACE %} # Vlan interfaces -{% for vlan_interface in minigraph_vlan_interfaces %} -auto {{ vlan_interface['attachto'] }} -iface {{ vlan_interface['attachto'] }} {{ 'inet' if vlan_interface['addr'] | ipv4 else 'inet6' }} static +{% for (name, prefix) in VLAN_INTERFACE.keys() | sort %} +auto {{ name }} +iface {{ name }} {{ 'inet' if prefix | ipv4 else 'inet6' }} static bridge_ports none - address {{ vlan_interface['addr'] }} - netmask {{ vlan_interface['mask'] }} + address {{ prefix | ip }} + netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} {% endfor %} # -{% endblock vlan_interfaces %} {% endif %} -{% if minigraph_portchannels.keys() | length %} +{% endblock vlan_interfaces %} {% block pc_interfaces %} +{% if PORTCHANNEL_INTERFACE %} # Portchannel interfaces -{% for pc_interface in minigraph_portchannel_interfaces %} -allow-hotplug {{ pc_interface['attachto'] }} -iface {{ pc_interface['attachto'] }} {{ 'inet' if pc_interface['addr'] | ipv4 else 'inet6' }} static - mtu 9216 - address {{ pc_interface['addr'] }} - netmask {{ pc_interface['mask'] }} +{% for (name, prefix) in PORTCHANNEL_INTERFACE.keys() | sort %} +allow-hotplug {{ name }} +iface {{ name }} {{ 'inet' if prefix | ipv4 else 'inet6' }} static + mtu 9100 + address {{ prefix | ip }} + netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} # {% endfor %} -{% endblock pc_interfaces %} {% endif %} +{% endblock pc_interfaces %} diff --git a/files/image_config/ntp/ntp-config.service b/files/image_config/ntp/ntp-config.service index 948e7f4953c8..05e6211b9782 100644 --- a/files/image_config/ntp/ntp-config.service +++ b/files/image_config/ntp/ntp-config.service @@ -1,6 +1,8 @@ [Unit] Description=Update NTP configuration Before=ntp.service +Requires=database.service +After=database.service [Service] Type=oneshot diff --git a/files/image_config/ntp/ntp-config.sh b/files/image_config/ntp/ntp-config.sh index 2465058ba021..7c79a16c0ef3 100755 --- a/files/image_config/ntp/ntp-config.sh +++ b/files/image_config/ntp/ntp-config.sh @@ -1,3 +1,3 @@ #!/bin/bash -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/ntp.conf.j2 >/etc/ntp.conf +sonic-cfggen -d -t /usr/share/sonic/templates/ntp.conf.j2 >/etc/ntp.conf diff --git a/files/image_config/ntp/ntp.conf.j2 b/files/image_config/ntp/ntp.conf.j2 index 3ae0c1804e52..ae72820339be 100644 --- a/files/image_config/ntp/ntp.conf.j2 +++ b/files/image_config/ntp/ntp.conf.j2 @@ -23,13 +23,15 @@ filegen clockstats file clockstats type day enable # pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will # pick a different set every time it starts up. Please consider joining the # pool: -{% for ntp_server in ntp_servers %} +{% for ntp_server in NTP_SERVER %} server {{ ntp_server }} iburst {% endfor %} #only listen on localhost and eth0 ips (default is to listen on all ip addresses) interface ignore wildcard -interface listen {{ minigraph_mgmt_interface.addr }} +{% for (mgmt_intf, mgmt_prefix) in MGMT_INTERFACE %} +interface listen {{ mgmt_prefix | ip }} +{% endfor %} interface listen 127.0.0.1 # Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for diff --git a/files/image_config/platform/rc.local b/files/image_config/platform/rc.local index 8b8db4a261c3..d3ecba7d8518 100755 --- a/files/image_config/platform/rc.local +++ b/files/image_config/platform/rc.local @@ -29,6 +29,7 @@ if [ ! -e /host/machine.conf ]; then done fi + migration="TRUE" umount /mnt/onie-boot fi @@ -36,6 +37,26 @@ fi echo "install platform dependent packages at the first boot time" +firsttime_exit() +{ + rm /host/image-$sonic_version/platform/firsttime + exit 0 +} + +# Given a string of tuples of the form field=value, extract the value for a field +# In : $string, $field +# Out: $value +value_extract() +{ +set -- $string +for x in "$@"; do + case "$x" in + $field=*) + value="${x#$field=}" + esac +done +} + sonic_version=$(cat /etc/sonic/sonic_version.yml | grep build_version | cut -f2 -d" ") if [ -f /host/image-$sonic_version/platform/firsttime ]; then @@ -46,8 +67,7 @@ if [ -f /host/image-$sonic_version/platform/firsttime ]; then platform=$onie_platform else echo "Unknown sonic platform" - rm /host/image-$sonic_version/platform/firsttime - exit 0 + firsttime_exit fi # Try to take old configuration saved during installation @@ -76,6 +96,88 @@ if [ -f /host/image-$sonic_version/platform/firsttime ]; then dpkg -i /host/image-$sonic_version/platform/$platform/*.deb fi + # If the unit booted into SONiC from another NOS's grub, + # we now install a grub for SONiC. + if [ -n "$onie_platform" ] && [ -n "$migration" ]; then + + grub_bin=$(ls /host/image-$sonic_version/platform/x86_64-grub/grub-pc-bin*.deb 2> /dev/null) + if [ -z "$grub_bin" ]; then + echo "Unable to locate grub package !" >> /etc/migration.log + firsttime_exit + fi + + dpkg -i $grub_bin > /dev/null 2>&1 + if [ $? != 0 ]; then + echo "Unable to install grub package !" >> /etc/migration.log + firsttime_exit + fi + + # Determine the block device to install grub + sonic_dev=$(blkid | grep SONiC-OS | head -n 1 | awk '{print $1}' | sed -e 's/[0-9]:.*$//') + if [ -z "$sonic_dev" ]; then + echo "Unable to determine sonic partition !" >> /etc/migration.log + firsttime_exit + fi + + grub-install --boot-directory=/host --recheck $sonic_dev 2>/dev/null + if [ $? != 0 ]; then + echo "grub install failed !" >> /etc/migration.log + firsttime_exit + fi + + # The SONiC "raw" build mode has already generated a proto grub.cfg + # as part of the migration. Platform specific constants need to be + # retrieved from installer.conf (if present) and assigned. + . /usr/share/sonic/device/$platform/installer.conf + + if [ ! -z "$CONSOLE_PORT" ]; then + field="\-\-port" + string=$(grep $field /host/grub.cfg) + value_extract $string $field + console_port=$value + if [ ! -z "$console_port" ] && [ "$console_port" != "$CONSOLE_PORT" ]; then + sed -i -e "s/\-\-port=$console_port/\-\-port=$CONSOLE_PORT/g" /host/grub.cfg + fi + echo "grub.cfg console port=$console_port & installer.conf CONSOLE_PORT=$CONSOLE_PORT" >> /etc/migration.log + fi + + if [ ! -z "$CONSOLE_DEV" ]; then + field="console" + string=$(grep $field /host/grub.cfg) + value_extract $string $field + console_dev_name=$(echo $value | sed -e "s/^.*=//" -e "s/,.*//") + console_dev="${console_dev_name#ttyS}" + if [ "$console_dev" != "$CONSOLE_DEV" ]; then + sed -i -e "s/console=ttyS$console_dev/console=ttyS$CONSOLE_DEV/g" /host/grub.cfg + fi + echo "grub.cfg console dev=$console_dev & installer.conf CONSOLE_DEV=$CONSOLE_DEV" >> /etc/migration.log + fi + + if [ ! -z "$VAR_LOG_SIZE" ]; then + field="var_log_size" + string=$(grep $field /host/grub.cfg) + value_extract $string $field + var_log_size=$value + if [ ! -z "$var_log_size" ] && [ "$var_log_size" != "$VAR_LOG_SIZE" ]; then + sed -i -e "s/var_log_size=$var_log_size/var_log_size=$VAR_LOG_SIZE/g" /host/grub.cfg + fi + echo "grub.cfg var_log_size=$var_log_size & installer.conf VAR_LOG_SIZE=$VAR_LOG_SIZE" >> /etc/migration.log + fi + + # Set the root based on the label + sonic_root=$(blkid | grep SONiC-OS | head -n 1 | awk '{print $1}' | sed -e 's/:.*$//') + sonic_root=$(echo "$sonic_root" | sed 's/\//\\\//g') + sed -i -e "s/%%SONIC_ROOT%%/$sonic_root/g" /host/grub.cfg + + # Add the Diag and ONIE entries + mount $onie_dev /mnt/onie-boot + . /mnt/onie-boot/onie/grub.d/50_onie_grub >> /host/grub.cfg + umount /mnt/onie-boot + + # Initialize the SONiC's grub config + mv /host/grub.cfg /host/grub/grub.cfg + fi + rm /host/image-$sonic_version/platform/firsttime fi diff --git a/files/image_config/rsyslog/rsyslog-config.service b/files/image_config/rsyslog/rsyslog-config.service index be3c209e7560..e013b992030d 100644 --- a/files/image_config/rsyslog/rsyslog-config.service +++ b/files/image_config/rsyslog/rsyslog-config.service @@ -1,5 +1,7 @@ [Unit] Description=Update rsyslog configuration +Requires=database.service +After=database.service [Service] Type=oneshot diff --git a/files/image_config/rsyslog/rsyslog-config.sh b/files/image_config/rsyslog/rsyslog-config.sh index 06a4934a4be5..c8ba7b99453c 100755 --- a/files/image_config/rsyslog/rsyslog-config.sh +++ b/files/image_config/rsyslog/rsyslog-config.sh @@ -1,4 +1,4 @@ #!/bin/bash -sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/rsyslog.conf.j2 >/etc/rsyslog.conf +sonic-cfggen -d -t /usr/share/sonic/templates/rsyslog.conf.j2 >/etc/rsyslog.conf systemctl restart rsyslog diff --git a/files/image_config/rsyslog/rsyslog.conf.j2 b/files/image_config/rsyslog/rsyslog.conf.j2 index 54e2eec3f999..063f119f6bdd 100644 --- a/files/image_config/rsyslog/rsyslog.conf.j2 +++ b/files/image_config/rsyslog/rsyslog.conf.j2 @@ -30,11 +30,6 @@ $UDPServerRun 514 ########################### #### GLOBAL DIRECTIVES #### ########################### -#Set remote syslog server -{% for server in syslog_servers %} -*.* @{{ server }}:514 -{% endfor %} - # # Use traditional timestamp format. # To enable high precision timestamps, comment out the following line. @@ -42,9 +37,14 @@ $UDPServerRun 514 #$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat # Define a custom template -$template SONiCFileFormat,"%TIMESTAMP%.%timestamp:::date-subseconds% %HOSTNAME% %syslogseverity-text:::uppercase% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" +$template SONiCFileFormat,"%timegenerated%.%timegenerated:::date-subseconds% %HOSTNAME% %syslogseverity-text:::uppercase% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" $ActionFileDefaultTemplate SONiCFileFormat +#Set remote syslog server +{% for server in SYSLOG_SERVER %} +*.* @{{ server }}:514;SONiCFileFormat +{% endfor %} + # # Set the default permissions for all log files. # diff --git a/files/image_config/updategraph/updategraph.service b/files/image_config/updategraph/updategraph.service index ba0b5dcb85e2..c66e9be75702 100644 --- a/files/image_config/updategraph/updategraph.service +++ b/files/image_config/updategraph/updategraph.service @@ -1,8 +1,6 @@ [Unit] Description=download minigraph from graph service -Before=ntp-config.service -Before=rsyslog-config.service -Before=interfaces-config.service +Before=database.service [Service] Type=oneshot diff --git a/files/initramfs-tools/arista-convertfs.j2 b/files/initramfs-tools/arista-convertfs.j2 index 81c6d9d1943f..75ce011e839a 100644 --- a/files/initramfs-tools/arista-convertfs.j2 +++ b/files/initramfs-tools/arista-convertfs.j2 @@ -82,28 +82,6 @@ run_cmd() { fi } -create_varlog_file() { - local err_msg="Error: create var-log ext4 file" - local cmd="[ -n "$varlog_size" ] && mkdir -p $root_mnt/disk-img && dd if=/dev/zero of=$root_mnt/disk-img/var-log.ext4 count=$((2048*$varlog_size)) && mke2fs -t ext4 -q -F $root_mnt/disk-img/var-log.ext4" - run_cmd "$cmd" "$err_msg" -} - -mount_and_create_varlog_file() { - [ -z "$varlog_size" ] && exit 0 - mkdir -p "$root_mnt" - mount -t ext4 "$root_dev" "$root_mnt" - # exit when the var_log.ext4 exists and the size matches - if [ -e "$root_mnt/disk-img/var-log.ext4" ]; then - cur_varlog_size=$(ls -l $root_mnt/disk-img/var-log.ext4 | awk '{print $5}') - if [ $cur_varlog_size == $((1024*1024*$varlog_size)) ]; then - exit 0 - fi - fi - create_varlog_file - umount "$root_mnt" - exit 0 -} - # Extract kernel parameters set -- $(cat /proc/cmdline) for x in "$@"; do @@ -114,9 +92,6 @@ for x in "$@"; do Aboot=*) aboot_flag="${x#Aboot=}" ;; - varlog_size=*) - varlog_size="${x#varlog_size=}" - ;; loop=*) x1="${x#loop=}" image_dir="${x1%/*}" @@ -135,8 +110,8 @@ if ! wait_for_root_dev; then exit 1 fi -# mount, create varlog file and exit when the root is ext4 -blkid | grep "$root_dev.*vfat" -q || mount_and_create_varlog_file +# exit when the root is ext4 +blkid | grep "$root_dev.*vfat" -q || exit 0 # Get flash dev name if [ -z "$block_flash" ]; then @@ -201,5 +176,3 @@ run_cmd "$cmd" "$err_msg" err_msg="Error: copying files form $tmp_mnt to $root_mnt failed" cmd="cp -a $tmp_mnt/. $root_mnt/" run_cmd "$cmd" "$err_msg" - -create_varlog_file diff --git a/files/initramfs-tools/union-mount.j2 b/files/initramfs-tools/union-mount.j2 index acc21e2885bc..db40d4f08601 100644 --- a/files/initramfs-tools/union-mount.j2 +++ b/files/initramfs-tools/union-mount.j2 @@ -1,6 +1,12 @@ #!/bin/sh -e + +PREREQS="varlog" + +prereqs() { echo "$PREREQS"; } + case $1 in prereqs) + prereqs exit 0 ;; esac diff --git a/files/initramfs-tools/varlog b/files/initramfs-tools/varlog new file mode 100644 index 000000000000..d1340eaa9d8b --- /dev/null +++ b/files/initramfs-tools/varlog @@ -0,0 +1,36 @@ +#!/bin/sh -e + +PREREQS="" + +prereqs() { echo "$PREREQS"; } + +case $1 in + prereqs) + prereqs + exit 0 + ;; +esac + +# Extract kernel parameters +set -- $(cat /proc/cmdline) +for x in "$@"; do + case "$x" in + varlog_size=*) + varlog_size="${x#varlog_size=}" + esac +done + +[ -z "$varlog_size" ] && exit 0 + +# exit when the var_log.ext4 exists and the size matches +if [ -e "${rootmnt}/host/disk-img/var-log.ext4" ]; then + cur_varlog_size=$(ls -l ${rootmnt}/host/disk-img/var-log.ext4 | awk '{print $5}') + if [ $cur_varlog_size == $((1024*1024*$varlog_size)) ]; then + exit 0 + else + rm -rf ${rootmnt}/host/disk-img + fi +fi + +# create varlog disk +mkdir -p ${rootmnt}/host/disk-img && ${rootmnt}/usr/bin/fallocate -l "$varlog_size"M ${rootmnt}/host/disk-img/var-log.ext4 && mkfs.ext4 -q -F ${rootmnt}/host/disk-img/var-log.ext4 diff --git a/functions.sh b/functions.sh index c73aeb45d649..01f645ca72c7 100644 --- a/functions.sh +++ b/functions.sh @@ -55,7 +55,7 @@ sonic_get_version() { local latest_tag=$(git describe --tags --abbrev=0) local branch_name=$(git rev-parse --abbrev-ref HEAD) if [ -n "$(git status --untracked-files=no -s --ignore-submodules)" ]; then - local dirty="-dirty" + local dirty="-dirty-$DIRTY_SUFFIX" fi BUILD_NUMBER=${BUILD_NUMBER:-0} ## Check if we are on tagged commit diff --git a/installer/x86_64/install.sh b/installer/x86_64/install.sh index ad1cc3691fbf..358da41071b5 100755 --- a/installer/x86_64/install.sh +++ b/installer/x86_64/install.sh @@ -423,7 +423,7 @@ else demo_mnt="build_raw_image_mnt" demo_dev=$cur_wd/"%%OUTPUT_RAW_IMAGE%%" - mkfs.ext4 $demo_dev + mkfs.ext4 -L $demo_volume_label $demo_dev echo "Mounting $demo_dev on $demo_mnt..." mkdir $demo_mnt @@ -450,24 +450,6 @@ TAR_EXTRA_OPTION="--numeric-owner" mkdir -p $demo_mnt/$image_dir/$DOCKERFS_DIR unzip -op $ONIE_INSTALLER_PAYLOAD "$FILESYSTEM_DOCKERFS" | tar xz $TAR_EXTRA_OPTION -f - -C $demo_mnt/$image_dir/$DOCKERFS_DIR -# Create loop device for /var/log to limit its size to $VAR_LOG_SIZE MB -if [ -f $demo_mnt/disk-img/var-log.ext4 ]; then - current_log_size_mb=$(ls -l --block-size=M $demo_mnt/disk-img/var-log.ext4 | cut -f5 -d" ") - if [ "$current_log_size_mb" = "$VAR_LOG_SIZE"M ]; then - echo "Log file system already exists. Size: ${VAR_LOG_SIZE}MB" - VAR_LOG_SIZE=0 - else - rm -rf $demo_mnt/disk-img - fi -fi - -if [ "$VAR_LOG_SIZE" != "0" ]; then - echo "Creating new log file system. Size: ${VAR_LOG_SIZE}MB" - mkdir -p $demo_mnt/disk-img - dd if=/dev/zero of=$demo_mnt/disk-img/var-log.ext4 count=$((2048*$VAR_LOG_SIZE)) - mkfs.ext4 -q $demo_mnt/disk-img/var-log.ext4 -F -fi - if [ "$install_env" = "onie" ]; then # Store machine description in target file system cp /etc/machine.conf $demo_mnt @@ -553,6 +535,12 @@ if [ "$install_env" = "sonic" ]; then onie_menuentry=$(cat /host/grub/grub.cfg | sed "/menuentry ONIE/,/}/!d") fi +if [ "$install_env" = "build" ]; then + grub_cfg_root=%%SONIC_ROOT%% +else + grub_cfg_root=$demo_dev +fi + cat <> $grub_cfg menuentry '$demo_grub_entry' { search --no-floppy --label --set=root $demo_volume_label @@ -561,9 +549,9 @@ menuentry '$demo_grub_entry' { if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi insmod part_msdos insmod ext2 - linux /$image_dir/boot/vmlinuz-3.16.0-4-amd64 root=$demo_dev rw $GRUB_CMDLINE_LINUX \ + linux /$image_dir/boot/vmlinuz-3.16.0-4-amd64 root=$grub_cfg_root rw $GRUB_CMDLINE_LINUX \ loop=$image_dir/$FILESYSTEM_SQUASHFS loopfstype=squashfs \ - apparmor=1 security=apparmor $ONIE_PLATFORM_EXTRA_CMDLINE_LINUX + apparmor=1 security=apparmor varlog_size=$VAR_LOG_SIZE $ONIE_PLATFORM_EXTRA_CMDLINE_LINUX echo 'Loading $demo_volume_label $demo_type initial ramdisk ...' initrd /$image_dir/boot/initrd.img-3.16.0-4-amd64 } @@ -582,6 +570,7 @@ EOF fi if [ "$install_env" = "build" ]; then + cp $grub_cfg $demo_mnt/grub.cfg umount $demo_mnt else cp $grub_cfg $onie_initrd_tmp/$demo_mnt/grub/grub.cfg diff --git a/platform/broadcom/docker-ptf-brcm.mk b/platform/broadcom/docker-ptf-brcm.mk index 7b78aa9ec316..c57ce43dc905 100644 --- a/platform/broadcom/docker-ptf-brcm.mk +++ b/platform/broadcom/docker-ptf-brcm.mk @@ -4,4 +4,4 @@ DOCKER_PTF_BRCM = docker-ptf-brcm.gz $(DOCKER_PTF_BRCM)_PATH = $(DOCKERS_PATH)/docker-ptf-saithrift $(DOCKER_PTF_BRCM)_DEPENDS += $(PYTHON_SAITHRIFT_BRCM) $(DOCKER_PTF_BRCM)_LOAD_DOCKERS += $(DOCKER_PTF) -SONIC_DOCKER_IMAGES += $(DOCKER_PTF_BRCM) +#SONIC_DOCKER_IMAGES += $(DOCKER_PTF_BRCM) diff --git a/platform/broadcom/libsaithrift-dev.mk b/platform/broadcom/libsaithrift-dev.mk index c809539b47fe..6e422db6e799 100644 --- a/platform/broadcom/libsaithrift-dev.mk +++ b/platform/broadcom/libsaithrift-dev.mk @@ -4,4 +4,4 @@ LIBSAITHRIFT_DEV_BRCM = libsaithrift-dev_0.9.4_amd64.deb $(LIBSAITHRIFT_DEV_BRCM)_SRC_PATH = $(SRC_PATH)/SAI $(LIBSAITHRIFT_DEV_BRCM)_DEPENDS += $(LIBTHRIFT) $(LIBTHRIFT_DEV) $(THRIFT_COMPILER) $(BRCM_SAI) $(BRCM_SAI_DEV) $(LIBSAITHRIFT_DEV_BRCM)_RDEPENDS += $(LIBTHRIFT) $(BRCM_SAI) -SONIC_DPKG_DEBS += $(LIBSAITHRIFT_DEV_BRCM) +#SONIC_DPKG_DEBS += $(LIBSAITHRIFT_DEV_BRCM) diff --git a/platform/broadcom/python-saithrift.mk b/platform/broadcom/python-saithrift.mk index f9da4143c7d9..18bf77c3d009 100644 --- a/platform/broadcom/python-saithrift.mk +++ b/platform/broadcom/python-saithrift.mk @@ -3,4 +3,4 @@ PYTHON_SAITHRIFT_BRCM = python-saithrift_0.9.4_amd64.deb $(PYTHON_SAITHRIFT_BRCM)_SRC_PATH = $(SRC_PATH)/SAI $(PYTHON_SAITHRIFT_BRCM)_DEPENDS += $(BRCM_SAI_DEV) $(THRIFT_COMPILER) $(PYTHON_THRIFT) $(LIBTHRIFT_DEV) -SONIC_DPKG_DEBS += $(PYTHON_SAITHRIFT_BRCM) +#SONIC_DPKG_DEBS += $(PYTHON_SAITHRIFT_BRCM) diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk index 30b517f8d385..b52118570251 100755 --- a/platform/broadcom/rules.mk +++ b/platform/broadcom/rules.mk @@ -15,7 +15,7 @@ include $(PLATFORM_PATH)/raw-image.mk include $(PLATFORM_PATH)/one-aboot.mk include $(PLATFORM_PATH)/libsaithrift-dev.mk include $(PLATFORM_PATH)/python-saithrift.mk -include $(PLATFORM_PATH)/docker-ptf-brcm.mk +#include $(PLATFORM_PATH)/docker-ptf-brcm.mk BCMCMD = bcmcmd $(BCMCMD)_URL = "https://sonicstorage.blob.core.windows.net/packages/20170518/bcmcmd?sv=2015-04-05&sr=b&sig=OCW4mfmbQ6D0BH8nllpAWrS8XL9uczrw32w3XgL4jws%3D&se=2030-03-31T23%3A06%3A15Z&sp=r" @@ -26,12 +26,10 @@ $(DSSERVE)_URL = "https://sonicstorage.blob.core.windows.net/packages/20170518/d SONIC_ONLINE_FILES += $(BCMCMD) $(DSSERVE) SONIC_ALL += $(SONIC_ONE_IMAGE) $(SONIC_ONE_ABOOT_IMAGE) \ - $(DOCKER_FPM) \ - $(DOCKER_PTF_BRCM) \ - $(DOCKER_SYNCD_BRCM_RPC) + $(DOCKER_FPM) # Inject brcm sai into sairedis -$(LIBSAIREDIS)_DEPENDS += $(BRCM_OPENNSL) $(BRCM_SAI) $(BRCM_SAI_DEV) $(LIBSAITHRIFT_DEV_BRCM) +$(LIBSAIREDIS)_DEPENDS += $(BRCM_SAI) $(BRCM_SAI_DEV) #$(LIBSAITHRIFT_DEV_BRCM) # Runtime dependency on brcm sai is set only for syncd -$(SYNCD)_RDEPENDS += $(BRCM_OPENNSL) $(BRCM_SAI) +$(SYNCD)_RDEPENDS += $(BRCM_SAI) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index eaf188485fed..ea804a69c0eb 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,10 +1,9 @@ -BRCM_SAI = libsaibcm_2.1.5.1-17_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_2.1.5.1-17_amd64.deb?sv=2015-04-05&sr=b&sig=6sJ4dd%2FF1hqStNQk5Z6d%2BYQGRZxLDihXRl60EeN7agc%3D&se=2031-05-02T09%3A37%3A54Z&sp=r" +BRCM_SAI = libsaibcm_3.0.3.2-5_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_3.0.3.2-5_amd64.deb?sv=2015-04-05&sr=b&sig=MQE6FrxHs%2BIUPjRaSpWagcSjY6bbHLCUYasusxILkEs%3D&se=2031-06-07T21%3A50%3A36Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_2.1.5.1-17_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_3.0.3.2-5_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_2.1.5.1-17_amd64.deb?sv=2015-04-05&sr=b&sig=syV0rie0L2Dn4lhmndCTyCTgXQv8DPoWD3IxtlSdeNo%3D&se=2031-05-02T09%3A37%3A18Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_3.0.3.2-5_amd64.deb?sv=2015-04-05&sr=b&sig=o8bjWlxxYAM%2F95aSshRFJE57JwKVjRaH4jDU2lDEoMg%3D&se=2031-06-07T21%3A50%3A19Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV) -$(BRCM_SAI)_DEPENDS += $(BRCM_OPENNSL) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) diff --git a/platform/broadcom/sdk.mk b/platform/broadcom/sdk.mk index 5280fa2c9c1b..04d540c64582 100644 --- a/platform/broadcom/sdk.mk +++ b/platform/broadcom/sdk.mk @@ -1,7 +1,4 @@ -BRCM_OPENNSL = libopennsl_3.2.2.2-10-20170707181826.44_amd64.deb -$(BRCM_OPENNSL)_URL = "https://sonicstorage.blob.core.windows.net/packages/libopennsl_3.2.2.2-10-20170707181826.44_amd64.deb?sv=2015-04-05&sr=b&sig=hc4PbMQvfOu7p7E0MR1kn0OA6vu%2BPIdYOLeDU9hPJMY%3D&se=2031-03-19T21%3A20%3A15Z&sp=r" +BRCM_OPENNSL_KERNEL = opennsl-modules-3.16.0-4-amd64_3.2.3.3-1_amd64.deb +$(BRCM_OPENNSL_KERNEL)_URL = "https://sonicstorage.blob.core.windows.net/packages/opennsl-modules-3.16.0-4-amd64_3.2.3.3-1_amd64.deb?sv=2015-04-05&sr=b&sig=Uepf4z2wOadX%2F6OR%2BCoQzjv2tkwEZ2AspBiuo5sb25s%3D&se=2031-05-30T19%3A37%3A19Z&sp=r" -BRCM_OPENNSL_KERNEL = opennsl-modules-3.16.0-4-amd64_3.2.2.2-10-20170707181826.44_amd64.deb -$(BRCM_OPENNSL_KERNEL)_URL = "https://sonicstorage.blob.core.windows.net/packages/opennsl-modules-3.16.0-4-amd64_3.2.2.2-10-20170707181826.44_amd64.deb?sv=2015-04-05&sr=b&sig=xtGLlxX5SspadCxaObMGGVMQliPGrTkuN0T6A4wLETA%3D&se=2031-03-19T21%3A21%3A43Z&sp=r" - -SONIC_ONLINE_DEBS += $(BRCM_OPENNSL) $(BRCM_OPENNSL_KERNEL) +SONIC_ONLINE_DEBS += $(BRCM_OPENNSL_KERNEL) diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 7c505290bb26..d1417bff1778 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 7c505290bb26babdef604a377e71b3df702897a8 +Subproject commit d1417bff17780255d4cc371b315f620087673eb8 diff --git a/platform/broadcom/sonic-platform-modules-dell b/platform/broadcom/sonic-platform-modules-dell index 5ab014c0d4f9..1abd4e6c41f6 160000 --- a/platform/broadcom/sonic-platform-modules-dell +++ b/platform/broadcom/sonic-platform-modules-dell @@ -1 +1 @@ -Subproject commit 5ab014c0d4f9ad71d7791e7d4da0645d2b2d493b +Subproject commit 1abd4e6c41f633272667a5833a63ab6f8da15199 diff --git a/platform/broadcom/sonic-platform-modules-ingrasys b/platform/broadcom/sonic-platform-modules-ingrasys index 1a67af3caa00..e66b8839da21 160000 --- a/platform/broadcom/sonic-platform-modules-ingrasys +++ b/platform/broadcom/sonic-platform-modules-ingrasys @@ -1 +1 @@ -Subproject commit 1a67af3caa00352e5e7db880e1eeda0bdf1fde6b +Subproject commit e66b8839da2180fd586aae040701faf180d59477 diff --git a/platform/mellanox/docker-ptf-mlnx.mk b/platform/mellanox/docker-ptf-mlnx.mk index 7f23dc715e32..9f994f62de64 100644 --- a/platform/mellanox/docker-ptf-mlnx.mk +++ b/platform/mellanox/docker-ptf-mlnx.mk @@ -4,4 +4,4 @@ DOCKER_PTF_MLNX = docker-ptf-mlnx.gz $(DOCKER_PTF_MLNX)_PATH = $(DOCKERS_PATH)/docker-ptf-saithrift $(DOCKER_PTF_MLNX)_DEPENDS += $(PYTHON_SAITHRIFT_MLNX) $(DOCKER_PTF_MLNX)_LOAD_DOCKERS += $(DOCKER_PTF) -SONIC_DOCKER_IMAGES += $(DOCKER_PTF_MLNX) +#SONIC_DOCKER_IMAGES += $(DOCKER_PTF_MLNX) diff --git a/platform/mellanox/docker-syncd-mlnx/start.sh b/platform/mellanox/docker-syncd-mlnx/start.sh index 0ad00c6fc252..623316050475 100755 --- a/platform/mellanox/docker-syncd-mlnx/start.sh +++ b/platform/mellanox/docker-syncd-mlnx/start.sh @@ -4,8 +4,4 @@ rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd -# mlnx-fw-upgrade.sh will exit if firmware was actually upgraded -# or if some error occurs -. mlnx-fw-upgrade.sh - supervisorctl start syncd diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index a50230a025d9..8c40d46d9182 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -1,6 +1,6 @@ # mellanox firmware -MLNX_FW_VERSION = 13.1224.0140 +MLNX_FW_VERSION = 13.1400.0126 MLNX_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_FW_VERSION))-EVB.mfa $(MLNX_FW_FILE)_URL = $(MLNX_SDK_BASE_URL)/$(MLNX_FW_FILE) SONIC_ONLINE_FILES += $(MLNX_FW_FILE) diff --git a/platform/mellanox/libsaithrift-dev.mk b/platform/mellanox/libsaithrift-dev.mk index 0fc6d3f4eb84..39222be39cab 100644 --- a/platform/mellanox/libsaithrift-dev.mk +++ b/platform/mellanox/libsaithrift-dev.mk @@ -4,4 +4,4 @@ LIBSAITHRIFT_DEV_MLNX = libsaithrift-dev_0.9.4_amd64.deb $(LIBSAITHRIFT_DEV_MLNX)_SRC_PATH = $(SRC_PATH)/SAI $(LIBSAITHRIFT_DEV_MLNX)_DEPENDS += $(LIBTHRIFT) $(LIBTHRIFT_DEV) $(THRIFT_COMPILER) $(MLNX_SAI) $(MLNX_SAI_DEV) $(LIBSAITHRIFT_DEV_MLNX)_RDEPENDS += $(LIBTHRIFT) $(MLNX_SAI) -SONIC_DPKG_DEBS += $(LIBSAITHRIFT_DEV_MLNX) +#SONIC_DPKG_DEBS += $(LIBSAITHRIFT_DEV_MLNX) diff --git a/platform/mellanox/mlnx-sai.mk b/platform/mellanox/mlnx-sai.mk index 332d496e76d0..bba10132160d 100644 --- a/platform/mellanox/mlnx-sai.mk +++ b/platform/mellanox/mlnx-sai.mk @@ -1,7 +1,7 @@ # Mellanox SAI -MLNX_SAI_VERSION = 161120 -MLNX_SAI_REVISION = ba3ccd6de8e5b82fa2cdfc30f9b8b1f1882bfede +MLNX_SAI_VERSION = sonic1.9.1fixes-master +MLNX_SAI_REVISION = dc0e84b3762f847369524a917e271ceb2878b4d3 export MLNX_SAI_VERSION MLNX_SAI_REVISION diff --git a/platform/mellanox/python-saithrift.mk b/platform/mellanox/python-saithrift.mk index cbe5af29b3e2..59685121e02c 100644 --- a/platform/mellanox/python-saithrift.mk +++ b/platform/mellanox/python-saithrift.mk @@ -3,4 +3,4 @@ PYTHON_SAITHRIFT_MLNX = python-saithrift_0.9.4_amd64.deb $(PYTHON_SAITHRIFT_MLNX)_SRC_PATH = $(SRC_PATH)/SAI $(PYTHON_SAITHRIFT_MLNX)_DEPENDS += $(MLNX_SAI_DEV) $(MLNX_SAI) $(THRIFT_COMPILER) $(PYTHON_THRIFT) $(LIBTHRIFT_DEV) -SONIC_DPKG_DEBS += $(PYTHON_SAITHRIFT_MLNX) +#SONIC_DPKG_DEBS += $(PYTHON_SAITHRIFT_MLNX) diff --git a/platform/mellanox/rules.mk b/platform/mellanox/rules.mk index 6b88748c73a2..d67401df245d 100644 --- a/platform/mellanox/rules.mk +++ b/platform/mellanox/rules.mk @@ -12,12 +12,10 @@ include $(PLATFORM_PATH)/python-saithrift.mk include $(PLATFORM_PATH)/docker-ptf-mlnx.mk SONIC_ALL += $(SONIC_ONE_IMAGE) \ - $(DOCKER_FPM) \ - $(DOCKER_PTF_MLNX) \ - $(DOCKER_SYNCD_MLNX_RPC) + $(DOCKER_FPM) # Inject mlnx sai into sairedis -$(LIBSAIREDIS)_DEPENDS += $(MLNX_SAI) $(LIBSAITHRIFT_DEV_MLNX) +$(LIBSAIREDIS)_DEPENDS += $(MLNX_SAI) #$(LIBSAITHRIFT_DEV_MLNX) # Runtime dependency on mlnx sai is set only for syncd $(SYNCD)_RDEPENDS += $(MLNX_SAI) diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index bb576aaabee5..7c517627c23d 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,5 +1,5 @@ -MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/ba3ccd6de8e5b82fa2cdfc30f9b8b1f1882bfede/sdk -MLNX_SDK_VERSION = 4.2.3130 +MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/4ebc01e95b754c56da7f8b5fb45b82fbe661d05a/sdk +MLNX_SDK_VERSION = 4.2.5010 MLNX_SDK_RDEBS += $(APPLIBS) $(IPROUTE2) $(SX_ACL_RM) $(SX_COMPLIB) \ $(SX_EXAMPLES) $(SX_GEN_UTILS) $(SX_SCEW) $(SX_SDN_HAL) \ $(SXD_LIBS) $(TESTX) @@ -20,8 +20,6 @@ $(eval $(call add_derived_package,$(IPROUTE2),$(IPROUTE2_DEV))) SX_COMPLIB = sx-complib_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb SX_COMPLIB_DEV = sx-complib-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_COMPLIB),$(SX_COMPLIB_DEV))) -SX_COMPLIB_DEV_STATIC = sx-complib-dev-static_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -$(eval $(call add_derived_package,$(SX_COMPLIB),$(SX_COMPLIB_DEV_STATIC))) SX_EXAMPLES = sx-examples_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb $(SX_EXAMPLES)_DEPENDS += $(APPLIBS) $(SX_SCEW) $(SXD_LIBS) SX_EXAMPLES_DEV = sx-examples-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb @@ -33,13 +31,9 @@ $(eval $(call add_derived_package,$(SX_GEN_UTILS),$(SX_GEN_UTILS_DEV))) SX_SCEW = sx-scew_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb SX_SCEW_DEV = sx-scew-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_SCEW),$(SX_SCEW_DEV))) -SX_SCEW_DEV_STATIC = sx-scew-dev-static_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -$(eval $(call add_derived_package,$(SX_SCEW),$(SX_SCEW_DEV_STATIC))) SXD_LIBS = sxd-libs_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb SXD_LIBS_DEV = sxd-libs-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SXD_LIBS),$(SXD_LIBS_DEV))) -SXD_LIBS_DEV_STATIC = sxd-libs-dev-static_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -$(eval $(call add_derived_package,$(SXD_LIBS),$(SXD_LIBS_DEV_STATIC))) #packages that are required for runtime only PYTHON_SDK_API = python-sdk-api_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb $(PYTHON_SDK_API)_DEPENDS += $(APPLIBS) $(SXD_LIBS) diff --git a/rules/config b/rules/config index 5403c981f170..ad13ad047e04 100644 --- a/rules/config +++ b/rules/config @@ -12,9 +12,8 @@ # container. SONIC_CONFIG_BUILD_JOBS = 1 -# SONIC_CONFIG_BUILD_JOBS - set number of jobs for number of jobs per package. +# SONIC_CONFIG_MAKE_JOBS - set number of parallel make jobs per package. # Corresponding -j argument will be passed to make/dpkg commands that build separate packages -# container. SONIC_CONFIG_MAKE_JOBS = $(shell nproc) # SONIC_CONFIG_ENABLE_COLORS - enable colored output in build system. @@ -49,3 +48,6 @@ SONIC_ROUTING_STACK = quagga # ENABLE_SYNCD_RPC - build docker-syncd with rpc packages for testing purposes. # Uncomment to enable: # ENABLE_SYNCD_RPC = y + +# Enable Origanization Extensions - Specific to the deployment scenarios of the Organization +ENABLE_ORGANIZATION_EXTENSIONS = y diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index 39f8cdd3f297..76e7dac4ab63 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -12,4 +12,7 @@ $(DOCKER_PLATFORM_MONITOR)_CONTAINER_NAME = pmon $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += --net=host --privileged -t $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +# Mount Arista python library on Aboot images to be used by plugins +$(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista:/usr/lib/python2.7/dist-packages/arista:ro + $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += sensors:/usr/bin/sensors diff --git a/slave.mk b/slave.mk index cc4a59a6d881..c26e4932f05a 100644 --- a/slave.mk +++ b/slave.mk @@ -99,6 +99,7 @@ $(info "SHUTDOWN_BGP_ON_START" : "$(SHUTDOWN_BGP_ON_START)") $(info "SONIC_CONFIG_DEBUG" : "$(SONIC_CONFIG_DEBUG)") $(info "ROUTING_STACK" : "$(SONIC_ROUTING_STACK)") $(info "ENABLE_SYNCD_RPC" : "$(ENABLE_SYNCD_RPC)") +$(info "ENABLE_ORGANIZATION_EXTENSIONS" : "$(ENABLE_ORGANIZATION_EXTENSIONS)") $(info ) ############################################################################### @@ -179,13 +180,13 @@ SONIC_TARGET_LIST += $(addprefix $(FILES_PATH)/, $(SONIC_ONLINE_FILES)) # SONIC_MAKE_DEBS += $(SOME_NEW_DEB) $(addprefix $(DEBS_PATH)/, $(SONIC_MAKE_DEBS)) : $(DEBS_PATH)/% : .platform $$(addsuffix -install,$$(addprefix $(DEBS_PATH)/,$$($$*_DEPENDS))) $(HEADER) - # remove target to force rebuild + # Remove target to force rebuild rm -f $(addprefix $(DEBS_PATH)/, $* $($*_DERIVED_DEBS) $($*_EXTRA_DEBS)) - # apply series of patches if exist + # Apply series of patches if exist if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && QUILT_PATCHES=../$(notdir $($*_SRC_PATH)).patch quilt push -a; popd; fi - # build project and take package + # Build project and take package make DEST=$(shell pwd)/$(DEBS_PATH) -C $($*_SRC_PATH) $(shell pwd)/$(DEBS_PATH)/$* $(LOG) - # clean up + # Clean up if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && quilt pop -a -f; popd; fi $(FOOTER) @@ -199,16 +200,18 @@ SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_MAKE_DEBS)) # SONIC_DPKG_DEBS += $(SOME_NEW_DEB) $(addprefix $(DEBS_PATH)/, $(SONIC_DPKG_DEBS)) : $(DEBS_PATH)/% : .platform $$(addsuffix -install,$$(addprefix $(DEBS_PATH)/,$$($$*_DEPENDS))) $(HEADER) - # Build project and take package + # Remove old build logs if they exist rm -f $($*_SRC_PATH)/debian/*.debhelper.log - # apply series of patches if exist + # Apply series of patches if exist if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && QUILT_PATCHES=../$(notdir $($*_SRC_PATH)).patch quilt push -a; popd; fi + # Build project pushd $($*_SRC_PATH) $(LOG) [ ! -f ./autogen.sh ] || ./autogen.sh $(LOG) dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) $(LOG) popd $(LOG) - # clean up + # Clean up if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && quilt pop -a -f; popd; fi + # Take built package(s) mv $(addprefix $($*_SRC_PATH)/../, $* $($*_DERIVED_DEBS) $($*_EXTRA_DEBS)) $(DEBS_PATH) $(LOG) $(FOOTER) @@ -222,10 +225,15 @@ SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_DPKG_DEBS)) # SONIC_PYTHON_STDEB_DEBS += $(SOME_NEW_DEB) $(addprefix $(DEBS_PATH)/, $(SONIC_PYTHON_STDEB_DEBS)) : $(DEBS_PATH)/% : .platform $$(addsuffix -install,$$(addprefix $(DEBS_PATH)/,$$($$*_DEPENDS))) $(HEADER) - # Build project and take package + # Apply series of patches if exist + if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && QUILT_PATCHES=../$(notdir $($*_SRC_PATH)).patch quilt push -a; popd; fi + # Build project pushd $($*_SRC_PATH) $(LOG) python setup.py --command-packages=stdeb.command bdist_deb $(LOG) popd $(LOG) + # Clean up + if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && quilt pop -a -f; popd; fi + # Take built package(s) mv $(addprefix $($*_SRC_PATH)/deb_dist/, $* $($*_DERIVED_DEBS)) $(DEBS_PATH) $(LOG) $(FOOTER) @@ -374,13 +382,14 @@ $(DOCKER_LOAD_TARGETS) : $(TARGET_PATH)/%.gz-load : .platform docker-start $$(TA # targets for building installers with base image $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : .platform onie-image.conf $$(addprefix $(DEBS_PATH)/,$$($$*_DEPENDS)) $$(addprefix $(DEBS_PATH)/,$$($$*_INSTALLS)) $$(addprefix $(FILES_PATH)/,$$($$*_FILES)) $(addprefix $(DEBS_PATH)/,$(INITRAMFS_TOOLS) $(LINUX_KERNEL) $(IGB_DRIVER) $(SONIC_DEVICE_DATA) $(SONIC_UTILS)) $$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) $$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_CONFIG_ENGINE)) $(HEADER) - ## Pass initramfs and linux kernel explicitly. They are used for all platforms + # Pass initramfs and linux kernel explicitly. They are used for all platforms export initramfs_tools="$(DEBS_PATH)/$(INITRAMFS_TOOLS)" export linux_kernel="$(DEBS_PATH)/$(LINUX_KERNEL)" export kversion="$(KVERSION)" export image_type="$($*_IMAGE_TYPE)" export sonicadmin_user="$(USERNAME)" export sonic_asic_platform="$(CONFIGURED_PLATFORM)" + export enable_organization_extensions="$(ENABLE_ORGANIZATION_EXTENSIONS)" export enable_dhcp_graph_service="$(ENABLE_DHCP_GRAPH_SERVICE)" export shutdown_bgp_on_start="$(SHUTDOWN_BGP_ON_START)" export installer_debs="$(addprefix $(DEBS_PATH)/,$($*_DEPENDS))" @@ -393,6 +402,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : .platform export docker_image="$(docker)" export docker_image_name="$(basename $(docker))" export docker_container_name="$($(docker)_CONTAINER_NAME)" + $(eval $(docker)_RUN_OPT += $($(docker)_$($*_IMAGE_TYPE)_RUN_OPT)) export docker_image_run_opt="$($(docker)_RUN_OPT)" j2 files/build_templates/docker_image_ctl.j2 > $($(docker)_CONTAINER_NAME).sh if [ -f files/build_templates/$($(docker)_CONTAINER_NAME).service.j2 ]; then @@ -413,6 +423,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : .platform chmod +x sonic_debian_extension.sh, ) + DIRTY_SUFFIX="$(shell date +%Y%m%d\.%H%M%S)" + export DIRTY_SUFFIX ./build_debian.sh "$(USERNAME)" "$(shell perl -e 'print crypt("$(PASSWORD)", "salt"),"\n"')" $(LOG) TARGET_MACHINE=$($*_MACHINE) IMAGE_TYPE=$($*_IMAGE_TYPE) ./build_image.sh $(LOG) diff --git a/src/SAI b/src/SAI deleted file mode 160000 index 940c7b6afb1d..000000000000 --- a/src/SAI +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 940c7b6afb1db4e8504b7cdb24ccd669748dbde8 diff --git a/src/libteam/0003-teamd-lacp-runner-will-send-lacp-update-right-after-.patch b/src/libteam/0003-teamd-lacp-runner-will-send-lacp-update-right-after-.patch new file mode 100644 index 000000000000..1cae8bad21aa --- /dev/null +++ b/src/libteam/0003-teamd-lacp-runner-will-send-lacp-update-right-after-.patch @@ -0,0 +1,98 @@ +From 417e9dfdccbbee2cf86e46e994e8ece3433b46a4 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Wed, 20 Sep 2017 00:34:07 +0000 +Subject: [PATCH] [teamd] lacp runner will send lacp update right after it + received SIGINT signal + +--- + teamd/teamd.c | 1 + + teamd/teamd.h | 3 +++ + teamd/teamd_events.c | 13 +++++++++++++ + teamd/teamd_runner_lacp.c | 10 ++++++++++ + 4 files changed, 27 insertions(+) + +diff --git a/teamd/teamd.c b/teamd/teamd.c +index aac2511..c987333 100644 +--- a/teamd/teamd.c ++++ b/teamd/teamd.c +@@ -386,6 +386,7 @@ static int teamd_run_loop_run(struct teamd_context *ctx) + case 'q': + if (quit_in_progress) + return -EBUSY; ++ teamd_refresh_ports(ctx); + err = teamd_flush_ports(ctx); + if (err) + return err; +diff --git a/teamd/teamd.h b/teamd/teamd.h +index 5dbfb9b..ef0fb1c 100644 +--- a/teamd/teamd.h ++++ b/teamd/teamd.h +@@ -189,11 +189,14 @@ struct teamd_event_watch_ops { + struct teamd_port *tdport, void *priv); + int (*port_ifname_changed)(struct teamd_context *ctx, + struct teamd_port *tdport, void *priv); ++ void (*refresh)(struct teamd_context *ctx, ++ struct teamd_port *tdport, void *priv); + int (*option_changed)(struct teamd_context *ctx, + struct team_option *option, void *priv); + char *option_changed_match_name; + }; + ++void teamd_refresh_ports(struct teamd_context *ctx); + int teamd_event_port_added(struct teamd_context *ctx, + struct teamd_port *tdport); + void teamd_event_port_removed(struct teamd_context *ctx, +diff --git a/teamd/teamd_events.c b/teamd/teamd_events.c +index 1a95974..5c2ef56 100644 +--- a/teamd/teamd_events.c ++++ b/teamd/teamd_events.c +@@ -34,6 +34,19 @@ struct event_watch_item { + void *priv; + }; + ++void teamd_refresh_ports(struct teamd_context *ctx) ++{ ++ struct teamd_port *tdport; ++ struct event_watch_item *watch; ++ ++ teamd_for_each_tdport(tdport, ctx) { ++ list_for_each_node_entry(watch, &ctx->event_watch_list, list) { ++ if (!watch->ops->refresh) continue; ++ watch->ops->refresh(ctx, tdport, watch->priv); ++ } ++ } ++} ++ + int teamd_event_port_added(struct teamd_context *ctx, + struct teamd_port *tdport) + { +diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c +index 9c77fae..e38c291 100644 +--- a/teamd/teamd_runner_lacp.c ++++ b/teamd/teamd_runner_lacp.c +@@ -1383,12 +1383,22 @@ static int lacp_event_watch_port_changed(struct teamd_context *ctx, + return lacp_port_link_update(lacp_port); + } + ++static void lacp_event_watch_refresh(struct teamd_context *ctx, struct teamd_port *tdport, void *priv) ++{ ++ struct lacp *lacp = priv; ++ ++ struct lacp_port *lacp_port = lacp_port_get(lacp, tdport); ++ if (lacp_port_selected(lacp_port)) ++ (void) lacpdu_send(lacp_port); ++} ++ + static const struct teamd_event_watch_ops lacp_event_watch_ops = { + .hwaddr_changed = lacp_event_watch_hwaddr_changed, + .port_added = lacp_event_watch_port_added, + .port_removed = lacp_event_watch_port_removed, + .port_changed = lacp_event_watch_port_changed, + .admin_state_changed = lacp_event_watch_admin_state_changed, ++ .refresh = lacp_event_watch_refresh, + }; + + static int lacp_carrier_init(struct teamd_context *ctx, struct lacp *lacp) +-- +2.7.4 + diff --git a/src/libteam/Makefile b/src/libteam/Makefile index 283a6b56fbec..c84250749477 100644 --- a/src/libteam/Makefile +++ b/src/libteam/Makefile @@ -17,6 +17,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Apply patch git apply ../0001-libteam-Add-team_get_port_enabled-function.patch git apply ../0002-libteam-Temporarily-remove-redundant-debug-mes.patch + git apply ../0003-teamd-lacp-runner-will-send-lacp-update-right-after-.patch popd # Obtain debian packaging diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index c0b2e6550a9f..997008af5cee 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -100,9 +100,8 @@ def parse_png(png, hname): if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): (lo_prefix, mgmt_prefix, name, hwsku, d_type) = parse_device(device) - lo_addr = None if not lo_prefix else lo_prefix.split('/')[0] - mgmt_addr = None if not mgmt_prefix else mgmt_prefix.split('/')[0] - devices[name] = {'lo_addr': lo_addr, 'type': d_type, 'mgmt_addr': mgmt_addr, 'hwsku': hwsku} + device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } + devices[name] = device_data if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): @@ -131,71 +130,28 @@ def parse_dpg(dpg, hname): continue ipintfs = child.find(str(QName(ns, "IPInterfaces"))) - intfs = [] + intfs = {} for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text intfname = port_alias_map.get(intfalias, intfalias) ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text - ipn = ipaddress.IPNetwork(ipprefix) - ipaddr = ipn.ip - prefix_len = ipn.prefixlen - addr_bits = ipn.max_prefixlen - subnet = ipaddress.IPNetwork(str(ipn.network) + '/' + str(prefix_len)) - ipmask = ipn.netmask - - intf = {'addr': ipaddr, 'subnet': subnet} - if isinstance(ipn, ipaddress.IPv4Network): - intf['mask'] = ipmask - else: - intf['mask'] = str(prefix_len) - intf.update({'attachto': intfname, 'prefixlen': int(prefix_len)}) - - # TODO: remove peer_addr after dependency removed - ipaddr_val = int(ipn.ip) - peer_addr_val = None - if int(prefix_len) == addr_bits - 2: - if ipaddr_val & 0x3 == 1: - peer_addr_val = ipaddr_val + 1 - else: - peer_addr_val = ipaddr_val - 1 - elif int(prefix_len) == addr_bits - 1: - if ipaddr_val & 0x1 == 0: - peer_addr_val = ipaddr_val + 1 - else: - peer_addr_val = ipaddr_val - 1 - if peer_addr_val is not None: - intf['peer_addr'] = ipaddress.IPAddress(peer_addr_val) - intfs.append(intf) + intfs[(intfname, ipprefix)] = {} lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) - lo_intfs = [] + lo_intfs = {} for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): intfname = lointf.find(str(QName(ns, "AttachTo"))).text ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text - ipn = ipaddress.IPNetwork(ipprefix) - ipaddr = ipn.ip - prefix_len = ipn.prefixlen - ipmask = ipn.netmask - lo_intf = {'name': intfname, 'addr': ipaddr, 'prefixlen': prefix_len} - if isinstance(ipn, ipaddress.IPv4Network): - lo_intf['mask'] = ipmask - else: - lo_intf['mask'] = str(prefix_len) - lo_intfs.append(lo_intf) - + lo_intfs[(intfname, ipprefix)] = {} + mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) - mgmt_intf = None + mgmt_intf = {} for mgmtintf in mgmtintfs.findall(str(QName(ns1, "ManagementIPInterface"))): + intfname = mgmtintf.find(str(QName(ns, "AttachTo"))).text ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text mgmtipn = ipaddress.IPNetwork(ipprefix) - # Ignore IPv6 management address - if mgmtipn.version == 6: - continue - ipaddr = mgmtipn.ip - prefix_len = str(mgmtipn.prefixlen) - ipmask = mgmtipn.netmask gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) - mgmt_intf = {'addr': ipaddr, 'prefixlen': prefix_len, 'mask': ipmask, 'gwaddr': gwaddr} + mgmt_intf[(intfname, ipprefix)] = {'gwaddr': gwaddr} pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) pc_intfs = [] @@ -206,7 +162,7 @@ def parse_dpg(dpg, hname): pcmbr_list = pcintfmbr.split(';') for i, member in enumerate(pcmbr_list): pcmbr_list[i] = port_alias_map.get(member, member) - pcs[pcintfname] = {'name': pcintfname, 'members': pcmbr_list} + pcs[pcintfname] = {'members': pcmbr_list} vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] @@ -218,7 +174,7 @@ def parse_dpg(dpg, hname): vmbr_list = vintfmbr.split(';') for i, member in enumerate(vmbr_list): vmbr_list[i] = port_alias_map.get(member, member) - vlan_attributes = {'name': vintfname, 'members': vmbr_list, 'vlanid': vlanid} + vlan_attributes = {'members': vmbr_list, 'vlanid': vlanid} sonic_vlan_name = "Vlan%s" % vlanid vlans[sonic_vlan_name] = vlan_attributes @@ -243,7 +199,7 @@ def parse_dpg(dpg, hname): acl_intfs = port_alias_map.values() break; if acl_intfs: - acls[aclname] = { 'AttachTo': acl_intfs, 'IsMirror': is_mirror } + acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'mirror' if is_mirror else 'L3'} return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls return None, None, None, None, None, None @@ -279,7 +235,7 @@ def parse_cpg(cpg, hname): else: rrclient = '0' if hostname == hname: - myasn = int(asn) + myasn = asn peers = router.find(str(QName(ns1, "Peers"))) for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))): addr = bgpPeer.find(str(QName(ns, "Address"))).text @@ -295,8 +251,8 @@ def parse_cpg(cpg, hname): for peer in bgp_sessions: bgp_session = bgp_sessions[peer] if hostname == bgp_session['name']: - bgp_session['asn'] = int(asn) - bgp_session['rrclient'] = int(rrclient) + bgp_session['asn'] = asn + bgp_session['rrclient'] = rrclient return bgp_sessions, myasn, bgp_peers_with_range @@ -331,51 +287,17 @@ def parse_meta(meta, hname): return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id def parse_deviceinfo(meta, hwsku): - ethernet_interfaces = [] - + ethernet_interfaces = {} for device_info in meta.findall(str(QName(ns, "DeviceInfo"))): dev_sku = device_info.find(str(QName(ns, "HwSku"))).text if dev_sku == hwsku: interfaces = device_info.find(str(QName(ns, "EthernetInterfaces"))) for interface in interfaces.findall(str(QName(ns1, "EthernetInterface"))): - name = interface.find(str(QName(ns, "InterfaceName"))).text + alias = interface.find(str(QName(ns, "InterfaceName"))).text speed = interface.find(str(QName(ns, "Speed"))).text - ethernet_interfaces.append({ 'name':name, 'speed':speed }) - + ethernet_interfaces[port_alias_map.get(alias, alias)] = speed return ethernet_interfaces -def get_console_info(devices, dev, port): - for k, v in devices.items(): - if k == dev: - break - else: - return {} - - ret_val = v - ret_val.update({ - 'ts_port': port, - 'ts_dev': dev - }) - - return ret_val - - -def get_mgmt_info(devices, dev, port): - for k, v in devices.items(): - if k == dev: - break - else: - return {} - - ret_val = v - ret_val.update({ - 'mgmt_port': port, - 'mgmt_dev': dev - }) - - return ret_val - - def parse_port_config(hwsku, platform=None, port_config_file=None): port_config_candidates = [] if port_config_file != None: @@ -406,7 +328,7 @@ def parse_port_config(hwsku, platform=None, port_config_file=None): alias = name else: alias = tokens[2].strip() - ports[name] = {'name': name, 'alias': alias} + ports[name] = {'alias': alias} port_alias_map[alias] = name return ports @@ -429,7 +351,7 @@ def parse_xml(filename, platform=None, port_config_file=None): neighbors = None devices = None hostname = None - ethernet_interfaces = [] + port_speeds = {} syslog_servers = [] dhcp_servers = [] ntp_servers = [] @@ -460,93 +382,91 @@ def parse_xml(filename, platform=None, port_config_file=None): elif child.tag == str(QName(ns, "MetadataDeclaration")): (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) elif child.tag == str(QName(ns, "DeviceInfos")): - ethernet_interfaces = parse_deviceinfo(child, hwsku) + port_speeds = parse_deviceinfo(child, hwsku) results = {} - results['minigraph_hwsku'] = hwsku - # sorting by lambdas are not easily done without custom filters. - # TODO: add jinja2 filter to accept a lambda to sort a list of dictionaries by attribute. - # TODO: alternatively (preferred), implement class containers for multiple-attribute entries, enabling sort by attr + results['DEVICE_METADATA'] = {'localhost': { + 'bgp_asn': bgp_asn, + 'deployment_id': deployment_id, + 'hostname': hostname, + 'hwsku': hwsku, + 'type': devices[hostname]['type'] + }} results['BGP_NEIGHBOR'] = bgp_sessions - results['DEVICE_METADATA'] = {'localhost': { 'bgp_asn': bgp_asn }} results['BGP_PEER_RANGE'] = bgp_peers_with_range - # TODO: sort does not work properly on all interfaces of varying lengths. Need to sort by integer group(s). - - phyport_intfs = [] - vlan_intfs = [] - pc_intfs = [] + if mgmt_routes: + # TODO: differentiate v4 and v6 + mgmt_intf.itervalues().next()['forced_mgmt_routes'] = mgmt_routes + results['MGMT_INTERFACE'] = mgmt_intf + results['LOOPBACK_INTERFACE'] = lo_intfs + + phyport_intfs = {} + vlan_intfs = {} + pc_intfs = {} for intf in intfs: - intfname = intf['attachto'] - if intfname[0:4] == 'Vlan': - vlan_intfs.append(intf) - elif intfname[0:11] == 'PortChannel': - pc_intfs.append(intf) + if intf[0][0:4] == 'Vlan': + vlan_intfs[intf] = {} + elif intf[0][0:11] == 'PortChannel': + pc_intfs[intf] = {} else: - phyport_intfs.append(intf) - - results['minigraph_interfaces'] = sorted(phyport_intfs, key=lambda x: x['attachto']) - results['minigraph_vlan_interfaces'] = sorted(vlan_intfs, key=lambda x: x['attachto']) - results['minigraph_portchannel_interfaces'] = sorted(pc_intfs, key=lambda x: x['attachto']) - results['minigraph_ports'] = ports - results['minigraph_vlans'] = vlans - results['minigraph_portchannels'] = pcs - results['minigraph_mgmt_interface'] = mgmt_intf - results['minigraph_lo_interfaces'] = lo_intfs - results['minigraph_acls'] = acls - results['minigraph_neighbors'] = neighbors - results['minigraph_devices'] = devices - results['minigraph_underlay_neighbors'] = u_neighbors - results['minigraph_underlay_devices'] = u_devices - results['minigraph_as_xml'] = mini_graph_path - if devices != None: - results['minigraph_console'] = get_console_info(devices, console_dev, console_port) - results['minigraph_mgmt'] = get_mgmt_info(devices, mgmt_dev, mgmt_port) - results['minigraph_hostname'] = hostname - results['inventory_hostname'] = hostname - results['syslog_servers'] = syslog_servers - results['dhcp_servers'] = dhcp_servers - results['ntp_servers'] = ntp_servers - results['forced_mgmt_routes'] = mgmt_routes - results['erspan_dst'] = erspan_dst - results['deployment_id'] = deployment_id - results['ethernet_interfaces'] = ethernet_interfaces + phyport_intfs[intf] = {} + + results['INTERFACE'] = phyport_intfs + results['VLAN_INTERFACE'] = vlan_intfs + results['PORTCHANNEL_INTERFACE'] = pc_intfs + + for port_name in port_speeds: + ports.setdefault(port_name, {})['speed'] = port_speeds[port_name] + results['PORT'] = ports + results['PORTCHANNEL'] = pcs + results['VLAN'] = vlans + + results['DEVICE_NEIGHBOR'] = neighbors + results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) + results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) + results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) + + results['ACL_TABLE'] = acls + mirror_sessions = {} + if erspan_dst: + lo_addr = '0.0.0.0' + for lo in lo_intfs: + lo_network = ipaddress.IPNetwork(lo[1]) + if lo_network.version == 4: + lo_addr = str(lo_network.ip) + break + count = 0 + for dst in erspan_dst: + mirror_sessions['everflow{}'.format(count)] = {"dst_ip": dst, "src_ip": lo_addr} + count += 1 + results['MIRROR_SESSION'] = mirror_sessions return results + def parse_device_desc_xml(filename): root = ET.parse(filename).getroot() (lo_prefix, mgmt_prefix, hostname, hwsku, d_type) = parse_device(root) results = {} - results['minigraph_hwsku'] = hwsku - results['minigraph_hostname'] = hostname - results['inventory_hostname'] = hostname - - lo_intfs = [] - ipn = ipaddress.IPNetwork(lo_prefix) - ipaddr = ipn.ip - prefix_len = ipn.prefixlen - ipmask = ipn.netmask - lo_intf = {'name': None, 'addr': ipaddr, 'prefixlen': prefix_len} - if isinstance(ipn, ipaddress.IPv4Network): - lo_intf['mask'] = ipmask - else: - lo_intf['mask'] = str(prefix_len) - lo_intfs.append(lo_intf) - results['minigraph_lo_interfaces'] = lo_intfs + results['DEVICE_METADATA'] = {'localhost': { + 'hostname': hostname, + 'hwsku': hwsku, + }} + + results['LOOPBACK_INTERFACE'] = {('lo', lo_prefix): {}} + + mgmt_intf = {} + mgmtipn = ipaddress.IPNetwork(mgmt_prefix) + gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) + results['MGMT_INTERFACE'] = {('eth0', mgmt_prefix): {'gwaddr': gwaddr}} - mgmt_intf = None - mgmt_ipn = ipaddress.IPNetwork(mgmt_prefix) - ipaddr = mgmt_ipn.ip - prefix_len = str(mgmt_ipn.prefixlen) - ipmask = mgmt_ipn.netmask - gwaddr = ipaddress.IPAddress(int(mgmt_ipn.network) + 1) - mgmt_intf = {'addr': ipaddr, 'prefixlen': prefix_len, 'mask': ipmask, 'gwaddr': gwaddr} - results['minigraph_mgmt_interface'] = mgmt_intf return results + port_alias_map = {} + def print_parse_xml(filename): results = parse_xml(filename) print(json.dumps(results, indent=3, cls=minigraph_encoder)) diff --git a/src/sonic-config-engine/minigraph.py~ b/src/sonic-config-engine/minigraph.py~ new file mode 100644 index 000000000000..f97877c1cd5e --- /dev/null +++ b/src/sonic-config-engine/minigraph.py~ @@ -0,0 +1,472 @@ +#!/usr/bin/env python +import calendar +import os +import sys +import socket +import struct +import json +import copy +import ipaddr as ipaddress +from collections import defaultdict + +from lxml import etree as ET +from lxml.etree import QName + +DOCUMENTATION = ''' +--- +module: minigraph_facts +version_added: "1.9" +author: Guohan Lu (gulv@microsoft.com) +short_description: Retrive minigraph facts for a device. +description: + - Retrieve minigraph facts for a device, the facts will be + inserted to the ansible_facts key. +options: + host: + description: + - Set to target snmp server (normally {{inventory_hostname}}) + required: true +''' + +EXAMPLES = ''' +# Gather minigraph facts +- name: Gathering minigraph facts about the device + minigraph_facts: host={{ hostname }} +''' + +ns = "Microsoft.Search.Autopilot.Evolution" +ns1 = "http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" +ns2 = "Microsoft.Search.Autopilot.NetMux" +ns3 = "http://www.w3.org/2001/XMLSchema-instance" + + +class minigraph_encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, ( + ipaddress.IPv4Network, ipaddress.IPv6Network, + ipaddress.IPv4Address, ipaddress.IPv6Address + )): + return str(obj) + return json.JSONEncoder.default(self, obj) + +def parse_device(device): + lo_prefix = None + mgmt_prefix = None + d_type = None # don't shadow type() + hwsku = None + name = None + if str(QName(ns3, "type")) in device.attrib: + d_type = device.attrib[str(QName(ns3, "type"))] + + for node in device: + if node.tag == str(QName(ns, "Address")): + lo_prefix = node.find(str(QName(ns2, "IPPrefix"))).text + elif node.tag == str(QName(ns, "ManagementAddress")): + mgmt_prefix = node.find(str(QName(ns2, "IPPrefix"))).text + elif node.tag == str(QName(ns, "Hostname")): + name = node.text + elif node.tag == str(QName(ns, "HwSku")): + hwsku = node.text + return (lo_prefix, mgmt_prefix, name, hwsku, d_type) + +def parse_png(png, hname): + neighbors = {} + devices = {} + console_dev = '' + console_port = '' + mgmt_dev = '' + mgmt_port = '' + for child in png: + if child.tag == str(QName(ns, "DeviceInterfaceLinks")): + for link in child.findall(str(QName(ns, "DeviceLinkBase"))): + linktype = link.find(str(QName(ns, "ElementType"))).text + if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": + continue + + enddevice = link.find(str(QName(ns, "EndDevice"))).text + endport = link.find(str(QName(ns, "EndPort"))).text + startdevice = link.find(str(QName(ns, "StartDevice"))).text + startport = link.find(str(QName(ns, "StartPort"))).text + + if enddevice == hname: + if port_alias_map.has_key(endport): + endport = port_alias_map[endport] + neighbors[endport] = {'name': startdevice, 'port': startport} + else: + if port_alias_map.has_key(startport): + startport = port_alias_map[startport] + neighbors[startport] = {'name': enddevice, 'port': endport} + + if child.tag == str(QName(ns, "Devices")): + for device in child.findall(str(QName(ns, "Device"))): + (lo_prefix, mgmt_prefix, name, hwsku, d_type) = parse_device(device) + device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } + devices[name] = device_data + + if child.tag == str(QName(ns, "DeviceInterfaceLinks")): + for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): + if str(QName(ns3, "type")) in if_link.attrib: + link_type = if_link.attrib[str(QName(ns3, "type"))] + if link_type == 'DeviceSerialLink': + for node in if_link: + if node.tag == str(QName(ns, "EndPort")): + console_port = node.text.split()[-1] + elif node.tag == str(QName(ns, "EndDevice")): + console_dev = node.text + elif link_type == 'DeviceMgmtLink': + for node in if_link: + if node.tag == str(QName(ns, "EndPort")): + mgmt_port = node.text.split()[-1] + elif node.tag == str(QName(ns, "EndDevice")): + mgmt_dev = node.text + + return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) + + +def parse_dpg(dpg, hname): + for child in dpg: + hostname = child.find(str(QName(ns, "Hostname"))) + if hostname.text != hname: + continue + + ipintfs = child.find(str(QName(ns, "IPInterfaces"))) + intfs = {} + for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): + intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text + intfname = port_alias_map.get(intfalias, intfalias) + ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text + intfs[(intfname, ipprefix)] = {} + + lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) + lo_intfs = {} + for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): + intfname = lointf.find(str(QName(ns, "AttachTo"))).text + ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text + lo_intfs[(intfname, ipprefix)] = {} + + mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) + mgmt_intf = {} + for mgmtintf in mgmtintfs.findall(str(QName(ns1, "ManagementIPInterface"))): + intfname = mgmtintf.find(str(QName(ns, "AttachTo"))).text + ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text + mgmtipn = ipaddress.IPNetwork(ipprefix) + gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) + mgmt_intf[(intfname, ipprefix)] = {'gwaddr': gwaddr} + + pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) + pc_intfs = [] + pcs = {} + for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))): + pcintfname = pcintf.find(str(QName(ns, "Name"))).text + pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text + pcmbr_list = pcintfmbr.split(';') + for i, member in enumerate(pcmbr_list): + pcmbr_list[i] = port_alias_map.get(member, member) + pcs[pcintfname] = {'members': pcmbr_list} + + vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) + vlan_intfs = [] + vlans = {} + for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): + vintfname = vintf.find(str(QName(ns, "Name"))).text + vlanid = vintf.find(str(QName(ns, "VlanID"))).text + vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text + vmbr_list = vintfmbr.split(';') + for i, member in enumerate(vmbr_list): + vmbr_list[i] = port_alias_map.get(member, member) + vlan_attributes = {'members': vmbr_list, 'vlanid': vlanid} + sonic_vlan_name = "Vlan%s" % vlanid + vlans[sonic_vlan_name] = vlan_attributes + + aclintfs = child.find(str(QName(ns, "AclInterfaces"))) + acls = {} + for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): + aclname = aclintf.find(str(QName(ns, "InAcl"))).text.lower().replace(" ", "_").replace("-", "_") + aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') + acl_intfs = [] + is_mirror = False + for member in aclattach: + member = member.strip() + if pcs.has_key(member): + acl_intfs.extend(pcs[member]['members']) # For ACL attaching to port channels, we break them into port channel members + elif vlans.has_key(member): + print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported" + elif port_alias_map.has_key(member): + acl_intfs.append(port_alias_map[member]) + elif member.lower() == 'erspan': + is_mirror = True; + # Erspan session will be attached to all front panel ports + acl_intfs = port_alias_map.values() + break; + if acl_intfs: + acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'mirror' if is_mirror else 'L3'} + return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls + return None, None, None, None, None, None + + +def parse_cpg(cpg, hname): + bgp_sessions = {} + myasn = None + bgp_peers_with_range = {} + for child in cpg: + tag = child.tag + if tag == str(QName(ns, "PeeringSessions")): + for session in child.findall(str(QName(ns, "BGPSession"))): + start_router = session.find(str(QName(ns, "StartRouter"))).text + start_peer = session.find(str(QName(ns, "StartPeer"))).text + end_router = session.find(str(QName(ns, "EndRouter"))).text + end_peer = session.find(str(QName(ns, "EndPeer"))).text + if end_router == hname: + bgp_sessions[start_peer] = { + 'name': start_router, + 'local_addr': end_peer + } + else: + bgp_sessions[end_peer] = { + 'name': end_router, + 'local_addr': start_peer + } + elif child.tag == str(QName(ns, "Routers")): + for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): + asn = router.find(str(QName(ns1, "ASN"))).text + hostname = router.find(str(QName(ns1, "Hostname"))).text + if router.find(str(QName(ns1, "RRClient"))): + rrclient = '1' + else: + rrclient = '0' + if hostname == hname: + myasn = asn + peers = router.find(str(QName(ns1, "Peers"))) + for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))): + addr = bgpPeer.find(str(QName(ns, "Address"))).text + if bgpPeer.find(str(QName(ns1, "PeersRange"))) is not None: + name = bgpPeer.find(str(QName(ns1, "Name"))).text + ip_range = bgpPeer.find(str(QName(ns1, "PeersRange"))).text + ip_range_group = ip_range.split(';') if ip_range and ip_range != "" else [] + bgp_peers_with_range[name] = { + 'name': name, + 'ip_range': ip_range_group + } + else: + for peer in bgp_sessions: + bgp_session = bgp_sessions[peer] + if hostname == bgp_session['name']: + bgp_session['asn'] = int(asn) + bgp_session['rrclient'] = int(rrclient) + + return bgp_sessions, myasn, bgp_peers_with_range + + +def parse_meta(meta, hname): + syslog_servers = [] + dhcp_servers = [] + ntp_servers = [] + mgmt_routes = [] + erspan_dst = [] + deployment_id = None + device_metas = meta.find(str(QName(ns, "Devices"))) + for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))): + if device.find(str(QName(ns1, "Name"))).text == hname: + properties = device.find(str(QName(ns1, "Properties"))) + for device_property in properties.findall(str(QName(ns1, "DeviceProperty"))): + name = device_property.find(str(QName(ns1, "Name"))).text + value = device_property.find(str(QName(ns1, "Value"))).text + value_group = value.split(';') if value and value != "" else [] + if name == "DhcpResources": + dhcp_servers = value_group + elif name == "NtpResources": + ntp_servers = value_group + elif name == "SyslogResources": + syslog_servers = value_group + elif name == "ForcedMgmtRoutes": + mgmt_routes = value_group + elif name == "ErspanDestinationIpv4": + erspan_dst = value_group + elif name == "DeploymentId": + deployment_id = value + return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id + +def parse_deviceinfo(meta, hwsku): + ethernet_interfaces = {} + for device_info in meta.findall(str(QName(ns, "DeviceInfo"))): + dev_sku = device_info.find(str(QName(ns, "HwSku"))).text + if dev_sku == hwsku: + interfaces = device_info.find(str(QName(ns, "EthernetInterfaces"))) + for interface in interfaces.findall(str(QName(ns1, "EthernetInterface"))): + alias = interface.find(str(QName(ns, "InterfaceName"))).text + speed = interface.find(str(QName(ns, "Speed"))).text + ethernet_interfaces[port_alias_map.get(alias, alias)] = speed + return ethernet_interfaces + +def parse_port_config(hwsku, platform=None, port_config_file=None): + port_config_candidates = [] + if port_config_file != None: + port_config_candidates.append(port_config_file) + port_config_candidates.append('/usr/share/sonic/hwsku/port_config.ini') + if platform != None: + port_config_candidates.append(os.path.join('/usr/share/sonic/device', platform, hwsku, 'port_config.ini')) + port_config_candidates.append(os.path.join('/usr/share/sonic/platform', hwsku, 'port_config.ini')) + port_config_candidates.append(os.path.join('/usr/share/sonic', hwsku, 'port_config.ini')) + port_config = None + for candidate in port_config_candidates: + if os.path.isfile(candidate): + port_config = candidate + break + if port_config == None: + return None + + ports = {} + with open(port_config) as data: + for line in data: + if line.startswith('#'): + continue + tokens = line.split() + if len(tokens) < 2: + continue + name = tokens[0].strip() + if len(tokens) == 2: + alias = name + else: + alias = tokens[2].strip() + ports[name] = {'alias': alias} + port_alias_map[alias] = name + return ports + +def parse_xml(filename, platform=None, port_config_file=None): + root = ET.parse(filename).getroot() + mini_graph_path = filename + + u_neighbors = None + u_devices = None + hwsku = None + bgp_sessions = None + bgp_asn = None + intfs = None + vlan_intfs = None + pc_intfs = None + vlans = None + pcs = None + mgmt_intf = None + lo_intf = None + neighbors = None + devices = None + hostname = None + port_speeds = {} + syslog_servers = [] + dhcp_servers = [] + ntp_servers = [] + mgmt_routes = [] + erspan_dst = [] + bgp_peers_with_range = None + deployment_id = None + + hwsku_qn = QName(ns, "HwSku") + hostname_qn = QName(ns, "Hostname") + for child in root: + if child.tag == str(hwsku_qn): + hwsku = child.text + if child.tag == str(hostname_qn): + hostname = child.text + + ports = parse_port_config(hwsku, platform, port_config_file) + + for child in root: + if child.tag == str(QName(ns, "DpgDec")): + (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls) = parse_dpg(child, hostname) + elif child.tag == str(QName(ns, "CpgDec")): + (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) + elif child.tag == str(QName(ns, "PngDec")): + (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) + elif child.tag == str(QName(ns, "UngDec")): + (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) + elif child.tag == str(QName(ns, "MetadataDeclaration")): + (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) + elif child.tag == str(QName(ns, "DeviceInfos")): + port_speeds = parse_deviceinfo(child, hwsku) + + results = {} + results['DEVICE_METADATA'] = {'localhost': { + 'bgp_asn': bgp_asn, + 'deployment_id': deployment_id, + 'hostname': hostname, + 'hwsku': hwsku, + 'type': devices[hostname]['type'] + }} + results['BGP_NEIGHBOR'] = bgp_sessions + results['BGP_PEER_RANGE'] = bgp_peers_with_range + if mgmt_routes: + # TODO: differentiate v4 and v6 + mgmt_intf.itervalues().next()['forced_mgmt_routes'] = mgmt_routes + results['MGMT_INTERFACE'] = mgmt_intf + results['LOOPBACK_INTERFACE'] = lo_intfs + + phyport_intfs = {} + vlan_intfs = {} + pc_intfs = {} + for intf in intfs: + if intf[0][0:4] == 'Vlan': + vlan_intfs[intf] = {} + elif intf[0][0:11] == 'PortChannel': + pc_intfs[intf] = {} + else: + phyport_intfs[intf] = {} + + results['INTERFACE'] = phyport_intfs + results['VLAN_INTERFACE'] = vlan_intfs + results['PORTCHANNEL_INTERFACE'] = pc_intfs + + for port_name in port_speeds: + ports.setdefault(port_name, {})['speed'] = port_speeds[port_name] + results['PORT'] = ports + results['PORTCHANNEL'] = pcs + results['VLAN'] = vlans + + results['DEVICE_NEIGHBOR'] = neighbors + results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) + results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) + results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) + + results['ACL_TABLE'] = acls + mirror_sessions = {} + if erspan_dst: + lo_addr = '0.0.0.0' + for lo in lo_intfs: + lo_network = ipaddress.IPNetwork(lo[1]) + if lo_network.version == 4: + lo_addr = str(lo_network.ip) + break + count = 0 + for dst in erspan_dst: + mirror_sessions['everflow{}'.format(count)] = {"dst_ip": dst, "src_ip": lo_addr} + count += 1 + results['MIRROR_SESSION'] = mirror_sessions + + return results + + +def parse_device_desc_xml(filename): + root = ET.parse(filename).getroot() + (lo_prefix, mgmt_prefix, hostname, hwsku, d_type) = parse_device(root) + + results = {} + results['DEVICE_METADATA'] = {'localhost': { + 'hostname': hostname, + 'hwsku': hwsku, + }} + + results['LOOPBACK_INTERFACE'] = {('lo', lo_prefix): {}} + + mgmt_intf = {} + mgmtipn = ipaddress.IPNetwork(mgmt_prefix) + gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) + results['MGMT_INTERFACE'] = {('eth0', mgmt_prefix): {'gwaddr': gwaddr}} + + return results + + +port_alias_map = {} + + +def print_parse_xml(filename): + results = parse_xml(filename) + print(json.dumps(results, indent=3, cls=minigraph_encoder)) diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index 070b3100ea5a..5303557c4fb4 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -22,6 +22,7 @@ import yaml import jinja2 import netaddr import json +from functools import partial from minigraph import minigraph_encoder from minigraph import parse_xml from minigraph import parse_device_desc_xml @@ -32,11 +33,11 @@ from swsssdk import ConfigDBConnector def is_ipv4(value): if not value: return False - if isinstance(value, netaddr.IPAddress): + if isinstance(value, netaddr.IPNetwork): addr = value else: try: - addr = netaddr.IPAddress(str(value)) + addr = netaddr.IPNetwork(str(value)) except: return False return addr.version == 4 @@ -44,15 +45,25 @@ def is_ipv4(value): def is_ipv6(value): if not value: return False - if isinstance(value, netaddr.IPAddress): + if isinstance(value, netaddr.IPNetwork): addr = value else: try: - addr = netaddr.IPAddress(str(value)) + addr = netaddr.IPNetwork(str(value)) except: return False return addr.version == 6 +def prefix_attr(attr, value): + if not value: + return None + else: + try: + prefix = netaddr.IPNetwork(str(value)) + except: + return None + return str(getattr(prefix, attr)) + def unique_name(l): name_list = [] new_list = [] @@ -79,10 +90,31 @@ TODO(taoyl): Current version of config db only supports BGP admin states. def output_to_db(output_data): db_data = {} for table_name in output_data: - if table_name == 'BGP_NEIGHBOR' or table_name == 'BGP_PEER_RANGE' or table_name == 'DEVICE_METADATA': + if table_name[0].isupper(): db_data[table_name] = output_data[table_name] return db_data + @staticmethod + def to_serialized(data): + for table in data: + if type(data[table]) is dict: + for key in data[table].keys(): + new_key = ConfigDBConnector.serialize_key(key) + if new_key != key: + data[table][new_key] = data[table].pop(key) + return data + + @staticmethod + def to_deserialized(data): + for table in data: + if type(data[table]) is dict: + for key in data[table].keys(): + new_key = ConfigDBConnector.deserialize_key(key) + if new_key != key: + data[table][new_key] = data[table].pop(key) + return data + + def deep_update(dst, src): for key, value in src.iteritems(): if isinstance(value, dict): @@ -138,11 +170,11 @@ def main(): for yaml_file in args.yaml: with open(yaml_file, 'r') as stream: additional_data = yaml.load(stream) - deep_update(data, additional_data) + deep_update(data, FormatConverter.to_deserialized(additional_data)) for json_file in args.json: with open(json_file, 'r') as stream: - deep_update(data, json.load(stream)) + deep_update(data, FormatConverter.to_deserialized(json.load(stream))) if args.additional_data != None: deep_update(data, json.loads(args.additional_data)) @@ -158,6 +190,8 @@ def main(): env.filters['ipv4'] = is_ipv4 env.filters['ipv6'] = is_ipv6 env.filters['unique_name'] = unique_name + for attr in ['ip', 'network', 'prefixlen', 'netmask']: + env.filters[attr] = partial(prefix_attr, attr) template = env.get_template(template_file) print template.render(data) @@ -174,7 +208,7 @@ def main(): configdb.set_config(FormatConverter.output_to_db(data)) if args.print_data: - print json.dumps(data, indent=4, cls=minigraph_encoder) + print json.dumps(FormatConverter.to_serialized(data), indent=4, cls=minigraph_encoder) if __name__ == "__main__": diff --git a/src/sonic-config-engine/tests/sample_output/interfaces b/src/sonic-config-engine/tests/sample_output/interfaces index 5c57bf8fac85..ec3b6f740bc4 100644 --- a/src/sonic-config-engine/tests/sample_output/interfaces +++ b/src/sonic-config-engine/tests/sample_output/interfaces @@ -22,155 +22,165 @@ iface eth0 inet static netmask 255.255.255.0 ########## management network policy routing rules # management port up rules - up ip route add default via 10.0.0.1 dev eth0 table default - up ip rule add from 10.0.0.100/32 table default + up ip -4 route add default via 10.0.0.1 dev eth0 table default + up ip -4 rule add from 10.0.0.100/32 table default # management port down rules - down ip route delete default via 10.0.0.1 dev eth0 table default - down ip rule delete from 10.0.0.100/32 table default + down ip -4 route delete default via 10.0.0.1 dev eth0 table default + down ip -4 rule delete from 10.0.0.100/32 table default +iface eth0 inet6 static + address 2603:10e2:0:2902::8 + netmask 64 + ########## management network policy routing rules + # management port up rules + up ip -6 route add default via 2603:10e2:0:2902::1 dev eth0 table default + up ip -6 rule add from 2603:10e2:0:2902::8/128 table default + # management port down rules + down ip -6 route delete default via 2603:10e2:0:2902::1 dev eth0 table default + down ip -6 rule delete from 2603:10e2:0:2902::8/128 table default # # The switch front panel interfaces # "|| true" is added to suppress the error when interface is already a member of VLAN allow-hotplug fortyGigE0/4 iface fortyGigE0/4 inet manual - pre-up ifconfig fortyGigE0/4 up mtu 9216 + pre-up ifconfig fortyGigE0/4 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/4 || true post-down ifconfig fortyGigE0/4 down # allow-hotplug fortyGigE0/8 iface fortyGigE0/8 inet manual - pre-up ifconfig fortyGigE0/8 up mtu 9216 + pre-up ifconfig fortyGigE0/8 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/8 || true post-down ifconfig fortyGigE0/8 down # allow-hotplug fortyGigE0/12 iface fortyGigE0/12 inet manual - pre-up ifconfig fortyGigE0/12 up mtu 9216 + pre-up ifconfig fortyGigE0/12 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/12 || true post-down ifconfig fortyGigE0/12 down # allow-hotplug fortyGigE0/16 iface fortyGigE0/16 inet manual - pre-up ifconfig fortyGigE0/16 up mtu 9216 + pre-up ifconfig fortyGigE0/16 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/16 || true post-down ifconfig fortyGigE0/16 down # allow-hotplug fortyGigE0/20 iface fortyGigE0/20 inet manual - pre-up ifconfig fortyGigE0/20 up mtu 9216 + pre-up ifconfig fortyGigE0/20 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/20 || true post-down ifconfig fortyGigE0/20 down # allow-hotplug fortyGigE0/24 iface fortyGigE0/24 inet manual - pre-up ifconfig fortyGigE0/24 up mtu 9216 + pre-up ifconfig fortyGigE0/24 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/24 || true post-down ifconfig fortyGigE0/24 down # allow-hotplug fortyGigE0/28 iface fortyGigE0/28 inet manual - pre-up ifconfig fortyGigE0/28 up mtu 9216 + pre-up ifconfig fortyGigE0/28 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/28 || true post-down ifconfig fortyGigE0/28 down # allow-hotplug fortyGigE0/32 iface fortyGigE0/32 inet manual - pre-up ifconfig fortyGigE0/32 up mtu 9216 + pre-up ifconfig fortyGigE0/32 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/32 || true post-down ifconfig fortyGigE0/32 down # allow-hotplug fortyGigE0/36 iface fortyGigE0/36 inet manual - pre-up ifconfig fortyGigE0/36 up mtu 9216 + pre-up ifconfig fortyGigE0/36 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/36 || true post-down ifconfig fortyGigE0/36 down # allow-hotplug fortyGigE0/40 iface fortyGigE0/40 inet manual - pre-up ifconfig fortyGigE0/40 up mtu 9216 + pre-up ifconfig fortyGigE0/40 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/40 || true post-down ifconfig fortyGigE0/40 down # allow-hotplug fortyGigE0/44 iface fortyGigE0/44 inet manual - pre-up ifconfig fortyGigE0/44 up mtu 9216 + pre-up ifconfig fortyGigE0/44 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/44 || true post-down ifconfig fortyGigE0/44 down # allow-hotplug fortyGigE0/48 iface fortyGigE0/48 inet manual - pre-up ifconfig fortyGigE0/48 up mtu 9216 + pre-up ifconfig fortyGigE0/48 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/48 || true post-down ifconfig fortyGigE0/48 down # allow-hotplug fortyGigE0/52 iface fortyGigE0/52 inet manual - pre-up ifconfig fortyGigE0/52 up mtu 9216 + pre-up ifconfig fortyGigE0/52 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/52 || true post-down ifconfig fortyGigE0/52 down # allow-hotplug fortyGigE0/56 iface fortyGigE0/56 inet manual - pre-up ifconfig fortyGigE0/56 up mtu 9216 + pre-up ifconfig fortyGigE0/56 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/56 || true post-down ifconfig fortyGigE0/56 down # allow-hotplug fortyGigE0/60 iface fortyGigE0/60 inet manual - pre-up ifconfig fortyGigE0/60 up mtu 9216 + pre-up ifconfig fortyGigE0/60 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/60 || true post-down ifconfig fortyGigE0/60 down # allow-hotplug fortyGigE0/64 iface fortyGigE0/64 inet manual - pre-up ifconfig fortyGigE0/64 up mtu 9216 + pre-up ifconfig fortyGigE0/64 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/64 || true post-down ifconfig fortyGigE0/64 down # allow-hotplug fortyGigE0/68 iface fortyGigE0/68 inet manual - pre-up ifconfig fortyGigE0/68 up mtu 9216 + pre-up ifconfig fortyGigE0/68 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/68 || true post-down ifconfig fortyGigE0/68 down # allow-hotplug fortyGigE0/72 iface fortyGigE0/72 inet manual - pre-up ifconfig fortyGigE0/72 up mtu 9216 + pre-up ifconfig fortyGigE0/72 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/72 || true post-down ifconfig fortyGigE0/72 down # allow-hotplug fortyGigE0/76 iface fortyGigE0/76 inet manual - pre-up ifconfig fortyGigE0/76 up mtu 9216 + pre-up ifconfig fortyGigE0/76 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/76 || true post-down ifconfig fortyGigE0/76 down # allow-hotplug fortyGigE0/80 iface fortyGigE0/80 inet manual - pre-up ifconfig fortyGigE0/80 up mtu 9216 + pre-up ifconfig fortyGigE0/80 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/80 || true post-down ifconfig fortyGigE0/80 down # allow-hotplug fortyGigE0/84 iface fortyGigE0/84 inet manual - pre-up ifconfig fortyGigE0/84 up mtu 9216 + pre-up ifconfig fortyGigE0/84 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/84 || true post-down ifconfig fortyGigE0/84 down # allow-hotplug fortyGigE0/88 iface fortyGigE0/88 inet manual - pre-up ifconfig fortyGigE0/88 up mtu 9216 + pre-up ifconfig fortyGigE0/88 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/88 || true post-down ifconfig fortyGigE0/88 down # allow-hotplug fortyGigE0/92 iface fortyGigE0/92 inet manual - pre-up ifconfig fortyGigE0/92 up mtu 9216 + pre-up ifconfig fortyGigE0/92 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/92 || true post-down ifconfig fortyGigE0/92 down # allow-hotplug fortyGigE0/96 iface fortyGigE0/96 inet manual - pre-up ifconfig fortyGigE0/96 up mtu 9216 + pre-up ifconfig fortyGigE0/96 up mtu 9100 post-up brctl addif Vlan1000 fortyGigE0/96 || true post-down ifconfig fortyGigE0/96 down # @@ -210,49 +220,49 @@ iface Vlan1000 inet static # Portchannel interfaces allow-hotplug PortChannel01 iface PortChannel01 inet static - mtu 9216 + mtu 9100 address 10.0.0.56 netmask 255.255.255.254 # allow-hotplug PortChannel01 iface PortChannel01 inet6 static - mtu 9216 + mtu 9100 address fc00::71 netmask 126 # allow-hotplug PortChannel02 iface PortChannel02 inet static - mtu 9216 + mtu 9100 address 10.0.0.58 netmask 255.255.255.254 # allow-hotplug PortChannel02 iface PortChannel02 inet6 static - mtu 9216 + mtu 9100 address fc00::75 netmask 126 # allow-hotplug PortChannel03 iface PortChannel03 inet static - mtu 9216 + mtu 9100 address 10.0.0.60 netmask 255.255.255.254 # allow-hotplug PortChannel03 iface PortChannel03 inet6 static - mtu 9216 + mtu 9100 address fc00::79 netmask 126 # allow-hotplug PortChannel04 iface PortChannel04 inet static - mtu 9216 + mtu 9100 address 10.0.0.62 netmask 255.255.255.254 # allow-hotplug PortChannel04 iface PortChannel04 inet6 static - mtu 9216 + mtu 9100 address fc00::7d netmask 126 # diff --git a/src/sonic-config-engine/tests/sample_output/ipinip.json b/src/sonic-config-engine/tests/sample_output/ipinip.json index 00862a379281..5a7ac1b6063b 100644 --- a/src/sonic-config-engine/tests/sample_output/ipinip.json +++ b/src/sonic-config-engine/tests/sample_output/ipinip.json @@ -11,4 +11,3 @@ "OP": "SET" } ] - diff --git a/src/sonic-config-engine/tests/sample_output/lldpd.conf b/src/sonic-config-engine/tests/sample_output/lldpd.conf new file mode 100644 index 000000000000..0328385cf307 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/lldpd.conf @@ -0,0 +1,5 @@ +configure ports Ethernet116 lldp portidsubtype local fortyGigE0/116 description ARISTA02T1:Ethernet1/1 +configure ports Ethernet124 lldp portidsubtype local fortyGigE0/124 description ARISTA04T1:Ethernet1/1 +configure ports Ethernet112 lldp portidsubtype local fortyGigE0/112 description ARISTA01T1:Ethernet1/1 +configure ports Ethernet120 lldp portidsubtype local fortyGigE0/120 description ARISTA03T1:Ethernet1/1 + diff --git a/src/sonic-config-engine/tests/sample_output/mirror.json b/src/sonic-config-engine/tests/sample_output/mirror.json index 54065700a282..225235067e23 100644 --- a/src/sonic-config-engine/tests/sample_output/mirror.json +++ b/src/sonic-config-engine/tests/sample_output/mirror.json @@ -1,6 +1,6 @@ [ { - "MIRROR_SESSION_TABLE:everflow": { + "MIRROR_SESSION_TABLE:everflow0": { "src_ip": "10.1.0.32", "dst_ip": "2.2.2.2", "gre_type": "0x88be", diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 153b0bb14f36..d78b19d88ba7 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -31,17 +31,17 @@ def test_dummy_run(self): self.assertEqual(output, '') def test_device_desc(self): - argument = '-v minigraph_hwsku -M "' + self.sample_device_desc + '"' + argument = '-v "DEVICE_METADATA[\'localhost\'][\'hwsku\']" -M "' + self.sample_device_desc + '"' output = self.run_script(argument) self.assertEqual(output.strip(), 'ACS-MSN2700') def test_device_desc_mgmt_ip(self): - argument = '-v "minigraph_mgmt_interface[\'addr\']" -M "' + self.sample_device_desc + '"' + argument = '-v "MGMT_INTERFACE.keys()[0]" -M "' + self.sample_device_desc + '"' output = self.run_script(argument) - self.assertEqual(output.strip(), '10.0.1.5') + self.assertEqual(output.strip(), "('eth0', '10.0.1.5/28')") def test_minigraph_sku(self): - argument = '-v minigraph_hwsku -m "' + self.sample_graph + '"' + argument = '-v "DEVICE_METADATA[\'localhost\'][\'hwsku\']" -m "' + self.sample_graph + '"' output = self.run_script(argument) self.assertEqual(output.strip(), 'Force10-Z9100') @@ -51,7 +51,7 @@ def test_print_data(self): self.assertTrue(len(output.strip()) > 0) def test_jinja_expression(self): - argument = '-m "' + self.sample_graph + '" -v "minigraph_devices[minigraph_hostname][\'type\']"' + argument = '-m "' + self.sample_graph + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' output = self.run_script(argument) self.assertEqual(output.strip(), 'LeafRouter') @@ -71,44 +71,49 @@ def test_render_template(self): self.assertEqual(output.strip(), 'value1\nvalue2') def test_minigraph_acl(self): - argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v minigraph_acls' + argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v ACL_TABLE' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'dataacl': {'IsMirror': False, 'AttachTo': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}}") + self.assertEqual(output.strip(), "{'dataacl': {'type': 'L3', 'policy_desc': 'dataacl', 'ports': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}}") def test_minigraph_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v minigraph_interfaces' + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v \'INTERFACE.keys()\'' output = self.run_script(argument) - self.assertEqual(output.strip(), "[{'subnet': IPv4Network('10.0.0.58/31'), 'peer_addr': IPv4Address('10.0.0.59'), 'addr': IPv4Address('10.0.0.58'), 'mask': IPv4Address('255.255.255.254'), 'attachto': 'Ethernet0', 'prefixlen': 31}, {'subnet': IPv6Network('fc00::74/126'), 'peer_addr': IPv6Address('fc00::76'), 'addr': IPv6Address('fc00::75'), 'mask': '126', 'attachto': 'Ethernet0', 'prefixlen': 126}]") + self.assertEqual(output.strip(), "[('Ethernet0', '10.0.0.58/31'), ('Ethernet0', 'FC00::75/126')]") def test_minigraph_vlans(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v minigraph_vlans' + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'Vlan1000': {'name': 'Vlan1000', 'members': ['Ethernet8'], 'vlanid': '1000'}}") + self.assertEqual(output.strip(), "{'Vlan1000': {'members': ['Ethernet8'], 'vlanid': '1000'}}") def test_minigraph_vlan_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v minigraph_vlan_interfaces' + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VLAN_INTERFACE.keys()"' output = self.run_script(argument) - self.assertEqual(output.strip(), "[{'prefixlen': 27, 'subnet': IPv4Network('192.168.0.0/27'), 'mask': IPv4Address('255.255.255.224'), 'addr': IPv4Address('192.168.0.1'), 'attachto': 'Vlan1000'}]") + self.assertEqual(output.strip(), "[('Vlan1000', '192.168.0.1/27')]") def test_minigraph_portchannels(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v minigraph_portchannels' + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v PORTCHANNEL' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'PortChannel01': {'name': 'PortChannel01', 'members': ['Ethernet4']}}") + self.assertEqual(output.strip(), "{'PortChannel01': {'members': ['Ethernet4']}}") def test_minigraph_portchannels_more_member(self): - argument = '-m "' + self.sample_graph_pc_test + '" -p "' + self.port_config + '" -v minigraph_portchannels' + argument = '-m "' + self.sample_graph_pc_test + '" -p "' + self.port_config + '" -v PORTCHANNEL' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'PortChannel01': {'name': 'PortChannel01', 'members': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}}") + self.assertEqual(output.strip(), "{'PortChannel01': {'members': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}}") def test_minigraph_portchannel_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v minigraph_portchannel_interfaces' + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORTCHANNEL_INTERFACE.keys()"' output = self.run_script(argument) - self.assertEqual(output.strip(), "[{'subnet': IPv4Network('10.0.0.56/31'), 'peer_addr': IPv4Address('10.0.0.57'), 'addr': IPv4Address('10.0.0.56'), 'mask': IPv4Address('255.255.255.254'), 'attachto': 'PortChannel01', 'prefixlen': 31}, {'subnet': IPv6Network('fc00::70/126'), 'peer_addr': IPv6Address('fc00::72'), 'addr': IPv6Address('fc00::71'), 'mask': '126', 'attachto': 'PortChannel01', 'prefixlen': 126}]") + self.assertEqual(output.strip(), "[('PortChannel01', 'FC00::71/126'), ('PortChannel01', '10.0.0.56/31')]") def test_minigraph_neighbors(self): - argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v minigraph_neighbors' + argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v "DEVICE_NEIGHBOR[\'Ethernet124\']"' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'Ethernet116': {'name': 'ARISTA02T1', 'port': 'Ethernet1/1'}, 'Ethernet124': {'name': 'ARISTA04T1', 'port': 'Ethernet1/1'}, 'Ethernet112': {'name': 'ARISTA01T1', 'port': 'Ethernet1/1'}, 'Ethernet120': {'name': 'ARISTA03T1', 'port': 'Ethernet1/1'}}") + self.assertEqual(output.strip(), "{'name': 'ARISTA04T1', 'port': 'Ethernet1/1'}") + + def test_minigraph_bgp(self): + argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v "BGP_NEIGHBOR[\'10.0.0.59\']"' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'rrclient': '0', 'local_addr': '10.0.0.58', 'asn': '64600', 'name': 'ARISTA02T1'}") def test_minigraph_peers_with_range(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v BGP_PEER_RANGE.values\(\)' @@ -116,11 +121,11 @@ def test_minigraph_peers_with_range(self): self.assertEqual(output.strip(), "[{'name': 'BGPSLBPassive', 'ip_range': ['10.10.10.10/26', '100.100.100.100/26']}]") def test_minigraph_deployment_id(self): - argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v deployment_id' + argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v "DEVICE_METADATA[\'localhost\'][\'deployment_id\']"' output = self.run_script(argument) self.assertEqual(output.strip(), "1") def test_minigraph_ethernet_interfaces(self): - argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v ethernet_interfaces' + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORT[\'Ethernet8\']"' output = self.run_script(argument) - self.assertEqual(output.strip(), "[{'speed': '10000', 'name': 'fortyGigE0/0'}, {'speed': '25000', 'name': 'fortyGigE0/4'}, {'speed': '40000', 'name': 'fortyGigE0/8'}, {'speed': '1000000', 'name': 'fortyGigE0/12'}]") + self.assertEqual(output.strip(), "{'alias': 'fortyGigE0/8', 'speed': '40000'}") diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 0f9264eb1d3b..4bdc1b41f5b4 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -26,10 +26,16 @@ def test_interfaces(self): def test_alias_map(self): alias_map_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-snmp-sv2', 'alias_map.j2') - argument = '-m "' + self.t0_minigraph + '" -p "' + self.t0_port_config + '" -t "' + alias_map_template + '"' + argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + alias_map_template output = self.run_script(argument) data = json.loads(output) self.assertEqual(data["Ethernet4"], "fortyGigE0/4") + + def test_lldp(self): + lldpd_conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-lldp-sv2', 'lldpd.conf.j2') + argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + lldpd_conf_template + ' > ' + self.output_file + self.run_script(argument) + self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'lldpd.conf'), self.output_file)) def test_teamd(self): @@ -40,7 +46,7 @@ def test_render_teamd(self, pc, minigraph, sample_output): self.assertTrue(filecmp.cmp(sample_output, self.output_file)) # Test T0 minigraph - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -v "minigraph_portchannels.keys() | join(\' \')"' + argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -v "PORTCHANNEL.keys() | join(\' \') if PORTCHANNEL"' output = self.run_script(argument) # Mock the output via config.sh in docker-teamd pc_list = output.split() @@ -51,7 +57,7 @@ def test_render_teamd(self, pc, minigraph, sample_output): test_render_teamd(self, pc_name, self.t0_minigraph, sample_output) # Test port channel test minigraph - argument = '-m ' + self.pc_minigraph + ' -p ' + self.t0_port_config + ' -v "minigraph_portchannels.keys() | join(\' \')"' + argument = '-m ' + self.pc_minigraph + ' -p ' + self.t0_port_config + ' -v "PORTCHANNEL.keys() | join(\' \') if PORTCHANNEL"' output = self.run_script(argument) # Mock the output via config.sh in docker-teamd pc_list = output.split() diff --git a/src/sonic-config-engine/translate_acl b/src/sonic-config-engine/translate_acl index 5525eff96774..b8138cf36b18 100755 --- a/src/sonic-config-engine/translate_acl +++ b/src/sonic-config-engine/translate_acl @@ -110,13 +110,14 @@ def generate_rule_json(table_name, rule, max_priority, mirror): rule_props["TCP_FLAGS"] = '0x{:02x}/0x{:02x}'.format(tcp_flags, tcp_flags) return rule_data -def generate_table_json(aclset, aclname, ports, mirror, max_priority, output_path='.'): +def generate_table_json(aclset, aclname, ports, t_type, max_priority, output_path='.'): table_name = aclname.replace(" ", "_").replace("-", "_") #table_name = generate_random_table_name() + mirror = (t_type == 'mirror') table_props = {} table_props["policy_desc"] = table_name - table_props["type"] = "mirror" if mirror else "L3" + table_props["type"] = t_type table_props["ports"] = ports table_data = [{}] @@ -138,7 +139,7 @@ def translate_acl_fixed_port(filename, output_path, port, max_priority): yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl") for aclsetname in yang_acl.acl.acl_sets.acl_set: aclset = yang_acl.acl.acl_sets.acl_set[aclsetname] - generate_table_json(aclset, aclsetname, port, max_priority, output_path) + generate_table_json(aclset, aclsetname, port, 'l3', max_priority, output_path) return def translate_acl(filename, output_path, mini_acl, max_priority): @@ -146,10 +147,10 @@ def translate_acl(filename, output_path, mini_acl, max_priority): for aclsetname in yang_acl.acl.acl_sets.acl_set: tablename = aclsetname.replace(" ", "_").replace("-", "_") if mini_acl.has_key(tablename): - is_mirror = mini_acl[tablename]['IsMirror'] - ports = ','.join(mini_acl[tablename]['AttachTo']) + t_type = mini_acl[tablename]['type'] + ports = ','.join(mini_acl[tablename]['ports']) aclset = yang_acl.acl.acl_sets.acl_set[aclsetname] - generate_table_json(aclset, aclsetname, ports, is_mirror, max_priority, output_path) + generate_table_json(aclset, aclsetname, ports, t_type, max_priority, output_path) return def main(): @@ -166,8 +167,8 @@ def main(): translate_acl_fixed_port(args.input, args.output_path, args.port, args.max_priority) elif args.minigraph: mini_data = parse_xml(args.minigraph, port_config_file=args.port_config) - if mini_data['minigraph_acls']: - translate_acl(args.input, args.output_path, mini_data['minigraph_acls'], args.max_priority) + if mini_data['ACL_TABLE']: + translate_acl(args.input, args.output_path, mini_data['ACL_TABLE'], args.max_priority) if __name__ == "__main__": main() diff --git a/src/sonic-py-swsssdk b/src/sonic-py-swsssdk index 9b54b80f1783..96b4928e790b 160000 --- a/src/sonic-py-swsssdk +++ b/src/sonic-py-swsssdk @@ -1 +1 @@ -Subproject commit 9b54b80f1783808c5ae2a30e189f24a7404a8c95 +Subproject commit 96b4928e790bbce7c959f0b5cbb0510e5954afb1 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 3f4afbbd9d7e..e4d24276cb6f 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 3f4afbbd9d7ed2f077922e0cb0d59df743e34a9a +Subproject commit e4d24276cb6fc7122f756c637f30ddea27487c70 diff --git a/src/sonic-snmpagent b/src/sonic-snmpagent index 186a4f65fbdd..bc4becf97ea6 160000 --- a/src/sonic-snmpagent +++ b/src/sonic-snmpagent @@ -1 +1 @@ -Subproject commit 186a4f65fbdde9d277d0aeef562e1fc196266fdb +Subproject commit bc4becf97ea69c15315414e8c7cba44067af2461 diff --git a/src/sonic-swss b/src/sonic-swss index eaccf67cabd2..bcdea1323e70 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit eaccf67cabd22df0ff7d0117fe55f4261bc961d9 +Subproject commit bcdea1323e70c73fa0a85c6df55eaed886bded81 diff --git a/src/sonic-swss-common b/src/sonic-swss-common index 4f917f2cc345..f6ff19bee131 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit 4f917f2cc345c54d1bf9d9f01d96e4c01071ac9a +Subproject commit f6ff19bee131048f2274a21ea1064a8493a7fd8b diff --git a/src/sonic-utilities b/src/sonic-utilities index d1ded16b06b4..b27d4f9e976f 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit d1ded16b06b493e2420d1013aee97afbdc8160d9 +Subproject commit b27d4f9e976f944f50d81e2354ba826194971774 From 745b96d2c0aebed5c2e083efdfbb174bcc7929bd Mon Sep 17 00:00:00 2001 From: nikos-li <31227248+nikos-li@users.noreply.github.com> Date: Wed, 4 Oct 2017 01:25:15 -0700 Subject: [PATCH 09/17] Remove stale files from sync --- dockers/docker-fpm-frr/bgpd.conf.j2~ | 91 ----- src/sonic-config-engine/minigraph.py~ | 472 -------------------------- 2 files changed, 563 deletions(-) delete mode 100644 dockers/docker-fpm-frr/bgpd.conf.j2~ delete mode 100644 src/sonic-config-engine/minigraph.py~ diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2~ b/dockers/docker-fpm-frr/bgpd.conf.j2~ deleted file mode 100644 index 08dd93c8dabe..000000000000 --- a/dockers/docker-fpm-frr/bgpd.conf.j2~ +++ /dev/null @@ -1,91 +0,0 @@ -! -{% 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 %} -! -{% block system_init %} -hostname {{ DEVICE_METADATA['localhost']['hostname'] }} -password zebra -log syslog informational -log facility local4 -! enable password {# {{ en_passwd }} TODO: param needed #} -{% endblock system_init %} -! -{% block bgp_init %} -! -! bgp multiple-instance -! -router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} - bgp log-neighbor-changes - bgp bestpath as-path multipath-relax - no bgp default ipv4-unicast -{# TODO: use lo[0] for backward compatibility, will revisit the case with multiple lo interfaces #} - bgp router-id {{ LOOPBACK_INTERFACE.keys()[0][1] }} -{# advertise loopback #} -{% for (name, prefix) in LOOPBACK_INTERFACE %} -{% if prefix | ipv4 %} - network {{ prefix | ip }}/32 -{% elif prefix | ipv6 %} - address-family ipv6 - network {{ prefix | ip }}/128 - exit-address-family -{% endif %} -{% endfor %} -{% endblock bgp_init %} -{% block vlan_advertisement %} -{% for (name, prefix) in VLAN_INTERFACE %} -{% if prefix | ipv4 %} - network {{ prefix }} -{% elif prefix | ipv6 %} - address-family ipv6 - network {{ prefix }} - exit-address-family -{% endif %} -{% endfor %} -{% endblock vlan_advertisement %} -{% block bgp_sessions %} -{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %} -{% if bgp_session['asn'] | int != 0 %} - neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} - neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} -{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} - neighbor {{ neighbor_addr }} allowas-in 1 -{% endif %} -{% if neighbor_addr | ipv4 %} - address-family ipv4 - neighbor {{ neighbor_addr }} activate -<<<<<<< HEAD -{% if bgp_session['rrclient'] != 0 %} -======= -{% if bgp_session['rrclient'] | int != 0 %} ->>>>>>> 554114cfaa4b55a85e3a74b169bfcf1a394accdd - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} - maximum-paths 64 - exit-address-family -{% endif %} -{% if neighbor_addr | ipv6 %} - address-family ipv6 - neighbor {{ neighbor_addr }} activate -<<<<<<< HEAD -{% if bgp_session['rrclient'] != 0 %} -======= -{% if bgp_session['rrclient'] | int != 0 %} ->>>>>>> 554114cfaa4b55a85e3a74b169bfcf1a394accdd - neighbor {{ neighbor_addr }} route-reflector-client -{% endif %} - maximum-paths 64 - exit-address-family -{% endif %} -{% endif %} -{% endfor %} -{% endblock bgp_sessions %} -! -maximum-paths 64 -! -route-map ISOLATE permit 10 -set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} -! diff --git a/src/sonic-config-engine/minigraph.py~ b/src/sonic-config-engine/minigraph.py~ deleted file mode 100644 index f97877c1cd5e..000000000000 --- a/src/sonic-config-engine/minigraph.py~ +++ /dev/null @@ -1,472 +0,0 @@ -#!/usr/bin/env python -import calendar -import os -import sys -import socket -import struct -import json -import copy -import ipaddr as ipaddress -from collections import defaultdict - -from lxml import etree as ET -from lxml.etree import QName - -DOCUMENTATION = ''' ---- -module: minigraph_facts -version_added: "1.9" -author: Guohan Lu (gulv@microsoft.com) -short_description: Retrive minigraph facts for a device. -description: - - Retrieve minigraph facts for a device, the facts will be - inserted to the ansible_facts key. -options: - host: - description: - - Set to target snmp server (normally {{inventory_hostname}}) - required: true -''' - -EXAMPLES = ''' -# Gather minigraph facts -- name: Gathering minigraph facts about the device - minigraph_facts: host={{ hostname }} -''' - -ns = "Microsoft.Search.Autopilot.Evolution" -ns1 = "http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" -ns2 = "Microsoft.Search.Autopilot.NetMux" -ns3 = "http://www.w3.org/2001/XMLSchema-instance" - - -class minigraph_encoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, ( - ipaddress.IPv4Network, ipaddress.IPv6Network, - ipaddress.IPv4Address, ipaddress.IPv6Address - )): - return str(obj) - return json.JSONEncoder.default(self, obj) - -def parse_device(device): - lo_prefix = None - mgmt_prefix = None - d_type = None # don't shadow type() - hwsku = None - name = None - if str(QName(ns3, "type")) in device.attrib: - d_type = device.attrib[str(QName(ns3, "type"))] - - for node in device: - if node.tag == str(QName(ns, "Address")): - lo_prefix = node.find(str(QName(ns2, "IPPrefix"))).text - elif node.tag == str(QName(ns, "ManagementAddress")): - mgmt_prefix = node.find(str(QName(ns2, "IPPrefix"))).text - elif node.tag == str(QName(ns, "Hostname")): - name = node.text - elif node.tag == str(QName(ns, "HwSku")): - hwsku = node.text - return (lo_prefix, mgmt_prefix, name, hwsku, d_type) - -def parse_png(png, hname): - neighbors = {} - devices = {} - console_dev = '' - console_port = '' - mgmt_dev = '' - mgmt_port = '' - for child in png: - if child.tag == str(QName(ns, "DeviceInterfaceLinks")): - for link in child.findall(str(QName(ns, "DeviceLinkBase"))): - linktype = link.find(str(QName(ns, "ElementType"))).text - if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": - continue - - enddevice = link.find(str(QName(ns, "EndDevice"))).text - endport = link.find(str(QName(ns, "EndPort"))).text - startdevice = link.find(str(QName(ns, "StartDevice"))).text - startport = link.find(str(QName(ns, "StartPort"))).text - - if enddevice == hname: - if port_alias_map.has_key(endport): - endport = port_alias_map[endport] - neighbors[endport] = {'name': startdevice, 'port': startport} - else: - if port_alias_map.has_key(startport): - startport = port_alias_map[startport] - neighbors[startport] = {'name': enddevice, 'port': endport} - - if child.tag == str(QName(ns, "Devices")): - for device in child.findall(str(QName(ns, "Device"))): - (lo_prefix, mgmt_prefix, name, hwsku, d_type) = parse_device(device) - device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } - devices[name] = device_data - - if child.tag == str(QName(ns, "DeviceInterfaceLinks")): - for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): - if str(QName(ns3, "type")) in if_link.attrib: - link_type = if_link.attrib[str(QName(ns3, "type"))] - if link_type == 'DeviceSerialLink': - for node in if_link: - if node.tag == str(QName(ns, "EndPort")): - console_port = node.text.split()[-1] - elif node.tag == str(QName(ns, "EndDevice")): - console_dev = node.text - elif link_type == 'DeviceMgmtLink': - for node in if_link: - if node.tag == str(QName(ns, "EndPort")): - mgmt_port = node.text.split()[-1] - elif node.tag == str(QName(ns, "EndDevice")): - mgmt_dev = node.text - - return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) - - -def parse_dpg(dpg, hname): - for child in dpg: - hostname = child.find(str(QName(ns, "Hostname"))) - if hostname.text != hname: - continue - - ipintfs = child.find(str(QName(ns, "IPInterfaces"))) - intfs = {} - for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): - intfalias = ipintf.find(str(QName(ns, "AttachTo"))).text - intfname = port_alias_map.get(intfalias, intfalias) - ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text - intfs[(intfname, ipprefix)] = {} - - lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces"))) - lo_intfs = {} - for lointf in lointfs.findall(str(QName(ns1, "LoopbackIPInterface"))): - intfname = lointf.find(str(QName(ns, "AttachTo"))).text - ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text - lo_intfs[(intfname, ipprefix)] = {} - - mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) - mgmt_intf = {} - for mgmtintf in mgmtintfs.findall(str(QName(ns1, "ManagementIPInterface"))): - intfname = mgmtintf.find(str(QName(ns, "AttachTo"))).text - ipprefix = mgmtintf.find(str(QName(ns1, "PrefixStr"))).text - mgmtipn = ipaddress.IPNetwork(ipprefix) - gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) - mgmt_intf[(intfname, ipprefix)] = {'gwaddr': gwaddr} - - pcintfs = child.find(str(QName(ns, "PortChannelInterfaces"))) - pc_intfs = [] - pcs = {} - for pcintf in pcintfs.findall(str(QName(ns, "PortChannel"))): - pcintfname = pcintf.find(str(QName(ns, "Name"))).text - pcintfmbr = pcintf.find(str(QName(ns, "AttachTo"))).text - pcmbr_list = pcintfmbr.split(';') - for i, member in enumerate(pcmbr_list): - pcmbr_list[i] = port_alias_map.get(member, member) - pcs[pcintfname] = {'members': pcmbr_list} - - vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) - vlan_intfs = [] - vlans = {} - for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): - vintfname = vintf.find(str(QName(ns, "Name"))).text - vlanid = vintf.find(str(QName(ns, "VlanID"))).text - vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text - vmbr_list = vintfmbr.split(';') - for i, member in enumerate(vmbr_list): - vmbr_list[i] = port_alias_map.get(member, member) - vlan_attributes = {'members': vmbr_list, 'vlanid': vlanid} - sonic_vlan_name = "Vlan%s" % vlanid - vlans[sonic_vlan_name] = vlan_attributes - - aclintfs = child.find(str(QName(ns, "AclInterfaces"))) - acls = {} - for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): - aclname = aclintf.find(str(QName(ns, "InAcl"))).text.lower().replace(" ", "_").replace("-", "_") - aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') - acl_intfs = [] - is_mirror = False - for member in aclattach: - member = member.strip() - if pcs.has_key(member): - acl_intfs.extend(pcs[member]['members']) # For ACL attaching to port channels, we break them into port channel members - elif vlans.has_key(member): - print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported" - elif port_alias_map.has_key(member): - acl_intfs.append(port_alias_map[member]) - elif member.lower() == 'erspan': - is_mirror = True; - # Erspan session will be attached to all front panel ports - acl_intfs = port_alias_map.values() - break; - if acl_intfs: - acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'mirror' if is_mirror else 'L3'} - return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls - return None, None, None, None, None, None - - -def parse_cpg(cpg, hname): - bgp_sessions = {} - myasn = None - bgp_peers_with_range = {} - for child in cpg: - tag = child.tag - if tag == str(QName(ns, "PeeringSessions")): - for session in child.findall(str(QName(ns, "BGPSession"))): - start_router = session.find(str(QName(ns, "StartRouter"))).text - start_peer = session.find(str(QName(ns, "StartPeer"))).text - end_router = session.find(str(QName(ns, "EndRouter"))).text - end_peer = session.find(str(QName(ns, "EndPeer"))).text - if end_router == hname: - bgp_sessions[start_peer] = { - 'name': start_router, - 'local_addr': end_peer - } - else: - bgp_sessions[end_peer] = { - 'name': end_router, - 'local_addr': start_peer - } - elif child.tag == str(QName(ns, "Routers")): - for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): - asn = router.find(str(QName(ns1, "ASN"))).text - hostname = router.find(str(QName(ns1, "Hostname"))).text - if router.find(str(QName(ns1, "RRClient"))): - rrclient = '1' - else: - rrclient = '0' - if hostname == hname: - myasn = asn - peers = router.find(str(QName(ns1, "Peers"))) - for bgpPeer in peers.findall(str(QName(ns, "BGPPeer"))): - addr = bgpPeer.find(str(QName(ns, "Address"))).text - if bgpPeer.find(str(QName(ns1, "PeersRange"))) is not None: - name = bgpPeer.find(str(QName(ns1, "Name"))).text - ip_range = bgpPeer.find(str(QName(ns1, "PeersRange"))).text - ip_range_group = ip_range.split(';') if ip_range and ip_range != "" else [] - bgp_peers_with_range[name] = { - 'name': name, - 'ip_range': ip_range_group - } - else: - for peer in bgp_sessions: - bgp_session = bgp_sessions[peer] - if hostname == bgp_session['name']: - bgp_session['asn'] = int(asn) - bgp_session['rrclient'] = int(rrclient) - - return bgp_sessions, myasn, bgp_peers_with_range - - -def parse_meta(meta, hname): - syslog_servers = [] - dhcp_servers = [] - ntp_servers = [] - mgmt_routes = [] - erspan_dst = [] - deployment_id = None - device_metas = meta.find(str(QName(ns, "Devices"))) - for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))): - if device.find(str(QName(ns1, "Name"))).text == hname: - properties = device.find(str(QName(ns1, "Properties"))) - for device_property in properties.findall(str(QName(ns1, "DeviceProperty"))): - name = device_property.find(str(QName(ns1, "Name"))).text - value = device_property.find(str(QName(ns1, "Value"))).text - value_group = value.split(';') if value and value != "" else [] - if name == "DhcpResources": - dhcp_servers = value_group - elif name == "NtpResources": - ntp_servers = value_group - elif name == "SyslogResources": - syslog_servers = value_group - elif name == "ForcedMgmtRoutes": - mgmt_routes = value_group - elif name == "ErspanDestinationIpv4": - erspan_dst = value_group - elif name == "DeploymentId": - deployment_id = value - return syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id - -def parse_deviceinfo(meta, hwsku): - ethernet_interfaces = {} - for device_info in meta.findall(str(QName(ns, "DeviceInfo"))): - dev_sku = device_info.find(str(QName(ns, "HwSku"))).text - if dev_sku == hwsku: - interfaces = device_info.find(str(QName(ns, "EthernetInterfaces"))) - for interface in interfaces.findall(str(QName(ns1, "EthernetInterface"))): - alias = interface.find(str(QName(ns, "InterfaceName"))).text - speed = interface.find(str(QName(ns, "Speed"))).text - ethernet_interfaces[port_alias_map.get(alias, alias)] = speed - return ethernet_interfaces - -def parse_port_config(hwsku, platform=None, port_config_file=None): - port_config_candidates = [] - if port_config_file != None: - port_config_candidates.append(port_config_file) - port_config_candidates.append('/usr/share/sonic/hwsku/port_config.ini') - if platform != None: - port_config_candidates.append(os.path.join('/usr/share/sonic/device', platform, hwsku, 'port_config.ini')) - port_config_candidates.append(os.path.join('/usr/share/sonic/platform', hwsku, 'port_config.ini')) - port_config_candidates.append(os.path.join('/usr/share/sonic', hwsku, 'port_config.ini')) - port_config = None - for candidate in port_config_candidates: - if os.path.isfile(candidate): - port_config = candidate - break - if port_config == None: - return None - - ports = {} - with open(port_config) as data: - for line in data: - if line.startswith('#'): - continue - tokens = line.split() - if len(tokens) < 2: - continue - name = tokens[0].strip() - if len(tokens) == 2: - alias = name - else: - alias = tokens[2].strip() - ports[name] = {'alias': alias} - port_alias_map[alias] = name - return ports - -def parse_xml(filename, platform=None, port_config_file=None): - root = ET.parse(filename).getroot() - mini_graph_path = filename - - u_neighbors = None - u_devices = None - hwsku = None - bgp_sessions = None - bgp_asn = None - intfs = None - vlan_intfs = None - pc_intfs = None - vlans = None - pcs = None - mgmt_intf = None - lo_intf = None - neighbors = None - devices = None - hostname = None - port_speeds = {} - syslog_servers = [] - dhcp_servers = [] - ntp_servers = [] - mgmt_routes = [] - erspan_dst = [] - bgp_peers_with_range = None - deployment_id = None - - hwsku_qn = QName(ns, "HwSku") - hostname_qn = QName(ns, "Hostname") - for child in root: - if child.tag == str(hwsku_qn): - hwsku = child.text - if child.tag == str(hostname_qn): - hostname = child.text - - ports = parse_port_config(hwsku, platform, port_config_file) - - for child in root: - if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls) = parse_dpg(child, hostname) - elif child.tag == str(QName(ns, "CpgDec")): - (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) - elif child.tag == str(QName(ns, "PngDec")): - (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) - elif child.tag == str(QName(ns, "UngDec")): - (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) - elif child.tag == str(QName(ns, "MetadataDeclaration")): - (syslog_servers, dhcp_servers, ntp_servers, mgmt_routes, erspan_dst, deployment_id) = parse_meta(child, hostname) - elif child.tag == str(QName(ns, "DeviceInfos")): - port_speeds = parse_deviceinfo(child, hwsku) - - results = {} - results['DEVICE_METADATA'] = {'localhost': { - 'bgp_asn': bgp_asn, - 'deployment_id': deployment_id, - 'hostname': hostname, - 'hwsku': hwsku, - 'type': devices[hostname]['type'] - }} - results['BGP_NEIGHBOR'] = bgp_sessions - results['BGP_PEER_RANGE'] = bgp_peers_with_range - if mgmt_routes: - # TODO: differentiate v4 and v6 - mgmt_intf.itervalues().next()['forced_mgmt_routes'] = mgmt_routes - results['MGMT_INTERFACE'] = mgmt_intf - results['LOOPBACK_INTERFACE'] = lo_intfs - - phyport_intfs = {} - vlan_intfs = {} - pc_intfs = {} - for intf in intfs: - if intf[0][0:4] == 'Vlan': - vlan_intfs[intf] = {} - elif intf[0][0:11] == 'PortChannel': - pc_intfs[intf] = {} - else: - phyport_intfs[intf] = {} - - results['INTERFACE'] = phyport_intfs - results['VLAN_INTERFACE'] = vlan_intfs - results['PORTCHANNEL_INTERFACE'] = pc_intfs - - for port_name in port_speeds: - ports.setdefault(port_name, {})['speed'] = port_speeds[port_name] - results['PORT'] = ports - results['PORTCHANNEL'] = pcs - results['VLAN'] = vlans - - results['DEVICE_NEIGHBOR'] = neighbors - results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) - results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) - results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) - - results['ACL_TABLE'] = acls - mirror_sessions = {} - if erspan_dst: - lo_addr = '0.0.0.0' - for lo in lo_intfs: - lo_network = ipaddress.IPNetwork(lo[1]) - if lo_network.version == 4: - lo_addr = str(lo_network.ip) - break - count = 0 - for dst in erspan_dst: - mirror_sessions['everflow{}'.format(count)] = {"dst_ip": dst, "src_ip": lo_addr} - count += 1 - results['MIRROR_SESSION'] = mirror_sessions - - return results - - -def parse_device_desc_xml(filename): - root = ET.parse(filename).getroot() - (lo_prefix, mgmt_prefix, hostname, hwsku, d_type) = parse_device(root) - - results = {} - results['DEVICE_METADATA'] = {'localhost': { - 'hostname': hostname, - 'hwsku': hwsku, - }} - - results['LOOPBACK_INTERFACE'] = {('lo', lo_prefix): {}} - - mgmt_intf = {} - mgmtipn = ipaddress.IPNetwork(mgmt_prefix) - gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) - results['MGMT_INTERFACE'] = {('eth0', mgmt_prefix): {'gwaddr': gwaddr}} - - return results - - -port_alias_map = {} - - -def print_parse_xml(filename): - results = parse_xml(filename) - print(json.dumps(results, indent=3, cls=minigraph_encoder)) From adea1da2e06c8a32a982c9d7d0c31037555d07ba Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 9 Oct 2017 03:32:20 -0700 Subject: [PATCH 10/17] Fix python warning from previous rrclient commit. Add config support for nhopself, keepalive and holdtime timers. Add route-map to prefer global nexthops for ebgp learned prefixes. --- dockers/docker-fpm-frr/bgpd.conf.j2 | 13 ++++++++++++ src/sonic-config-engine/minigraph.py | 31 +++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index 5452a976368a..c50216eb0cbd 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -51,6 +51,7 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} {% if bgp_session['asn'] | int != 0 %} neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }} neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }} + neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }} {% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %} neighbor {{ neighbor_addr }} allowas-in 1 {% endif %} @@ -59,6 +60,9 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} neighbor {{ neighbor_addr }} activate {% 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 %} maximum-paths 64 exit-address-family @@ -68,6 +72,12 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} neighbor {{ neighbor_addr }} activate {% 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'] %} + neighbor {{ neighbor_addr }} route-map set-next-hop-global-v6 in {% endif %} maximum-paths 64 exit-address-family @@ -81,3 +91,6 @@ maximum-paths 64 route-map ISOLATE permit 10 set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} ! +route-map set-next-hop-global-v6 permit 10 +set ipv6 next-hop prefer-global +! \ No newline at end of file diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 997008af5cee..a0c8a4630730 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -216,24 +216,42 @@ def parse_cpg(cpg, hname): start_peer = session.find(str(QName(ns, "StartPeer"))).text end_router = session.find(str(QName(ns, "EndRouter"))).text end_peer = session.find(str(QName(ns, "EndPeer"))).text + if session.find(str(QName(ns, "RRClient"))) is not None: + rrclient = 1 + else: + rrclient = 0 + if session.find(str(QName(ns, "HoldTime"))) is not None: + holdtime = session.find(str(QName(ns, "HoldTime"))).text + else: + holdtime = 180 + if session.find(str(QName(ns, "KeepAliveTime"))) is not None: + keepalive = session.find(str(QName(ns, "KeepAliveTime"))).text + else: + keepalive = 60 + if session.find(str(QName(ns, "NextHopSelf"))) is not None: + nhopself = 1 + else: + nhopself = 0 if end_router == hname: bgp_sessions[start_peer] = { 'name': start_router, - 'local_addr': end_peer + 'local_addr': end_peer, + 'holdtime': holdtime, + 'keepalive': keepalive, + 'nhopself': nhopself } else: bgp_sessions[end_peer] = { 'name': end_router, - 'local_addr': start_peer + 'local_addr': start_peer, + 'holdtime': holdtime, + 'keepalive': keepalive, + 'nhopself': nhopself } elif child.tag == str(QName(ns, "Routers")): for router in child.findall(str(QName(ns1, "BGPRouterDeclaration"))): asn = router.find(str(QName(ns1, "ASN"))).text hostname = router.find(str(QName(ns1, "Hostname"))).text - if router.find(str(QName(ns1, "RRClient"))): - rrclient = '1' - else: - rrclient = '0' if hostname == hname: myasn = asn peers = router.find(str(QName(ns1, "Peers"))) @@ -252,7 +270,6 @@ def parse_cpg(cpg, hname): bgp_session = bgp_sessions[peer] if hostname == bgp_session['name']: bgp_session['asn'] = asn - bgp_session['rrclient'] = rrclient return bgp_sessions, myasn, bgp_peers_with_range From cc133eaf07c6f47d19a36afcf3fc11f52a667cd6 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 9 Oct 2017 16:42:31 -0700 Subject: [PATCH 11/17] Fix python warning from previous rrclient commit and move config handling to a more relevant place for this cmd. Add config support for nhopself, keepalive and holdtime timers. Add route-map to prefer global nexthops for ebgp learned prefixes. --- dockers/docker-fpm-frr/bgpd.conf.j2 | 2 +- src/sonic-config-engine/minigraph.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dockers/docker-fpm-frr/bgpd.conf.j2 b/dockers/docker-fpm-frr/bgpd.conf.j2 index c50216eb0cbd..07e2dd0c571e 100644 --- a/dockers/docker-fpm-frr/bgpd.conf.j2 +++ b/dockers/docker-fpm-frr/bgpd.conf.j2 @@ -93,4 +93,4 @@ set as-path prepend {{ DEVICE_METADATA['localhost']['bgp_asn'] }} ! route-map set-next-hop-global-v6 permit 10 set ipv6 next-hop prefer-global -! \ No newline at end of file +! diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index a0c8a4630730..80c8b594beb6 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -236,6 +236,7 @@ def parse_cpg(cpg, hname): bgp_sessions[start_peer] = { 'name': start_router, 'local_addr': end_peer, + 'rrclient': rrclient, 'holdtime': holdtime, 'keepalive': keepalive, 'nhopself': nhopself @@ -244,6 +245,7 @@ def parse_cpg(cpg, hname): bgp_sessions[end_peer] = { 'name': end_router, 'local_addr': start_peer, + 'rrclient': rrclient, 'holdtime': holdtime, 'keepalive': keepalive, 'nhopself': nhopself From d1e05d8d6360b1712b6ab4791be45606346332dc Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 9 Oct 2017 19:46:21 -0700 Subject: [PATCH 12/17] Fix python warning from previous rrclient commit and move config handling to a more relevant place for this cmd. Add config support for nhopself, keepalive and holdtime timers. Add route-map to prefer global nexthops for ebgp learned prefixes. --- src/sonic-config-engine/minigraph.py | 10 ++-------- src/sonic-config-engine/tests/test_cfggen.py | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 80c8b594beb6..2034125b1dce 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -216,10 +216,7 @@ def parse_cpg(cpg, hname): start_peer = session.find(str(QName(ns, "StartPeer"))).text end_router = session.find(str(QName(ns, "EndRouter"))).text end_peer = session.find(str(QName(ns, "EndPeer"))).text - if session.find(str(QName(ns, "RRClient"))) is not None: - rrclient = 1 - else: - rrclient = 0 + rrclient = 1 if session.find(str(QName(ns, "RRClient"))) is not None else 0 if session.find(str(QName(ns, "HoldTime"))) is not None: holdtime = session.find(str(QName(ns, "HoldTime"))).text else: @@ -228,10 +225,7 @@ def parse_cpg(cpg, hname): keepalive = session.find(str(QName(ns, "KeepAliveTime"))).text else: keepalive = 60 - if session.find(str(QName(ns, "NextHopSelf"))) is not None: - nhopself = 1 - else: - nhopself = 0 + nhopself = 1 if session.find(str(QName(ns, "NextHopSelf"))) is not None else 0 if end_router == hname: bgp_sessions[start_peer] = { 'name': start_router, diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index d78b19d88ba7..337c06761762 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -113,7 +113,7 @@ def test_minigraph_neighbors(self): def test_minigraph_bgp(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v "BGP_NEIGHBOR[\'10.0.0.59\']"' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'rrclient': '0', 'local_addr': '10.0.0.58', 'asn': '64600', 'name': 'ARISTA02T1'}") + self.assertEqual(output.strip(), "{'rrclient': 0, 'name': 'ARISTA02T1', 'local_addr': '10.0.0.58', 'nhopself': 0, 'holdtime': '180', 'asn': '64600', 'keepalive': '60'}") def test_minigraph_peers_with_range(self): argument = '-m "' + self.sample_graph_bgp_speaker + '" -p "' + self.port_config + '" -v BGP_PEER_RANGE.values\(\)' From f1eb7350918ae96e1b993bf497a4ce62fdf2dc53 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 6 Nov 2017 17:45:53 -0800 Subject: [PATCH 13/17] Sync to master --- .gitignore | 1 + .gitmodules | 4 +- Makefile | 12 +- README.md | 33 +- build_debian.sh | 3 +- .../Arista-7060-CX32S/sai.profile | 1 - .../port_config.ini | 0 .../Arista-7060CX-32S-C32/sai.profile | 1 + .../x86_64-arista_7060_cx32s/minigraph.xml | 4 +- .../Arista-7260CX3-D108C8/port_config.ini | 238 +- .../x86_64-cel_seastone-r0/plugins/sfputil.py | 59 +- .../Force10-S6100-T1 | 1 + .../plugins/sfputil.py | 442 +++- .../plugins/sfputil.py | 395 ++- .../plugins/eeprom.py | 2 +- .../plugins/sfputil.py | 141 +- .../INVENTEC-D7054Q28B-S48-Q6/port_config.ini | 56 + .../INVENTEC-D7054Q28B-S48-Q6/sai.profile | 2 + .../installer.conf | 4 + .../minigraph.xml | 146 ++ .../plugins/eeprom.py | 22 + .../plugins/sfputil.py | 209 ++ .../x86_64-mlnx_msn2410-r0/plugins/sfputil.py | 17 +- .../x86_64-mlnx_msn2700-r0/plugins/sfputil.py | 17 +- .../x86_64-mlnx_msn2740-r0/plugins/sfputil.py | 17 +- dockers/docker-dhcp-relay/Dockerfile.j2 | 8 +- .../docker-dhcp-relay.supervisord.conf.j2 | 67 + dockers/docker-dhcp-relay/docker_init.sh | 18 + dockers/docker-dhcp-relay/isc-dhcp-relay.j2 | 28 - dockers/docker-dhcp-relay/isc-dhcp-relay.sh | 18 - dockers/docker-dhcp-relay/start.sh | 13 +- dockers/docker-dhcp-relay/supervisord.conf | 28 - dockers/docker-dhcp-relay/wait_for_intf.sh.j2 | 1 - dockers/docker-fpm-quagga/bgpd.conf.j2 | 15 +- dockers/docker-lldp-sv2/Dockerfile.j2 | 2 +- dockers/docker-lldp-sv2/reconfigure.sh | 17 +- dockers/docker-lldp-sv2/supervisord.conf | 2 +- dockers/docker-lldp/Dockerfile | 25 - dockers/docker-lldp/supervisord.conf | 19 - dockers/docker-mlnx-sswsyncd-rpc/Dockerfile | 38 - dockers/docker-mlnx-sswsyncd/Dockerfile | 33 - dockers/docker-orchagent/Dockerfile.j2 | 6 +- dockers/docker-orchagent/mirror.json.j2 | 24 - .../msn27xx.32ports.buffers.json.j2 | 287 +++ dockers/docker-orchagent/orchagent.sh | 8 +- dockers/docker-orchagent/start.sh | 6 +- dockers/docker-orchagent/supervisord.conf | 16 + dockers/docker-orchagent/switch.json.j2 | 18 + dockers/docker-orchagent/swssconfig.sh | 18 +- dockers/docker-platform-monitor/lm-sensors.sh | 14 +- dockers/docker-ptf/Dockerfile.j2 | 1 + dockers/docker-snmp/Dockerfile | 48 - dockers/docker-snmp/supervisord.conf | 14 - dockers/docker-sswsyncd/Dockerfile | 27 - dockers/docker-teamd/start.sh | 6 + files/Aboot/boot0.j2 | 3 - files/build_templates/snmp.service.j2 | 4 +- .../build_templates/sonic_debian_extension.j2 | 8 + files/build_templates/swss.service.j2 | 1 + files/dhcp/graphserviceurl | 2 +- .../interfaces/interfaces-config.sh | 20 +- files/image_config/interfaces/interfaces.j2 | 26 - files/image_config/ntp/ntp.conf.j2 | 4 + files/image_config/updategraph/updategraph | 20 +- files/initramfs-tools/arista-convertfs.j2 | 18 +- platform/broadcom/one-image.mk | 1 + .../broadcom/platform-modules-inventec.mk | 11 +- platform/broadcom/sai.mk | 8 +- platform/broadcom/sdk.mk | 4 +- .../broadcom/sonic-platform-modules-arista | 2 +- platform/broadcom/sonic-platform-modules-dell | 2 +- .../d7032q28b/conf/d7032q28b-modules.conf | 10 - .../d7032q28b/modules/Makefile | 4 + .../d7032q28b/modules/inv_eeprom.c | 181 ++ .../d7032q28b/modules/inv_platform.c | 395 +-- .../d7032q28b/modules/inv_swps.c | 618 +++++ .../d7032q28b/modules/inv_swps.h | 131 + .../d7032q28b/modules/io_expander.c | 887 +++++++ .../d7032q28b/modules/io_expander.h | 136 + .../d7032q28b/modules/transceiver.c | 898 +++++++ .../d7032q28b/modules/transceiver.h | 167 ++ .../d7032q28b/utils/inventec_d7032_util.py | 217 ++ .../d7032q28b/utils/onie-syseeprom | Bin 921685 -> 0 bytes .../d7054q28b/modules/Makefile | 6 + .../d7054q28b/modules/inv_cpld.c | 415 +++ .../d7054q28b/modules/inv_eeprom.c | 181 ++ .../d7054q28b/modules/inv_platform.c | 219 ++ .../d7054q28b/modules/inv_psoc.c | 1046 ++++++++ .../d7054q28b/modules/inv_swps.c | 730 ++++++ .../d7054q28b/modules/inv_swps.h | 170 ++ .../d7054q28b/modules/io_expander.c | 944 +++++++ .../d7054q28b/modules/io_expander.h | 143 ++ .../d7054q28b/modules/transceiver.c | 906 +++++++ .../d7054q28b/modules/transceiver.h | 168 ++ .../d7054q28b/utils/inventec_d7054_util.py | 234 ++ .../debian/changelog | 5 + .../debian/control | 5 + .../debian/platform-modules-d7032q28b.init | 37 +- .../debian/platform-modules-d7032q28b.install | 2 +- .../debian/platform-modules-d7032q28b.upstart | 5 + .../debian/platform-modules-d7054q28b.init | 40 + .../debian/platform-modules-d7054q28b.install | 1 + .../debian/platform-modules-d7054q28b.upstart | 5 + .../debian/rules | 5 +- platform/vs/README.md | 75 + platform/vs/create_vnet.sh | 38 + platform/vs/docker-sonic-vs.mk | 16 + platform/vs/docker-sonic-vs/50-default.conf | 68 + platform/vs/docker-sonic-vs/Dockerfile.j2 | 57 + platform/vs/docker-sonic-vs/brcm.profile.ini | 4 + platform/vs/docker-sonic-vs/orchagent.sh | 15 + platform/vs/docker-sonic-vs/start.sh | 35 + platform/vs/docker-sonic-vs/supervisord.conf | 76 + platform/vs/rules.mk | 4 + platform/vs/syncd-vs.mk | 13 + rules/sairedis.mk | 15 + rules/sonic-utilities.mk | 1 + rules/swss-common.mk | 3 + slave.mk | 12 +- sonic-slave/Dockerfile | 7 +- src/isc-dhcp/Makefile | 2 +- ...d-remote_id-and-bridge-iface-support.patch | 247 +- src/sonic-config-engine/minigraph.py | 105 +- src/sonic-config-engine/portconfig.py | 54 + src/sonic-config-engine/setup.py | 4 +- src/sonic-config-engine/sonic-cfggen | 2 +- .../tests/pc-test-graph.xml | 1 + .../tests/sample-port-config-mlnx.ini | 33 + .../tests/sample_output/interfaces | 152 -- .../tests/sample_output/isc-dhcp-relay | 7 - .../tests/sample_output/mirror.json | 14 - .../tests/sample_output/msn27.32ports.json | 341 +++ .../sample_output/rules_for_dataacl.json | 46 - .../sample_output/rules_for_everflow.json | 14 - .../tests/sample_output/table_dataacl.json | 10 - .../tests/sample_output/table_everflow.json | 10 - .../tests/simple-sample-graph.xml | 1 + .../tests/t0-sample-bgp-speaker.xml | 1 + .../tests/t0-sample-graph-everflow.xml | 1 + .../tests/t0-sample-graph.xml | 1 + .../tests/t1-sample-graph-mlnx.xml | 2240 +++++++++++++++++ src/sonic-config-engine/tests/test_acl.py | 58 - src/sonic-config-engine/tests/test_cfggen.py | 30 +- src/sonic-config-engine/tests/test_j2files.py | 18 +- src/sonic-config-engine/translate_acl | 174 -- src/sonic-frr/Makefile | 5 - src/sonic-frr/frr | 1 + src/sonic-platform-daemons | 2 +- src/sonic-py-swsssdk | 2 +- src/sonic-sairedis | 2 +- src/sonic-snmpagent | 2 +- src/sonic-swss | 2 +- src/sonic-swss-common | 2 +- src/sonic-utilities | 2 +- src/supervisor/Makefile | 4 +- 155 files changed, 14181 insertions(+), 1545 deletions(-) delete mode 100644 device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/sai.profile rename device/arista/x86_64-arista_7060_cx32s/{Arista-7060-CX32S => Arista-7060CX-32S-C32}/port_config.ini (100%) create mode 100644 device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/sai.profile mode change 100644 => 100755 device/celestica/x86_64-cel_seastone-r0/plugins/sfputil.py create mode 120000 device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100-T1 create mode 100644 device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini create mode 100644 device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile create mode 100644 device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf create mode 100644 device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml create mode 100644 device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py create mode 100755 device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py create mode 100644 dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 create mode 100755 dockers/docker-dhcp-relay/docker_init.sh delete mode 100644 dockers/docker-dhcp-relay/isc-dhcp-relay.j2 delete mode 100755 dockers/docker-dhcp-relay/isc-dhcp-relay.sh delete mode 100644 dockers/docker-dhcp-relay/supervisord.conf mode change 100755 => 100644 dockers/docker-dhcp-relay/wait_for_intf.sh.j2 delete mode 100644 dockers/docker-lldp/Dockerfile delete mode 100644 dockers/docker-lldp/supervisord.conf delete mode 100644 dockers/docker-mlnx-sswsyncd-rpc/Dockerfile delete mode 100755 dockers/docker-mlnx-sswsyncd/Dockerfile delete mode 100644 dockers/docker-orchagent/mirror.json.j2 create mode 100644 dockers/docker-orchagent/msn27xx.32ports.buffers.json.j2 create mode 100644 dockers/docker-orchagent/switch.json.j2 delete mode 100644 dockers/docker-snmp/Dockerfile delete mode 100644 dockers/docker-snmp/supervisord.conf delete mode 100755 dockers/docker-sswsyncd/Dockerfile delete mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h create mode 100755 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py delete mode 100755 platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/onie-syseeprom create mode 100755 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_psoc.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c create mode 100644 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.h create mode 100755 platform/broadcom/sonic-platform-modules-inventec/d7054q28b/utils/inventec_d7054_util.py create mode 100644 platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.upstart create mode 100644 platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.init create mode 100644 platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install create mode 100644 platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.upstart create mode 100644 platform/vs/README.md create mode 100755 platform/vs/create_vnet.sh create mode 100644 platform/vs/docker-sonic-vs.mk create mode 100644 platform/vs/docker-sonic-vs/50-default.conf create mode 100644 platform/vs/docker-sonic-vs/Dockerfile.j2 create mode 100644 platform/vs/docker-sonic-vs/brcm.profile.ini create mode 100755 platform/vs/docker-sonic-vs/orchagent.sh create mode 100755 platform/vs/docker-sonic-vs/start.sh create mode 100644 platform/vs/docker-sonic-vs/supervisord.conf create mode 100644 platform/vs/rules.mk create mode 100644 platform/vs/syncd-vs.mk create mode 100644 src/sonic-config-engine/portconfig.py create mode 100644 src/sonic-config-engine/tests/sample-port-config-mlnx.ini delete mode 100644 src/sonic-config-engine/tests/sample_output/isc-dhcp-relay delete mode 100644 src/sonic-config-engine/tests/sample_output/mirror.json create mode 100644 src/sonic-config-engine/tests/sample_output/msn27.32ports.json delete mode 100644 src/sonic-config-engine/tests/sample_output/rules_for_dataacl.json delete mode 100644 src/sonic-config-engine/tests/sample_output/rules_for_everflow.json delete mode 100644 src/sonic-config-engine/tests/sample_output/table_dataacl.json delete mode 100644 src/sonic-config-engine/tests/sample_output/table_everflow.json create mode 100644 src/sonic-config-engine/tests/t1-sample-graph-mlnx.xml delete mode 100644 src/sonic-config-engine/tests/test_acl.py delete mode 100755 src/sonic-config-engine/translate_acl create mode 160000 src/sonic-frr/frr diff --git a/.gitignore b/.gitignore index 9ca9d2ff1a98..c5ed255e62a9 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ dockers/docker-teamd/Dockerfile dockers/docker-sonic-mgmt/Dockerfile platform/*/docker-syncd-*/Dockerfile platform/*/docker-syncd-*-rpc/Dockerfile +platform/vs/docker-sonic-vs/Dockerfile # Installer-related files and directories installer/x86_64/platforms/ diff --git a/.gitmodules b/.gitmodules index 4bddfb4a60da..cc2b5b416028 100644 --- a/.gitmodules +++ b/.gitmodules @@ -44,7 +44,6 @@ [submodule "src/sonic-utilities"] path = src/sonic-utilities url = https://github.com/Azure/sonic-utilities - branch = v1.0.3 [submodule "platform/broadcom/sonic-platform-modules-s6000"] path = platform/broadcom/sonic-platform-modules-s6000 url = https://github.com/Azure/sonic-platform-modules-s6000 @@ -66,3 +65,6 @@ [submodule "platform/broadcom/sonic-platform-modules-cel"] path = platform/broadcom/sonic-platform-modules-cel url = https://github.com/celestica-Inc/sonic-platform-modules-cel.git +[submodule "src/sonic-frr/frr"] + path = src/sonic-frr/frr + url = https://github.com/FRRouting/frr.git diff --git a/Makefile b/Makefile index d672edc6836a..800cd32093e3 100644 --- a/Makefile +++ b/Makefile @@ -25,8 +25,8 @@ $(shell rm -f .screen) MAKEFLAGS += -B -SLAVE_BASE_TAG = $(shell shasum sonic-slave/Dockerfile | awk '{print substr($$1,0,11);}') -SLAVE_TAG = $(shell cat sonic-slave/Dockerfile.user sonic-slave/Dockerfile | shasum | awk '{print substr($$1,0,11);}') +SLAVE_BASE_TAG = $(shell sha1sum sonic-slave/Dockerfile | awk '{print substr($$1,0,11);}') +SLAVE_TAG = $(shell cat sonic-slave/Dockerfile.user sonic-slave/Dockerfile | sha1sum | awk '{print substr($$1,0,11);}') SLAVE_BASE_IMAGE = sonic-slave-base SLAVE_IMAGE = sonic-slave-$(USER) @@ -56,11 +56,11 @@ SONIC_BUILD_INSTRUCTION := make \ BUILD_NUMBER=$(BUILD_NUMBER) \ ENABLE_DHCP_GRAPH_SERVICE=$(ENABLE_DHCP_GRAPH_SERVICE) \ SHUTDOWN_BGP_ON_START=$(SHUTDOWN_BGP_ON_START) \ - SONIC_ENABLE_SYNCD_RPC=$(ENABLE_SYNCD_RPC) \ + ENABLE_SYNCD_RPC=$(ENABLE_SYNCD_RPC) \ PASSWORD=$(PASSWORD) \ USERNAME=$(USERNAME) -.PHONY: sonic-slave-build sonic-slave-bash +.PHONY: sonic-slave-build sonic-slave-bash init .DEFAULT_GOAL := all @@ -89,3 +89,7 @@ sonic-slave-bash : { echo Image $(SLAVE_IMAGE):$(SLAVE_TAG) not found. Building... ; \ $(DOCKER_BUILD) ; } @$(DOCKER_RUN) -t $(SLAVE_IMAGE):$(SLAVE_TAG) bash + +init : + git submodule update --init --recursive + git submodule foreach --recursive '[ -f .git ] && echo "gitdir: $$(realpath --relative-to=. $$(cut -d" " -f2 .git))" > .git' diff --git a/README.md b/README.md index c3d58ae1b538..bbae2e150b8e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ -Broadcom: [![Broadcom](https://sonic-jenkins.westus.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-all) -Cavium: [![Cavium](https://sonic-jenkins.westus.cloudapp.azure.com/job/cavium/job/buildimage-cavm-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/cavium/job/buildimage-cavm-all/) -Centec: [![Centec](https://sonic-jenkins.westus.cloudapp.azure.com/job/centec/job/buildimage-centec-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/centec/job/buildimage-centec-all/) +*master*: Broadcom: [![Broadcom](https://sonic-jenkins.westus.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/broadcom/job/buildimage-brcm-all) Mellanox: [![Mellanox](https://sonic-jenkins.westus.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/mellanox/job/buildimage-mlnx-all) -P4: [![Broadcom](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/buildimage-p4-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/buildimage-p4-all) +P4: [![P4](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/buildimage-p4-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/buildimage-p4-all) +VS: [![VS](https://sonic-jenkins.westus.cloudapp.azure.com/job/vs/job/buildimage-vs-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/vs/job/buildimage-vs-all) + +*201709*: Cavium: [![Cavium](https://sonic-jenkins.westus.cloudapp.azure.com/job/cavium/job/buildimage-cavm-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/cavium/job/buildimage-cavm-all/) +Centec: [![Centec](https://sonic-jenkins.westus.cloudapp.azure.com/job/centec/job/buildimage-centec-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/centec/job/buildimage-centec-all/) +Nephos: [![Nephos](https://sonic-jenkins.westus.cloudapp.azure.com/job/nephos/job/buildimage-nephos-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/nephos/job/buildimage-nephos-all/) +Marvell: [![Marvell](https://sonic-jenkins.westus.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-all/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/marvell/job/buildimage-mrvl-all/) # sonic-buildimage @@ -10,7 +14,7 @@ P4: [![Broadcom](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/buil # Description -Following is the instruction on how to build an [(ONIE)](https://github.com/opencomputeproject/onie) compatiable network operating system (NOS) installer image for network switches, and also how to build docker images running inside the NOS. Note that SONiC image are build per ASIC platform. Switches using the same ASIC platform share a common image. For a list of supported switches and ASIC, please refer to this [document](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/buildimage-p4-all). +Following is the instruction on how to build an [(ONIE)](https://github.com/opencomputeproject/onie) compatiable network operating system (NOS) installer image for network switches, and also how to build docker images running inside the NOS. Note that SONiC image are build per ASIC platform. Switches using the same ASIC platform share a common image. For a list of supported switches and ASIC, please refer to this [list](https://github.com/Azure/SONiC/wiki/Supported-Devices-and-Platforms) # Hardware Any server can be a build image server. We are using a server with 1T hard disk. The OS is Ubuntu 16.04. @@ -18,26 +22,23 @@ Any server can be a build image server. We are using a server with 1T hard disk. # Prerequisites ## SAI Version -SONiC V2 is using [SAI 0.9.4](https://github.com/opencomputeproject/SAI/tree/v0.9.4). +Please refer to [SONiC roadmap](https://github.com/Azure/SONiC/wiki/Sonic-Roadmap-Planning) on the SAI version for each SONiC release. ## Clone or fetch the code repository with all git submodules To clone the code repository recursively, assuming git version 1.9 or newer: git clone --recursive https://github.com/Azure/sonic-buildimage.git -NOTE: If the repo has already been cloned, however there are no files under the submodule directories (e.g., src/lldpd, src/ptf, src/sonic-linux-kernel, etc.), you can manually fetch all the git submodules as follows: - - git submodule update --init --recursive - -You also need to change all git paths to relative path as we build all submodules inside the docker: - - git submodule foreach --recursive '[ -f .git ] && echo "gitdir: $(realpath --relative-to=. $(cut -d" " -f2 .git))" > .git' - ## Usage To build SONiC installer image and docker images, run the following commands: + # Execute make init once after cloning the repo, or fetched remote repo with submodule updates + make init + + # Execute make configure once to configure ASIC make configure PLATFORM=[ASIC_VENDOR] + make **NOTE**: We recommend reserving 50G free space to build one platform. @@ -45,11 +46,12 @@ To build SONiC installer image and docker images, run the following commands: The SONiC installer contains all docker images needed. SONiC uses one image for all devices of a same ASIC vendor. The supported ASIC vendors are: - PLATFORM=broadcom -- PLATFORM=marvell (*pending*) +- PLATFORM=marvell - PLATFORM=mellanox - PLATFORM=cavium - PLATFORM=centec - PLATFORM=p4 +- PLATFORM=vs For Broadcom ASIC, we build ONIE and EOS image. EOS image is used for Arista devices, ONIE image is used for all other Broadcom ASIC based devices. @@ -95,6 +97,7 @@ This may take a while, but it is a one-time action, so please be patient. - docker-syncd-cavm.gz: docker image for the daemon to sync database and Cavium switch ASIC (gzip tar archive) - docker-syncd-mlnx.gz: docker image for the daemon to sync database and Mellanox switch ASIC (gzip tar archive) - docker-sonic-p4.gz: docker image for all-in-one for p4 software switch (gzip tar archive) + - docker-sonic-vs.gz: docker image for all-in-one for software virtual switch (gzip tar archive) ## Contribution Guide diff --git a/build_debian.sh b/build_debian.sh index a21cdada0243..3c6673a53ec4 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -207,7 +207,8 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in kexec-tools \ less \ unzip \ - gdisk + gdisk \ + grub2-common sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y download \ grub-pc-bin diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/sai.profile b/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/sai.profile deleted file mode 100644 index 29a42f07a734..000000000000 --- a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/sai.profile +++ /dev/null @@ -1 +0,0 @@ -SAI_INIT_CONFIG_FILE=/etc/bcm/th-a7060-cx32s-32x100G.config.bcm diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/port_config.ini similarity index 100% rename from device/arista/x86_64-arista_7060_cx32s/Arista-7060-CX32S/port_config.ini rename to device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/port_config.ini diff --git a/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/sai.profile b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/sai.profile new file mode 100644 index 000000000000..c04ad3498582 --- /dev/null +++ b/device/arista/x86_64-arista_7060_cx32s/Arista-7060CX-32S-C32/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/th-a7060-cx32s-32x100G.config.bcm diff --git a/device/arista/x86_64-arista_7060_cx32s/minigraph.xml b/device/arista/x86_64-arista_7060_cx32s/minigraph.xml index 513a60254818..23282de17af1 100644 --- a/device/arista/x86_64-arista_7060_cx32s/minigraph.xml +++ b/device/arista/x86_64-arista_7060_cx32s/minigraph.xml @@ -1040,7 +1040,7 @@ switch1 - Arista-7060-CX32S + Arista-7060CX-32S-C32 @@ -1075,5 +1075,5 @@ switch1 - Arista-7060-CX32S + Arista-7060CX-32S-C32 diff --git a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini index 35a2175cf21d..541b197f6bb8 100644 --- a/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini +++ b/device/arista/x86_64-arista_7260cx3_64/Arista-7260CX3-D108C8/port_config.ini @@ -1,121 +1,121 @@ # name lanes alias index Ethernet0 77,78 Ethernet1/1 1 -Ethernet2 79,80 Ethernet1/3 2 -Ethernet4 65,66 Ethernet2/1 3 -Ethernet6 67,68 Ethernet2/3 4 -Ethernet8 85,86 Ethernet3/1 5 -Ethernet10 87,88 Ethernet3/3 6 -Ethernet12 89,90 Ethernet4/1 7 -Ethernet14 91,92 Ethernet4/3 8 -Ethernet16 109,110 Ethernet5/1 9 -Ethernet18 111,112 Ethernet5/3 10 -Ethernet20 97,98 Ethernet6/1 11 -Ethernet22 99,100 Ethernet6/3 12 -Ethernet24 5,6 Ethernet7/1 13 -Ethernet26 7,8 Ethernet7/3 14 -Ethernet28 13,14 Ethernet8/1 15 -Ethernet30 15,16 Ethernet8/3 16 -Ethernet32 25,26 Ethernet9/1 17 -Ethernet34 27,28 Ethernet9/3 18 -Ethernet36 21,22 Ethernet10/1 19 -Ethernet38 23,24 Ethernet10/3 20 -Ethernet40 37,38 Ethernet11/1 21 -Ethernet42 39,40 Ethernet11/3 22 -Ethernet44 45,46 Ethernet12/1 23 -Ethernet46 47,48 Ethernet12/3 24 -Ethernet48 57,58 Ethernet13/1 25 -Ethernet50 59,60 Ethernet13/3 26 -Ethernet52 53,54 Ethernet14/1 27 -Ethernet54 55,56 Ethernet14/3 28 -Ethernet56 117,118 Ethernet15/1 29 -Ethernet58 119,120 Ethernet15/3 30 -Ethernet60 121,122 Ethernet16/1 31 -Ethernet62 123,124 Ethernet16/3 32 -Ethernet64 141,142 Ethernet17/1 33 -Ethernet66 143,144 Ethernet17/3 34 -Ethernet68 133,134,135,136 Ethernet18/1 35 -Ethernet72 197,198 Ethernet19/1 36 -Ethernet74 199,200 Ethernet19/3 37 -Ethernet76 205,206,207,208 Ethernet20/1 38 -Ethernet80 217,218 Ethernet21/1 39 -Ethernet82 219,220 Ethernet21/3 40 -Ethernet84 213,214 Ethernet22/1 41 -Ethernet86 215,216 Ethernet22/3 42 -Ethernet88 229,230 Ethernet23/1 43 -Ethernet90 231,232 Ethernet23/3 44 -Ethernet92 237,238 Ethernet24/1 45 -Ethernet94 239,240 Ethernet24/3 46 -Ethernet96 249,250 Ethernet25/1 47 -Ethernet98 251,252 Ethernet25/3 48 -Ethernet100 245,246 Ethernet26/1 49 -Ethernet102 247,248 Ethernet26/3 50 -Ethernet104 149,150 Ethernet27/1 51 -Ethernet106 151,152 Ethernet27/3 52 -Ethernet108 153,154 Ethernet28/1 53 -Ethernet110 155,156 Ethernet28/3 54 -Ethernet112 173,174 Ethernet29/1 55 -Ethernet114 175,176 Ethernet29/3 56 -Ethernet116 161,162 Ethernet30/1 57 -Ethernet118 163,164 Ethernet30/3 58 -Ethernet120 181,182 Ethernet31/1 59 -Ethernet122 183,184 Ethernet31/3 60 -Ethernet124 185,186 Ethernet32/1 61 -Ethernet126 187,188 Ethernet32/3 62 -Ethernet128 69,70 Ethernet33/1 63 -Ethernet130 71,72 Ethernet33/3 64 -Ethernet132 73,74 Ethernet34/1 65 -Ethernet134 75,76 Ethernet34/3 66 -Ethernet136 93,94 Ethernet35/1 67 -Ethernet138 95,96 Ethernet35/3 68 -Ethernet140 81,82 Ethernet36/1 69 -Ethernet142 83,84 Ethernet36/3 70 -Ethernet144 101,102 Ethernet37/1 71 -Ethernet146 103,104 Ethernet37/3 72 -Ethernet148 105,106 Ethernet38/1 73 -Ethernet150 107,108 Ethernet38/3 74 -Ethernet152 9,10 Ethernet39/1 75 -Ethernet154 11,12 Ethernet39/3 76 -Ethernet156 1,2 Ethernet40/1 77 -Ethernet158 3,4 Ethernet40/3 78 -Ethernet160 17,18 Ethernet41/1 79 -Ethernet162 19,20 Ethernet41/3 80 -Ethernet164 29,30 Ethernet42/1 81 -Ethernet166 31,32 Ethernet42/1 82 -Ethernet168 41,42 Ethernet43/1 83 -Ethernet170 43,44 Ethernet43/3 84 -Ethernet172 33,34 Ethernet44/1 85 -Ethernet174 35,36 Ethernet44/3 86 -Ethernet176 49,50,51,52 Ethernet45/1 87 -Ethernet180 61,62,63,64 Ethernet46/1 88 -Ethernet184 125,126,127,128 Ethernet47/1 89 -Ethernet188 113,114,115,116 Ethernet48/1 90 -Ethernet192 129,130,131,132 Ethernet49/1 91 -Ethernet196 137,138,139,140 Ethernet50/1 92 -Ethernet200 201,202,203,204 Ethernet51/1 93 -Ethernet204 193,194,195,196 Ethernet52/1 94 -Ethernet208 209,210 Ethernet53/1 95 -Ethernet210 211,212 Ethernet53/3 96 -Ethernet212 221,222 Ethernet54/1 97 -Ethernet214 223,224 Ethernet54/3 98 -Ethernet216 233,234 Ethernet55/1 99 -Ethernet218 235,236 Ethernet55/3 100 -Ethernet220 225,226 Ethernet56/1 101 -Ethernet222 227,228 Ethernet56/3 102 -Ethernet224 241,242 Ethernet57/1 103 -Ethernet226 243,244 Ethernet57/3 104 -Ethernet228 253,254 Ethernet58/1 105 -Ethernet230 255,256 Ethernet58/3 106 -Ethernet232 157,158 Ethernet59/1 107 -Ethernet234 159,160 Ethernet59/3 108 -Ethernet236 145,146 Ethernet60/1 109 -Ethernet238 147,148 Ethernet60/3 110 -Ethernet240 165,166 Ethernet61/1 111 -Ethernet242 167,168 Ethernet61/3 112 -Ethernet244 169,170 Ethernet62/1 113 -Ethernet246 171,172 Ethernet62/3 114 -Ethernet248 189,190 Ethernet63/1 115 -Ethernet250 191,192 Ethernet63/3 116 -Ethernet252 177,178 Ethernet64/1 117 -Ethernet254 179,180 Ethernet64/3 118 -Ethernet256 257 Ethernet257 119 -Ethernet260 259 Ethernet259 120 +Ethernet2 79,80 Ethernet1/3 1 +Ethernet4 65,66 Ethernet2/1 2 +Ethernet6 67,68 Ethernet2/3 2 +Ethernet8 85,86 Ethernet3/1 3 +Ethernet10 87,88 Ethernet3/3 3 +Ethernet12 89,90 Ethernet4/1 4 +Ethernet14 91,92 Ethernet4/3 4 +Ethernet16 109,110 Ethernet5/1 5 +Ethernet18 111,112 Ethernet5/3 5 +Ethernet20 97,98 Ethernet6/1 6 +Ethernet22 99,100 Ethernet6/3 6 +Ethernet24 5,6 Ethernet7/1 7 +Ethernet26 7,8 Ethernet7/3 7 +Ethernet28 13,14 Ethernet8/1 8 +Ethernet30 15,16 Ethernet8/3 8 +Ethernet32 25,26 Ethernet9/1 9 +Ethernet34 27,28 Ethernet9/3 9 +Ethernet36 21,22 Ethernet10/1 10 +Ethernet38 23,24 Ethernet10/3 10 +Ethernet40 37,38 Ethernet11/1 11 +Ethernet42 39,40 Ethernet11/3 11 +Ethernet44 45,46 Ethernet12/1 12 +Ethernet46 47,48 Ethernet12/3 12 +Ethernet48 57,58 Ethernet13/1 13 +Ethernet50 59,60 Ethernet13/3 13 +Ethernet52 53,54 Ethernet14/1 14 +Ethernet54 55,56 Ethernet14/3 14 +Ethernet56 117,118 Ethernet15/1 15 +Ethernet58 119,120 Ethernet15/3 15 +Ethernet60 121,122 Ethernet16/1 16 +Ethernet62 123,124 Ethernet16/3 16 +Ethernet64 141,142 Ethernet17/1 17 +Ethernet66 143,144 Ethernet17/3 17 +Ethernet68 133,134,135,136 Ethernet18/1 18 +Ethernet72 197,198 Ethernet19/1 19 +Ethernet74 199,200 Ethernet19/3 19 +Ethernet76 205,206,207,208 Ethernet20/1 20 +Ethernet80 217,218 Ethernet21/1 21 +Ethernet82 219,220 Ethernet21/3 21 +Ethernet84 213,214 Ethernet22/1 22 +Ethernet86 215,216 Ethernet22/3 22 +Ethernet88 229,230 Ethernet23/1 23 +Ethernet90 231,232 Ethernet23/3 23 +Ethernet92 237,238 Ethernet24/1 24 +Ethernet94 239,240 Ethernet24/3 24 +Ethernet96 249,250 Ethernet25/1 25 +Ethernet98 251,252 Ethernet25/3 25 +Ethernet100 245,246 Ethernet26/1 26 +Ethernet102 247,248 Ethernet26/3 26 +Ethernet104 149,150 Ethernet27/1 27 +Ethernet106 151,152 Ethernet27/3 27 +Ethernet108 153,154 Ethernet28/1 28 +Ethernet110 155,156 Ethernet28/3 28 +Ethernet112 173,174 Ethernet29/1 29 +Ethernet114 175,176 Ethernet29/3 29 +Ethernet116 161,162 Ethernet30/1 30 +Ethernet118 163,164 Ethernet30/3 30 +Ethernet120 181,182 Ethernet31/1 31 +Ethernet122 183,184 Ethernet31/3 31 +Ethernet124 185,186 Ethernet32/1 32 +Ethernet126 187,188 Ethernet32/3 32 +Ethernet128 69,70 Ethernet33/1 33 +Ethernet130 71,72 Ethernet33/3 33 +Ethernet132 73,74 Ethernet34/1 34 +Ethernet134 75,76 Ethernet34/3 34 +Ethernet136 93,94 Ethernet35/1 35 +Ethernet138 95,96 Ethernet35/3 35 +Ethernet140 81,82 Ethernet36/1 36 +Ethernet142 83,84 Ethernet36/3 36 +Ethernet144 101,102 Ethernet37/1 37 +Ethernet146 103,104 Ethernet37/3 37 +Ethernet148 105,106 Ethernet38/1 38 +Ethernet150 107,108 Ethernet38/3 38 +Ethernet152 9,10 Ethernet39/1 39 +Ethernet154 11,12 Ethernet39/3 39 +Ethernet156 1,2 Ethernet40/1 40 +Ethernet158 3,4 Ethernet40/3 40 +Ethernet160 17,18 Ethernet41/1 41 +Ethernet162 19,20 Ethernet41/3 41 +Ethernet164 29,30 Ethernet42/1 42 +Ethernet166 31,32 Ethernet42/3 42 +Ethernet168 41,42 Ethernet43/1 43 +Ethernet170 43,44 Ethernet43/3 43 +Ethernet172 33,34 Ethernet44/1 44 +Ethernet174 35,36 Ethernet44/3 44 +Ethernet176 49,50,51,52 Ethernet45/1 45 +Ethernet180 61,62,63,64 Ethernet46/1 46 +Ethernet184 125,126,127,128 Ethernet47/1 47 +Ethernet188 113,114,115,116 Ethernet48/1 48 +Ethernet192 129,130,131,132 Ethernet49/1 49 +Ethernet196 137,138,139,140 Ethernet50/1 50 +Ethernet200 201,202,203,204 Ethernet51/1 51 +Ethernet204 193,194,195,196 Ethernet52/1 52 +Ethernet208 209,210 Ethernet53/1 53 +Ethernet210 211,212 Ethernet53/3 53 +Ethernet212 221,222 Ethernet54/1 54 +Ethernet214 223,224 Ethernet54/3 54 +Ethernet216 233,234 Ethernet55/1 55 +Ethernet218 235,236 Ethernet55/3 55 +Ethernet220 225,226 Ethernet56/1 56 +Ethernet222 227,228 Ethernet56/3 56 +Ethernet224 241,242 Ethernet57/1 57 +Ethernet226 243,244 Ethernet57/3 57 +Ethernet228 253,254 Ethernet58/1 58 +Ethernet230 255,256 Ethernet58/3 58 +Ethernet232 157,158 Ethernet59/1 59 +Ethernet234 159,160 Ethernet59/3 59 +Ethernet236 145,146 Ethernet60/1 60 +Ethernet238 147,148 Ethernet60/3 60 +Ethernet240 165,166 Ethernet61/1 61 +Ethernet242 167,168 Ethernet61/3 61 +Ethernet244 169,170 Ethernet62/1 62 +Ethernet246 171,172 Ethernet62/3 62 +Ethernet248 189,190 Ethernet63/1 63 +Ethernet250 191,192 Ethernet63/3 63 +Ethernet252 177,178 Ethernet64/1 64 +Ethernet254 179,180 Ethernet64/3 64 +Ethernet256 257 Ethernet65 65 +Ethernet260 259 Ethernet66 66 diff --git a/device/celestica/x86_64-cel_seastone-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_seastone-r0/plugins/sfputil.py old mode 100644 new mode 100755 index f3943e734b58..7ff632e152b9 --- a/device/celestica/x86_64-cel_seastone-r0/plugins/sfputil.py +++ b/device/celestica/x86_64-cel_seastone-r0/plugins/sfputil.py @@ -1,25 +1,58 @@ #!/usr/bin/env python +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 31 - ports_in_block = 32 + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} + qsfp_ports = range(0, PORTS_IN_BLOCK + 1) - _qsfp_ports = range(0, ports_in_block + 1) + @property + def port_start(self): + return self.PORT_START - def __init__(self, port_num): + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): # Override port_to_eeprom_mapping for class initialization eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' - for x in range(self.port_start, self.port_end + 1): + + for x in range(self.PORT_START, self.PORT_END + 1): self.port_to_eeprom_mapping[x] = eeprom_path.format( x + 26 ) - sfputilbase.__init__(self, port_num) + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + raise NotImplementedError + + def get_low_power_mode(self, port_num): + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + raise NotImplementedError + + def reset(self, port_num): + raise NotImplementedError + diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100-T1 b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100-T1 new file mode 120000 index 000000000000..36b1b840b83e --- /dev/null +++ b/device/dell/x86_64-dell_s6100_c2538-r0/Force10-S6100-T1 @@ -0,0 +1 @@ +Force10-S6100 \ No newline at end of file diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py b/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py index 534e587ae722..d6fbcbcf6944 100644 --- a/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py @@ -1,27 +1,433 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# +# +-i2c----+--------+ +# | 6 | 7 | +# | +-------------+ | +# | |IOM1 | IOM3 | | +# | |IOM2 | IOM4 | | +# | +-------------+ | +# | 8 | 9 | +# +--------+--------+ + try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + import os + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 0 + PORT_END = 63 + PORTS_IN_BLOCK = 64 + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 0: [6, 18, 34, 50, 66], + 1: [6, 19, 35, 51, 67], + 2: [6, 20, 36, 52, 68], + 3: [6, 21, 37, 53, 69], + 4: [6, 22, 38, 54, 70], + 5: [6, 23, 39, 55, 71], + 6: [6, 24, 40, 56, 72], + 7: [6, 25, 41, 57, 73], + 8: [6, 26, 42, 58, 74], + 9: [6, 27, 43, 59, 75], + 10: [6, 28, 44, 60, 76], + 11: [6, 29, 45, 61, 77], + 12: [6, 30, 46, 62, 78], + 13: [6, 31, 47, 63, 79], + 14: [6, 32, 48, 64, 80], + 15: [6, 33, 49, 65, 81], + 16: [8, 18, 34, 50, 66], + 17: [8, 19, 35, 51, 67], + 18: [8, 20, 36, 52, 68], + 19: [8, 21, 37, 53, 69], + 20: [8, 22, 38, 54, 70], + 21: [8, 23, 39, 55, 71], + 22: [8, 24, 40, 56, 72], + 23: [8, 25, 41, 57, 73], + 24: [8, 26, 42, 58, 74], + 25: [8, 27, 43, 59, 75], + 26: [8, 28, 44, 60, 76], + 27: [8, 29, 45, 61, 77], + 28: [8, 30, 46, 62, 78], + 29: [8, 31, 47, 63, 79], + 30: [8, 32, 48, 64, 80], + 31: [8, 33, 49, 65, 81], + 32: [7, 18, 34, 50, 66], + 33: [7, 19, 35, 51, 67], + 34: [7, 20, 36, 52, 68], + 35: [7, 21, 37, 53, 69], + 36: [7, 22, 38, 54, 70], + 37: [7, 23, 39, 55, 71], + 38: [7, 24, 40, 56, 72], + 39: [7, 25, 41, 57, 73], + 40: [7, 26, 42, 58, 74], + 41: [7, 27, 43, 59, 75], + 42: [7, 28, 44, 60, 76], + 43: [7, 29, 45, 61, 77], + 44: [7, 30, 46, 62, 78], + 45: [7, 31, 47, 63, 79], + 46: [7, 32, 48, 64, 80], + 47: [7, 33, 49, 65, 81], + 48: [9, 18, 34, 50, 66], + 49: [9, 19, 35, 51, 67], + 50: [9, 20, 36, 52, 68], + 51: [9, 21, 37, 53, 69], + 52: [9, 22, 38, 54, 70], + 53: [9, 23, 39, 55, 71], + 54: [9, 24, 40, 56, 72], + 55: [9, 25, 41, 57, 73], + 56: [9, 26, 42, 58, 74], + 57: [9, 27, 43, 59, 75], + 58: [9, 28, 44, 60, 76], + 59: [9, 29, 45, 61, 77], + 60: [9, 30, 46, 62, 78], + 61: [9, 31, 47, 63, 79], + 62: [9, 32, 48, 64, 80], + 63: [9, 33, 49, 65, 81] +} + + IOM_1_PORT_START = 0 + IOM_1_PORT_END = 15 + + IOM_2_PORT_START = 16 + IOM_2_PORT_END = 31 + + IOM_3_PORT_START = 32 + IOM_3_PORT_END = 47 + + IOM_4_PORT_START = 48 + IOM_4_PORT_END = 63 + + BASE_VAL_PATH="/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" + + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def iom1_port_start(self): + return self.IOM_1_PORT_START + + @property + def iom1_port_end(self): + return self.IOM_1_PORT_END + + @property + def iom2_port_start(self): + return self.IOM_2_PORT_START + + @property + def iom2_port_end(self): + return self.IOM_2_PORT_END + + @property + def iom3_port_start(self): + return self.IOM_3_PORT_START + + @property + def iom3_port_end(self): + return self.IOM_3_PORT_END + + @property + def iom4_port_start(self): + return self.IOM_4_PORT_START + + @property + def iom4_port_end(self): + return self.IOM_4_PORT_END + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + @property + def port_to_i2c_mapping(self): + return self._port_to_i2c_mapping + + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" + global port_to_eeprom_path + + for port_num in range(0, self.port_end + 1): + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + assigned=0 + #i2c-6 + for x in range(1,5): + port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) + if ( os.path.isfile(port_to_eeprom_path) ): + self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path + assigned=1 + elif (not assigned): + self.port_to_eeprom_mapping[port_num]="No IOM" + + elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + assigned=0 + #i2c-8 + for x in range(1,5): + port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) + if ( os.path.isfile(port_to_eeprom_path) ): + self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path + assigned=1 + elif (not assigned): + self.port_to_eeprom_mapping[port_num]="No IOM" + + elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: + assigned=0 + #i2c-7 + for x in range(1,5): + port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) + if ( os.path.isfile(port_to_eeprom_path) ): + self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path + assigned=1 + elif (not assigned): + self.port_to_eeprom_mapping[port_num]="No IOM" + + + elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: + assigned=0 + #i2c-9 + for x in range(1,5): + port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) + if ( os.path.isfile(port_to_eeprom_path) ): + self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path + assigned=1 + elif (not assigned): + self.port_to_eeprom_mapping[port_num]="No IOM" + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + global i2c_line + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + #port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line=14 + elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + i2c_line=16 + elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: + i2c_line=15 + elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: + i2c_line=17 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_modprs" + reg_file = open(qsfp_path, "r") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + #Absence of IOM throws read error + if (content == 'read error'): + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + #Rationalize port settings + if port_num > 15: + port_num=port_num%16 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + #port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line=14 + elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + i2c_line=16 + elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: + i2c_line=15 + elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: + i2c_line=17 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "r") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + #Absence of IOM throws read error + if (content == 'read error'): + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + #Rationalize port settings + if port_num > 15: + port_num=port_num%16 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + #port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line=14 + elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + i2c_line=16 + elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: + i2c_line=15 + elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: + i2c_line=17 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "r+") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + #Absence of IOM throws read error + if (content == 'read error'): + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + #Rationalize port settings + if port_num > 15: + port_num=port_num%16 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def reset(self, port_num): + + global i2c_line + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + #port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line=14 + elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + i2c_line=16 + elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: + i2c_line=15 + elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: + i2c_line=17 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "r+") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + #Absence of IOM throws read error + if (content == 'read error'): + print("it's empty"); + return False + + # File content is a string containing the hex representation of the register + reg_value = int(content, 16) + + #Rationalize port settings + if port_num > 15: + port_num=port_num%16 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + # ResetL is active low + reg_value = reg_value & ~mask -class sfputil(sfputilbase): - """Platform specific sfputil class""" + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() - port_start = 0 - port_end = 63 - ports_in_block = 64 + # Sleep 1 second to allow it to settle + time.sleep(1) - eeprom_offset = 18 + # Flip the bit back high and write back to the register to take port out of reset + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "w") - port_to_eeprom_mapping = {} + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False - _qsfp_ports = range(0, ports_in_block + 1) + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom' - for x in range(0, self.port_end + 1): - self.port_to_eeprom_mapping[x] = eeprom_path.format(x + self.eeprom_offset) - sfputilbase.__init__(self, port_num) + return True diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py b/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py index 07e094db7bb8..5609abe9b49a 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py @@ -1,60 +1,339 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") - - -class sfputil(sfputilbase): - """Platform specific sfputil class""" - - port_start = 0 - port_end = 31 - ports_in_block = 32 - - port_to_eeprom_mapping = {} - port_to_i2c_mapping = { - 0: 18, - 1: 19, - 2: 20, - 3: 21, - 4: 22, - 5: 23, - 6: 24, - 7: 25, - 8: 26, - 9: 27, - 10: 28, - 11: 29, - 12: 31, - 13: 30, - 14: 33, - 15: 32, - 16: 34, - 17: 35, - 18: 36, - 19: 37, - 20: 38, - 21: 39, - 22: 40, - 23: 41, - 24: 42, - 25: 43, - 26: 44, - 27: 45, - 28: 46, - 29: 47, - 30: 48, - 31: 49 - } - - _qsfp_ports = range(0, ports_in_block + 1) - - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom' - for x in range(0, self.port_end + 1): - port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) - self.port_to_eeprom_mapping[x] = port_eeprom_path - sfputilbase.__init__(self, port_num) + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 + IOM_1_PORT_START = 0 + IOM_1_PORT_END = 11 + IOM_2_PORT_START = 12 + IOM_2_PORT_END = 21 + IOM_3_PORT_START = 22 + IOM_3_PORT_END = 31 + + BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 0: [9, 18], + 1: [9, 19], + 2: [9, 20], + 3: [9, 21], + 4: [9, 22], + 5: [9, 23], + 6: [9, 24], + 7: [9, 25], + 8: [8, 26], + 9: [8, 27], + 10: [8, 28], + 11: [8, 29], + 12: [8, 31], # reordered + 13: [8, 30], + 14: [8, 33], # reordered + 15: [8, 32], + 16: [7, 34], + 17: [7, 35], + 18: [7, 36], + 19: [7, 37], + 20: [7, 38], + 21: [7, 39], + 22: [7, 40], + 23: [7, 41], + 24: [6, 42], + 25: [6, 43], + 26: [6, 44], + 27: [6, 45], + 28: [6, 46], + 29: [6, 47], + 30: [6, 48], + 31: [6, 49] + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def iom1_port_start(self): + return self.IOM_1_PORT_START + + @property + def iom1_port_end(self): + return self.IOM_1_PORT_END + + @property + def iom2_port_start(self): + return self.IOM_2_PORT_START + + @property + def iom2_port_end(self): + return self.IOM_2_PORT_END + + @property + def iom3_port_start(self): + return self.IOM_3_PORT_START + + @property + def iom3_port_end(self): + return self.IOM_3_PORT_END + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + @property + def port_to_i2c_mapping(self): + return self._port_to_i2c_mapping + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" + + for x in range(0, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self.port_to_i2c_mapping[x][0], + self.port_to_i2c_mapping[x][1]) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + global i2c_line + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + # port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line = 14 + elif (port_num >= self.iom2_port_start and + port_num <= self.iom2_port_end): + i2c_line = 15 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + i2c_line = 16 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_modprs" + reg_file = open(qsfp_path, "r") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # Absence of IOM throws read error + if (content == 'read error'): + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Rationalize port settings + if port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + port_num = port_num % 12 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + port_num = port_num % 22 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line = 14 + elif (port_num >= self.iom2_port_start and + port_num <= self.iom2_port_end): + i2c_line = 15 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + i2c_line = 16 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "r") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # Absence of IOM throws read error + if (content == 'read error'): + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Rationalize port settings + if port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + port_num = port_num % 12 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + port_num = port_num % 22 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line = 14 + elif (port_num >= self.iom2_port_start and + port_num <= self.iom2_port_end): + i2c_line = 15 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + i2c_line = 16 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "r+") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # Absence of IOM throws read error + if (content == 'read error'): + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Rationalize port settings + if port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + port_num = port_num % 12 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + port_num = port_num % 22 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def reset(self, port_num): + + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + # port_num and i2c match + if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: + i2c_line = 14 + elif (port_num >= self.iom2_port_start and + port_num <= self.iom2_port_end): + i2c_line = 15 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + i2c_line = 16 + + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "r+") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # File content is a string containing the hex representation of th + reg_value = int(content, 16) + + # Rationalize port settings + if port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: + port_num = port_num % 12 + elif (port_num >= self.iom3_port_start and + port_num <= self.iom3_port_end): + port_num = port_num % 22 + + # Mask off the bit corresponding to our port + mask = (1 << port_num) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + # Flip the bit back high and write back to the register to take + # port out of reset + try: + qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" + reg_file = open(qsfp_path, "w+") + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + return True diff --git a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py index ad70e584bb2a..de5c24ba0e6d 100644 --- a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py +++ b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/eeprom.py @@ -18,5 +18,5 @@ class board(eeprom_tlvinfo.TlvInfoDecoder): def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/tmp/eeprom" + self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0053/eeprom" super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py index 020faab9db58..645c76b9f0db 100644 --- a/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py +++ b/device/inventec/x86_64-inventec_d7032q28b-r0/plugins/sfputil.py @@ -1,19 +1,23 @@ -#!/usr/bin/env python +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# try: - from sonic_sfp.sfputilbase import sfputilbase -except ImportError, e: - raise ImportError (str(e) + "- required module not found") + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) -class sfputil(sfputilbase): - """Platform specific sfputil class""" +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" - port_start = 0 - port_end = 31 - ports_in_block = 32 + PORT_START = 0 + PORT_END = 31 + PORTS_IN_BLOCK = 32 - port_to_eeprom_mapping = {} + _port_to_eeprom_mapping = {} port_to_i2c_mapping = { 0: 22, 1: 23, @@ -49,12 +53,117 @@ class sfputil(sfputilbase): 31: 21 } - _qsfp_ports = range(0, ports_in_block + 1) + @property + def port_start(self): + return self.PORT_START - def __init__(self, port_num): - # Override port_to_eeprom_mapping for class initialization - eeprom_path = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom' - for x in range(self.port_start, self.port_end + 1): + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(0, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + + for x in range(0, self.port_end + 1): port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) self.port_to_eeprom_mapping[x] = port_eeprom_path - sfputilbase.__init__(self, port_num) + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/swps/port"+str(port_num)+"/present") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = int(reg_file.readline().rstrip()) + + if reg_value == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + + reg_value = int(reg_file.readline().rstrip()) + + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod", "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = int(reg_file.readline().rstrip()) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def reset(self, port_num): + QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/class/swps/port"+str(port_num)+"/reset" + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + + return True diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini new file mode 100644 index 000000000000..a8eaeb1f0665 --- /dev/null +++ b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/port_config.ini @@ -0,0 +1,56 @@ +# 48x25G + 6x100G +# name lanes alias +Ethernet0 2 Ethernet0 +Ethernet4 1 Ethernet4 +Ethernet8 4 Ethernet8 +Ethernet12 3 Ethernet12 +Ethernet16 6 Ethernet16 +Ethernet20 5 Ethernet20 +Ethernet24 8 Ethernet24 +Ethernet28 7 Ethernet28 +Ethernet32 10 Ethernet32 +Ethernet36 9 Ethernet36 +Ethernet40 12 Ethernet40 +Ethernet44 11 Ethernet44 +Ethernet48 22 Ethernet48 +Ethernet52 21 Ethernet52 +Ethernet56 24 Ethernet56 +Ethernet60 23 Ethernet60 +Ethernet64 34 Ethernet64 +Ethernet68 33 Ethernet68 +Ethernet72 36 Ethernet72 +Ethernet76 35 Ethernet76 +Ethernet80 38 Ethernet80 +Ethernet84 37 Ethernet84 +Ethernet88 40 Ethernet88 +Ethernet92 39 Ethernet92 +Ethernet96 42 Ethernet96 +Ethernet100 41 Ethernet100 +Ethernet104 44 Ethernet104 +Ethernet108 43 Ethernet108 +Ethernet112 50 Ethernet112 +Ethernet116 49 Ethernet116 +Ethernet120 52 Ethernet120 +Ethernet124 51 Ethernet124 +Ethernet128 54 Ethernet128 +Ethernet132 53 Ethernet132 +Ethernet136 56 Ethernet136 +Ethernet140 55 Ethernet140 +Ethernet144 66 Ethernet144 +Ethernet148 65 Ethernet148 +Ethernet152 68 Ethernet152 +Ethernet156 67 Ethernet156 +Ethernet160 70 Ethernet160 +Ethernet164 69 Ethernet164 +Ethernet168 72 Ethernet168 +Ethernet172 71 Ethernet172 +Ethernet176 82 Ethernet176 +Ethernet180 81 Ethernet180 +Ethernet184 84 Ethernet184 +Ethernet188 83 Ethernet188 +Ethernet192 85,86,87,88 Ethernet192 +Ethernet196 97,98,99,100 Ethernet196 +Ethernet200 105,106,107,108 Ethernet200 +Ethernet204 101,102,103,104 Ethernet204 +Ethernet208 117,118,119,120 Ethernet208 +Ethernet212 109,110,111,112 Ethernet212 diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile new file mode 100644 index 000000000000..6f60cbd6118c --- /dev/null +++ b/device/inventec/x86_64-inventec_d7054q28b-r0/INVENTEC-D7054Q28B-S48-Q6/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/th-d7054q28b-48x10g-6x100g.config.bcm +SAI_NUM_ECMP_MEMBERS=32 diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf b/device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf new file mode 100644 index 000000000000..1db64ba02c38 --- /dev/null +++ b/device/inventec/x86_64-inventec_d7054q28b-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +VAR_LOG_SIZE=1024 diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml b/device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml new file mode 100644 index 000000000000..0e579ccbde14 --- /dev/null +++ b/device/inventec/x86_64-inventec_d7054q28b-r0/minigraph.xml @@ -0,0 +1,146 @@ + + + + + + OCPSCH0104001MS + 10.10.1.26 + SONiC-Inventec-d7054 + 10.10.1.25 + 1 + 10 + 3 + + + OCPSCH0104002MS + 10.10.2.26 + SONiC-Inventec-d7054 + 10.10.2.25 + 1 + 10 + 3 + + + + + 64536 + SONiC-Inventec-d7054 + + +
10.10.1.26
+ + +
+ +
10.10.2.26
+ + +
+
+ +
+ + 64542 + OCPSCH0104001MS + + + + 64543 + OCPSCH0104002MS + + +
+
+ + + + + + HostIP + Loopback0 + + 100.0.0.9/32 + + 100.0.0.9/32 + + + + + + + + SONiC-Inventec-d7054 + + + + + + Ethernet0 + 10.10.1.25/30 + + + + Ethernet4 + 10.10.2.25/30 + + + + + + + + + + + + 40000 + DeviceInterfaceLink + OCPSCH0104001MS + Ethernet24 + SONiC-Inventec-d7054 + Ethernet0 + + + 40000 + DeviceInterfaceLink + OCPSCH0104002MS + Ethernet24 + SONiC-Inventec-d7054 + Ethernet4 + + + + + SONiC-Inventec-d7054 + INVENTEC-D7054Q28B-S48-Q6 + + + + + + + SONiC-Inventec-d7054 + + + DhcpResources + + + + + NtpResources + + 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org + + + SyslogResources + + + + + + + + + SONiC-Inventec-d7054 + INVENTEC-D7054Q28B-S48-Q6 +
diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py new file mode 100644 index 000000000000..de5c24ba0e6d --- /dev/null +++ b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/eeprom.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +############################################################################# +# Inventec d7032q28b +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0053/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py new file mode 100755 index 000000000000..c2edefd2eb70 --- /dev/null +++ b/device/inventec/x86_64-inventec_d7054q28b-r0/plugins/sfputil.py @@ -0,0 +1,209 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 0 + PORT_END = 53 + PORTS_IN_BLOCK = 54 + QSFP_PORT_START = 48 + QSFP_PORT_END = 53 + + _port_to_eeprom_mapping = {} + port_to_i2c_mapping = { + 0: 11, + 1: 10, + 2: 13, + 3: 12, + 4: 15, + 5: 14, + 6: 17, + 7: 16, + 8: 19, + 9: 18, + 10: 21, + 11: 20, + 12: 23, + 13: 22, + 14: 25, + 15: 24, + 16: 27, + 17: 26, + 18: 29, + 19: 28, + 20: 31, + 21: 30, + 22: 33, + 23: 32, + 24: 35, + 25: 34, + 26: 37, + 27: 36, + 28: 39, + 29: 38, + 30: 41, + 31: 40, + 32: 43, + 33: 42, + 34: 45, + 35: 44, + 36: 47, + 37: 46, + 38: 49, + 39: 48, + 40: 51, + 41: 50, + 42: 53, + 43: 52, + 44: 55, + 45: 54, + 46: 57, + 47: 56, + 48: 59, + 49: 58, + 50: 61, + 51: 60, + 52: 63, + 53: 62 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = "/sys/bus/i2c/devices/{0}-0050/eeprom" + + for x in range(0, self.port_end + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/swps/port"+str(port_num)+"/present") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = int(reg_file.readline().rstrip()) + + if reg_value == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + + reg_value = int(reg_file.readline().rstrip()) + + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + print "\nError:SFP's don't support this property" + return False + + try: + reg_file = open("/sys/class/swps/port"+str(port_num)+"/lpmod", "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = int(reg_file.readline().rstrip()) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def reset(self, port_num): + QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/class/swps/port"+str(port_num)+"/reset" + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + print "\nError:SFP's don't support this property" + return False + + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + + return True diff --git a/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py index db71cb423503..0d7870b785fa 100644 --- a/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2410-r0/plugins/sfputil.py @@ -46,8 +46,23 @@ def __init__(self): SfpUtilBase.__init__(self) def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False - raise NotImplementedError + try: + reg_file = open("/bsp/qsfp/qsfp%d_status" % (port_num+1)) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string with the qsfp status + if content == "good": + return True + + return False def get_low_power_mode(self, port_num): diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py index b746af219917..b768cc44022d 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/plugins/sfputil.py @@ -46,8 +46,23 @@ def __init__(self): SfpUtilBase.__init__(self) def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False - raise NotImplementedError + try: + reg_file = open("/bsp/qsfp/qsfp%d_status" % (port_num+1)) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string with the qsfp status + if content == "good": + return True + + return False def get_low_power_mode(self, port_num): diff --git a/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py b/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py index b746af219917..b768cc44022d 100644 --- a/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py +++ b/device/mellanox/x86_64-mlnx_msn2740-r0/plugins/sfputil.py @@ -46,8 +46,23 @@ def __init__(self): SfpUtilBase.__init__(self) def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False - raise NotImplementedError + try: + reg_file = open("/bsp/qsfp/qsfp%d_status" % (port_num+1)) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = reg_file.readline().rstrip() + + # content is a string with the qsfp status + if content == "good": + return True + + return False def get_low_power_mode(self, port_num): diff --git a/dockers/docker-dhcp-relay/Dockerfile.j2 b/dockers/docker-dhcp-relay/Dockerfile.j2 index 3c6614c4921f..2c2bdcaecbf7 100644 --- a/dockers/docker-dhcp-relay/Dockerfile.j2 +++ b/dockers/docker-dhcp-relay/Dockerfile.j2 @@ -22,9 +22,7 @@ RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y RUN rm -rf /debs -COPY ["start.sh", "isc-dhcp-relay.sh", "/usr/bin/"] -COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] -COPY ["isc-dhcp-relay.j2", "/usr/share/sonic/templates/"] -COPY ["wait_for_intf.sh.j2", "/usr/share/sonic/templates/"] +COPY ["docker_init.sh", "start.sh", "/usr/bin/"] +COPY ["docker-dhcp-relay.supervisord.conf.j2", "wait_for_intf.sh.j2", "/usr/share/sonic/templates/"] -ENTRYPOINT ["/usr/bin/supervisord"] +ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 new file mode 100644 index 000000000000..747f65a3aaf6 --- /dev/null +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -0,0 +1,67 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[program:start.sh] +command=/usr/bin/start.sh +priority=1 +autostart=true +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n +priority=2 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +{# If our configuration has VLANs... #} +{% if VLAN %} +{# Count how many VLANs require a DHCP relay agent... #} +{% set num_relays = { 'count': 0 } %} +{% for vlan_name in VLAN %} +{% if VLAN[vlan_name]['dhcp_servers'] %} +{% set _dummy = num_relays.update({'count': num_relays.count + 1}) %} +{% endif %} +{% endfor %} +{# If one or more of the VLANs require a DHCP relay agent... #} +{% if num_relays.count > 0 %} +[group:isc-dhcp-relay] +programs= +{%- set add_preceding_comma = { 'flag': False } -%} +{%- for vlan_name in VLAN -%} +{%- if VLAN[vlan_name]['dhcp_servers'] -%} +{%- if add_preceding_comma.flag %},{% endif -%} +{%- set _dummy = add_preceding_comma.update({'flag': True}) -%} +isc-dhcp-relay-{{ vlan_name }} +{%- endif %} +{% endfor %} + + +{# Create a program entry for each DHCP relay agent instance #} +{% for vlan_name in VLAN -%} +{%- if VLAN[vlan_name]['dhcp_servers'] -%} +[program:isc-dhcp-relay-{{ vlan_name }}] +command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -i {{ vlan_name }} +{%- for (name, prefix) in INTERFACE -%} +{%- if prefix | ipv4 %} -i {{ name }}{% endif -%} +{%- endfor -%} +{%- for (name, prefix) in PORTCHANNEL_INTERFACE -%} +{%- if prefix | ipv4 %} -i {{ name }}{% endif -%} +{%- endfor -%} +{%- for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %} + +priority=3 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +{% endif %} +{% endfor %} +{% endif %} +{% endif %} diff --git a/dockers/docker-dhcp-relay/docker_init.sh b/dockers/docker-dhcp-relay/docker_init.sh new file mode 100755 index 000000000000..f6d402e6f780 --- /dev/null +++ b/dockers/docker-dhcp-relay/docker_init.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Generate supervisord config file +mkdir -p /etc/supervisor/conf.d/ +sonic-cfggen -d -t /usr/share/sonic/templates/docker-dhcp-relay.supervisord.conf.j2 > /etc/supervisor/conf.d/docker-dhcp-relay.supervisord.conf + +# Generate the script that waits for all interfaces to come up and make it executable +sonic-cfggen -d -t /usr/share/sonic/templates/wait_for_intf.sh.j2 > /usr/bin/wait_for_intf.sh +chmod +x /usr/bin/wait_for_intf.sh + +# Generate port name-alias map for isc-dhcp-relay to parse. Each line contains one +# name-alias pair of the form " " +sonic-cfggen -d --var-json "PORT" | python -c "import sys, json, os; [sys.stdout.write('%s %s\n' % (k, v['alias'] if 'alias' in v else k)) for (k, v) in json.load(sys.stdin).iteritems()]" > /tmp/port-name-alias-map.txt + +# The docker container should start this script as PID 1, so now that supervisord is +# properly configured, we exec supervisord so that it runs as PID 1 for the +# duration of the container's lifetime +exec /usr/bin/supervisord diff --git a/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 b/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 deleted file mode 100644 index cdedfcf9692b..000000000000 --- a/dockers/docker-dhcp-relay/isc-dhcp-relay.j2 +++ /dev/null @@ -1,28 +0,0 @@ -SERVERS="{{ DHCP_SERVER | join(' ') }}" - -INTERFACES=" -{%- set add_preceding_space = { 'flag': False } %} -{%- for (name, prefix) in INTERFACE %} -{%- if prefix | ipv4 %} -{%- if add_preceding_space.flag %} {% endif %} -{{ name }} -{%- set _dummy = add_preceding_space.update({'flag': True}) %} -{%- endif %} -{%- endfor %} -{%- for (name, prefix) in VLAN_INTERFACE %} -{%- if prefix | ipv4 %} -{%- if add_preceding_space.flag %} {% endif %} -{{ name }} -{%- set _dummy = add_preceding_space.update({'flag': True}) %} -{%- endif %} -{%- endfor %} -{%- for (name, prefix) in PORTCHANNEL_INTERFACE %} -{%- if prefix | ipv4 %} -{%- if add_preceding_space.flag %} {% endif %} -{{ name }} -{%- set _dummy = add_preceding_space.update({'flag': True}) %} -{%- endif %} -{%- endfor %}" - -# '-a' option provides option 82 circuit_id and remote_id information -OPTIONS="-a %h:%p %P" diff --git a/dockers/docker-dhcp-relay/isc-dhcp-relay.sh b/dockers/docker-dhcp-relay/isc-dhcp-relay.sh deleted file mode 100755 index 2224b8a0fe00..000000000000 --- a/dockers/docker-dhcp-relay/isc-dhcp-relay.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# -# Based off /etc/init.d/isc-dhcp-relay -# - -# Read init script configuration (interfaces the daemon should listen on -# and the DHCP server we should forward requests to.) -[ -f /etc/default/isc-dhcp-relay ] && . /etc/default/isc-dhcp-relay - -# Build command line for interfaces (will be passed to dhrelay below.) -IFCMD="" -if test "$INTERFACES" != ""; then - for I in $INTERFACES; do - IFCMD=${IFCMD}"-i "${I}" " - done -fi - -exec /usr/sbin/dhcrelay -d -q ${OPTIONS} ${IFCMD} ${SERVERS} diff --git a/dockers/docker-dhcp-relay/start.sh b/dockers/docker-dhcp-relay/start.sh index 37c3f488a5c7..b53d7e4e238a 100755 --- a/dockers/docker-dhcp-relay/start.sh +++ b/dockers/docker-dhcp-relay/start.sh @@ -1,16 +1,13 @@ #!/usr/bin/env bash -# Create isc-dhcp-relay config file -sonic-cfggen -d -t /usr/share/sonic/templates/isc-dhcp-relay.j2 > /etc/default/isc-dhcp-relay - +# Remove stale rsyslog PID file if it exists rm -f /var/run/rsyslogd.pid +# Start rsyslog supervisorctl start rsyslogd -# Wait for all interfaces to come up before starting the DHCP relay -sonic-cfggen -d -t /usr/share/sonic/templates/wait_for_intf.sh.j2 > /usr/bin/wait_for_intf.sh -chmod +x /usr/bin/wait_for_intf.sh +# Wait for all interfaces to come up before starting the DHCP relay agent(s) /usr/bin/wait_for_intf.sh -# Start the DHCP relay -supervisorctl start isc-dhcp-relay +# Start the DHCP relay agent(s) +supervisorctl start isc-dhcp-relay:* diff --git a/dockers/docker-dhcp-relay/supervisord.conf b/dockers/docker-dhcp-relay/supervisord.conf deleted file mode 100644 index ed1f75d1aed6..000000000000 --- a/dockers/docker-dhcp-relay/supervisord.conf +++ /dev/null @@ -1,28 +0,0 @@ -[supervisord] -logfile_maxbytes=1MB -logfile_backups=2 -nodaemon=true - -[program:start.sh] -command=/usr/bin/start.sh -priority=1 -autostart=true -autorestart=false -stdout_logfile=syslog -stderr_logfile=syslog - -[program:rsyslogd] -command=/usr/sbin/rsyslogd -n -priority=2 -autostart=false -autorestart=false -stdout_logfile=syslog -stderr_logfile=syslog - -[program:isc-dhcp-relay] -command=/usr/bin/isc-dhcp-relay.sh -priority=3 -autostart=false -autorestart=false -stdout_logfile=syslog -stderr_logfile=syslog diff --git a/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 b/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 old mode 100755 new mode 100644 index b859a43b07b1..1524b3221312 --- a/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 +++ b/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 @@ -25,4 +25,3 @@ wait_until_iface_exists {{ name }} {% for (name, prefix) in PORTCHANNEL_INTERFACE %} wait_until_iface_exists {{ name }} {% endfor %} - diff --git a/dockers/docker-fpm-quagga/bgpd.conf.j2 b/dockers/docker-fpm-quagga/bgpd.conf.j2 index 0ef144016246..bd8de7e4ba15 100644 --- a/dockers/docker-fpm-quagga/bgpd.conf.j2 +++ b/dockers/docker-fpm-quagga/bgpd.conf.j2 @@ -32,18 +32,17 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} bgp graceful-restart {% endif %} {% for (name, prefix) in LOOPBACK_INTERFACE %} -{# TODO: use v4 lo for backward compatibility, will revisit the case with multiple lo interfaces #} -{% if prefix | ipv4 %} +{% if prefix | ipv4 and name == 'Loopback0' %} bgp router-id {{ prefix | ip }} {% endif %} {% endfor %} {# advertise loopback #} {% for (name, prefix) in LOOPBACK_INTERFACE %} -{% if prefix | ipv4 %} +{% if prefix | ipv4 and name == 'Loopback0' %} network {{ prefix | ip }}/32 -{% elif prefix | ipv6 %} +{% elif prefix | ipv6 and name == 'Loopback0' %} address-family ipv6 - network {{ prefix | ip }}/128 + network {{ prefix | ip }}/64 exit-address-family {% endif %} {% endfor %} @@ -97,7 +96,11 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }} neighbor {{ bgp_peer['name'] }} remote-as {{ deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']] }} neighbor {{ bgp_peer['name'] }} ebgp-multihop 255 neighbor {{ bgp_peer['name'] }} soft-reconfiguration inbound - neighbor {{ bgp_peer['name'] }} update-source Loopback0 +{% for (name, prefix) in LOOPBACK_INTERFACE %} +{% if name == 'Loopback1' %} + neighbor {{ bgp_peer['name'] }} update-source {{ prefix | ip }} +{% endif %} +{% endfor %} neighbor {{ bgp_peer['name'] }} route-map FROM_BGP_SPEAKER_V4 in neighbor {{ bgp_peer['name'] }} route-map TO_BGP_SPEAKER_V4 out {% for ip_range in bgp_peer['ip_range'] %} diff --git a/dockers/docker-lldp-sv2/Dockerfile.j2 b/dockers/docker-lldp-sv2/Dockerfile.j2 index 158d5b52ffe7..bfb1f9ca678a 100644 --- a/dockers/docker-lldp-sv2/Dockerfile.j2 +++ b/dockers/docker-lldp-sv2/Dockerfile.j2 @@ -30,7 +30,7 @@ RUN pip install /python-wheels/swsssdk-2.0.1-py2-none-any.whl && \ COPY ["start.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] -COPY ["reconfigure.sh", "/opt/"] +COPY ["reconfigure.sh", "/usr/bin/"] COPY ["lldpd.conf.j2", "/usr/share/sonic/templates/"] COPY ["lldpd", "/etc/default/"] diff --git a/dockers/docker-lldp-sv2/reconfigure.sh b/dockers/docker-lldp-sv2/reconfigure.sh index 9f42a33a24b4..515e771aa6f2 100755 --- a/dockers/docker-lldp-sv2/reconfigure.sh +++ b/dockers/docker-lldp-sv2/reconfigure.sh @@ -2,9 +2,8 @@ set -e -num_of_interfaces=32 -if_step=4 -last_if_idx=$((num_of_interfaces*if_step - if_step)) +# TODO: Listen to state database when it is ready +interfaces=$(sonic-cfggen -d -v "PORT.keys() | join(' ')") function wait_until_if_exists { @@ -31,23 +30,23 @@ function wait_until_if_not_exists while /bin/true ; do # wait until all interfaces are created - echo Wait until all ifaces are created - for i in $(seq 0 $if_step $last_if_idx) + echo Wait until all interfaces are created + for i in $interfaces do - wait_until_if_exists "Ethernet$i" + wait_until_if_exists $i done echo Wait 10 seconds while lldpd finds new interfaces sleep 10 # apply lldpd configuration - echo apply lldpd configuration + echo Apply lldpd configuration lldpcli -c /etc/lldpd.conf # wait until all interfaces are destroyed echo Wait until all ifaces are destroyed - for i in $(seq 0 $if_step $last_if_idx) + for i in $interfaces do - wait_until_if_not_exists "Ethernet$i" + wait_until_if_not_exists $i done done diff --git a/dockers/docker-lldp-sv2/supervisord.conf b/dockers/docker-lldp-sv2/supervisord.conf index 505b72d18227..ab62d9ed2e87 100644 --- a/dockers/docker-lldp-sv2/supervisord.conf +++ b/dockers/docker-lldp-sv2/supervisord.conf @@ -33,7 +33,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:lldpd-conf-reload] -command=/opt/reconfigure.sh +command=/usr/bin/reconfigure.sh priority=150 autostart=false autorestart=false diff --git a/dockers/docker-lldp/Dockerfile b/dockers/docker-lldp/Dockerfile deleted file mode 100644 index 595c41bcd85e..000000000000 --- a/dockers/docker-lldp/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM docker-base - -COPY deps/swsssdk*.whl deps/lldpsyncd_*.deb deps/lldpd_*.deb /deps/ - -# Make apt-get non-interactive -ENV DEBIAN_FRONTEND=noninteractive - -# Pre-install the fundamental packages -# Install Python SwSS SDK (lldpsyncd dependency) -# Install LLDP Sync Daemon -# Note: dpkg_apt function has the benefit to detect missing .deb file -# Clean up -RUN apt-get update && \ - dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } && \ - dpkg_apt /deps/lldpd_*.deb && \ - dpkg_apt /deps/lldpsyncd_*.deb && \ - apt-get install -y python-pip supervisor && \ - pip install /deps/swsssdk*.whl && \ - apt-get remove -y python-pip && \ - apt-get purge -y && apt-get autoclean -y && apt-get autoremove -y && \ - rm -rf /deps ~/.cache - -COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf - -ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-lldp/supervisord.conf b/dockers/docker-lldp/supervisord.conf deleted file mode 100644 index faff70ed06fa..000000000000 --- a/dockers/docker-lldp/supervisord.conf +++ /dev/null @@ -1,19 +0,0 @@ -[supervisord] -nodaemon=true - -[program:lldpd] -# https://github.com/vincentbernat/lldpd/commit/9856f2792c301116cc4a3fcfba91b9672ee5db1f -# - `-d` means to stay in foreground, log to syslog -# - `-dd` means to stay in foreground, log warnings to console -# - `-ddd` means to stay in foreground, log warnings and info to console -# - `-dddd` means to stay in foreground, log all to console -command=/usr/sbin/lldpd -d -I Ethernet*,eth* -priority=100 - -[program:lldpsyncd] -command=/usr/sbin/lldpsyncd -priority=200 - -[program:rsyslogd] -command=/usr/sbin/rsyslogd -n -priority=1 diff --git a/dockers/docker-mlnx-sswsyncd-rpc/Dockerfile b/dockers/docker-mlnx-sswsyncd-rpc/Dockerfile deleted file mode 100644 index 4d1b3e49bcda..000000000000 --- a/dockers/docker-mlnx-sswsyncd-rpc/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM docker-base - -## Make apt-get non-interactive -ENV DEBIAN_FRONTEND=noninteractive - -## Pre-install the fundamental packages -RUN apt-get update \ - && apt-get -y install \ - net-tools - -COPY deps /deps -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; \ - dpkg_apt /deps/python-tabulate_*.deb \ - && dpkg_apt /deps/applibs_*.deb \ - && dpkg_apt /deps/applibs-dev_*.deb \ - && dpkg_apt /deps/sx-complib_*.deb \ - && dpkg_apt /deps/sxd-libs_*.deb \ - && dpkg_apt /deps/sx-scew_*.deb \ - && dpkg_apt /deps/sx-examples_*.deb \ - && dpkg_apt /deps/sx-gen-utils_*.deb \ - && dpkg_apt /deps/python-sdk-api_*.deb \ - && dpkg_apt /deps/sx-libnl_*.deb \ - && dpkg_apt /deps/iproute2_*.deb \ - && dpkg_apt /deps/libsswsdk_*.deb \ - && dpkg_apt /deps/libthrift-0.9.3_*.deb \ - && dpkg_apt /deps/libthrift-dev_*.deb - -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; \ - dpkg_apt /deps/mlnx-sai_*.deb \ - && dpkg_apt /deps/sswsyncd-saithrift_*.deb - -## Clean up -RUN apt-get clean -y ; apt-get autoclean -y ; apt-get autoremove -y ; rm -rf /deps - -ENTRYPOINT service rsyslog start \ - && mkdir -p /dev/sxdevs && ( [ -e /dev/sxdevs/sxcdev ] || mknod /dev/sxdevs/sxcdev c 231 193 ) \ - && service sswsyncd start \ - && /bin/bash diff --git a/dockers/docker-mlnx-sswsyncd/Dockerfile b/dockers/docker-mlnx-sswsyncd/Dockerfile deleted file mode 100755 index 631ff2e18030..000000000000 --- a/dockers/docker-mlnx-sswsyncd/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM docker-base - -## Make apt-get non-interactive -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update - -## Pre-install the fundamental packages -RUN apt-get update \ - && apt-get -y install \ - net-tools - -COPY deps /deps -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/python-tabulate_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/applibs_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/applibs-dev_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sx-complib_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sxd-libs_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sx-scew_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sx-examples_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sx-gen-utils_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/python-sdk-api_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sx-libnl_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/iproute2_*.deb - -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/mlnx-sai_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/libsswsdk_*.deb -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /deps/sswsyncd_*.deb - -ENTRYPOINT service rsyslog start \ - && mkdir -p /dev/sxdevs && ( [ -e /dev/sxdevs/sxcdev ] || mknod /dev/sxdevs/sxcdev c 231 193 ) \ - && sleep 5 && service sswsyncd start \ - && /bin/bash diff --git a/dockers/docker-orchagent/Dockerfile.j2 b/dockers/docker-orchagent/Dockerfile.j2 index 587d8f4db2ee..9fba8d17b9d6 100755 --- a/dockers/docker-orchagent/Dockerfile.j2 +++ b/dockers/docker-orchagent/Dockerfile.j2 @@ -28,8 +28,8 @@ RUN rm -rf /debs COPY ["arp_update", "start.sh", "orchagent.sh", "swssconfig.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] -COPY ["ipinip.json.j2", "/usr/share/sonic/templates/"] -COPY ["mirror.json.j2", "/usr/share/sonic/templates/"] -COPY ["ports.json.j2", "/usr/share/sonic/templates/"] + +## Copy all Jinja2 template files into the templates folder +COPY ["*.j2", "/usr/share/sonic/templates/"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-orchagent/mirror.json.j2 b/dockers/docker-orchagent/mirror.json.j2 deleted file mode 100644 index 3a3fc6eed079..000000000000 --- a/dockers/docker-orchagent/mirror.json.j2 +++ /dev/null @@ -1,24 +0,0 @@ -[ -{% if MIRROR_SESSION %} -{% for session in MIRROR_SESSION %} - { - "MIRROR_SESSION_TABLE:{{session}}": { - "src_ip": "{{ MIRROR_SESSION[session]['src_ip'] }}", - "dst_ip": "{{ MIRROR_SESSION[session]['dst_ip'] }}", -{% if onie_switch_asic == "mlnx" %} - "gre_type": "0x6558", - "queue": "1", -{% else %} - "gre_type": "0x88be", - "queue": "0", -{% endif %} - "dscp": "8", - "ttl": "255" - }, - "OP": "SET" - }{% if not loop.last %},{% endif %} - -{% endfor %} -{% endif %} -] - diff --git a/dockers/docker-orchagent/msn27xx.32ports.buffers.json.j2 b/dockers/docker-orchagent/msn27xx.32ports.buffers.json.j2 new file mode 100644 index 000000000000..ce1ddedbba37 --- /dev/null +++ b/dockers/docker-orchagent/msn27xx.32ports.buffers.json.j2 @@ -0,0 +1,287 @@ +[ +{% set port_names_list = [] %} +{% for port in PORT %} + {%- if port_names_list.append(port) %}{% endif %} +{% endfor %} +{% set port_names = port_names_list | join(',') %} + { + "BUFFER_POOL_TABLE:ingress_lossy_pool": { + "size": "6422528", + "type": "ingress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:egress_lossless_pool": { + "size": "7291456", + "type": "egress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:egress_lossy_pool": { + "size": "8254464", + "type": "egress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:ingress_lossless_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:ingress_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossy_pool]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:egress_lossless_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossless_pool]", + "size":"1518", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:egress_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossy_pool]", + "size":"4096", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:pg_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:q_lossless_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:q_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossy_pool]", + "size":"0", + "dynamic_th":"1" + }, + "OP": "SET" + }, + { + "BUFFER_PORT_INGRESS_PROFILE_LIST:{{ port_names }}": { + "profile_list" : "[BUFFER_PROFILE_TABLE:ingress_lossless_profile],[BUFFER_PROFILE_TABLE:ingress_lossy_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PORT_EGRESS_PROFILE_LIST:{{ port_names }}": { + "profile_list" : "[BUFFER_PROFILE_TABLE:egress_lossless_profile],[BUFFER_PROFILE_TABLE:egress_lossy_profile]" + }, + "OP": "SET" + }, + +{# The following template part is for variable PG profile configuration #} +{% set non_pg_lossless_pool_size = 866726 %} +{% set pg_range = '3-4' %} +{# Lists of supported speed and cable length #} +{% set supported_speed = [10000, 25000, 40000, 50000, 100000] %} +{% set supported_cable = [5, 40, 300] %} + +{# The key in this lictionary consist of two parts: (port speed)_(cable length) #} +{%- set portconfig2profile = { + '10000_5' : 'pg_lossless_10G_5m_profile', + '25000_5' : 'pg_lossless_25G_5m_profile', + '40000_5' : 'pg_lossless_40G_5m_profile', + '50000_5' : 'pg_lossless_50G_5m_profile', + '100000_5' : 'pg_lossless_100G_5m_profile', + + '10000_40' : 'pg_lossless_10G_40m_profile', + '25000_40' : 'pg_lossless_25G_40m_profile', + '40000_40' : 'pg_lossless_40G_40m_profile', + '50000_40' : 'pg_lossless_50G_40m_profile', + '100000_40' : 'pg_lossless_100G_40m_profile', + + '10000_300' : 'pg_lossless_10G_300m_profile', + '25000_300' : 'pg_lossless_25G_300m_profile', + '40000_300' : 'pg_lossless_40G_300m_profile', + '50000_300' : 'pg_lossless_50G_300m_profile', + '100000_300': 'pg_lossless_100G_300m_profile' + } +-%} + +{# PG profiles. All profiles reffered in portconfig2profile dictionary should be declared here #} +{# Only those which were actually used will be created in SAI #} +{%- set pg_profiles = { + 'pg_lossless_10G_5m_profile': { 'xon': 18432, 'xoff': 16384, 'size': 34816, 'dynamic_th': 1 }, + 'pg_lossless_25G_5m_profile': { 'xon': 18432, 'xoff': 16384, 'size': 34816, 'dynamic_th': 1 }, + 'pg_lossless_40G_5m_profile': { 'xon': 18432, 'xoff': 16384, 'size': 34816, 'dynamic_th': 1 }, + 'pg_lossless_50G_5m_profile': { 'xon': 18432, 'xoff': 16384, 'size': 34816, 'dynamic_th': 1 }, + 'pg_lossless_100G_5m_profile': { 'xon': 18432, 'xoff': 18432, 'size': 36864, 'dynamic_th': 1 }, + + 'pg_lossless_10G_40m_profile': { 'xon': 18432, 'xoff': 18432, 'size': 36864, 'dynamic_th': 1 }, + 'pg_lossless_25G_40m_profile': { 'xon': 18432, 'xoff': 21504, 'size': 39936, 'dynamic_th': 1 }, + 'pg_lossless_40G_40m_profile': { 'xon': 18432, 'xoff': 23552, 'size': 41984, 'dynamic_th': 1 }, + 'pg_lossless_50G_40m_profile': { 'xon': 18432, 'xoff': 23552, 'size': 41984, 'dynamic_th': 1 }, + 'pg_lossless_100G_40m_profile': { 'xon': 18432, 'xoff': 35840, 'size': 54272, 'dynamic_th': 1 }, + + 'pg_lossless_10G_300m_profile': { 'xon': 18432, 'xoff': 30720, 'size': 49152, 'dynamic_th': 1 }, + 'pg_lossless_25G_300m_profile': { 'xon': 18432, 'xoff': 53248, 'size': 71680, 'dynamic_th': 1 }, + 'pg_lossless_40G_300m_profile': { 'xon': 18432, 'xoff': 75776, 'size': 94208, 'dynamic_th': 1 }, + 'pg_lossless_50G_300m_profile': { 'xon': 18432, 'xoff': 75776, 'size': 94208, 'dynamic_th': 1 }, + 'pg_lossless_100G_300m_profile':{ 'xon': 18432, 'xoff': 165888,'size': 184320,'dynamic_th': 1 }, + } +-%} + +{# Port configuration to cable length look-up table #} +{# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #} +{# Roles described in the minigraph #} +{% set ports2cable = { + 'ToRRouter_Server' : '5', + 'LeafRouter_ToRRouter' : '40', + 'SpineRouter_LeafRouter' : '300' + } +%} + +{% set switch_role = DEVICE_METADATA['localhost']['type'] %} + +{%- macro cable_length(port_name) -%} + {%- set cable_len = [] -%} + {%- for local_port in DEVICE_NEIGHBOR -%} + {%- if local_port == port_name -%} + {%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} + {%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} + {%- set neighbor_role = neighbor.type -%} + {%- set roles1 = switch_role + '_' + neighbor_role %} + {%- set roles2 = neighbor_role + '_' + switch_role -%} + {%- if roles1 in ports2cable -%} + {%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%} + {%- elif roles2 in ports2cable -%} + {%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%} + {%- endif -%} + {% endif %} + {% endif %} + {%- endfor -%} + {%- if cable_len -%} + {{ cable_len.0 }} + {%- else -%} + {{ supported_cable | last }} + {%- endif -%} +{% endmacro %} + +{%- macro find_closest_greater_config(speed, cable) -%} +{%- set new_speed = [] -%} +{%- for std_speed in supported_speed -%} + {%- if std_speed | int >= speed | int -%} + {%- if new_speed.append(std_speed) -%}{%- endif -%} + {% endif -%} +{%- endfor -%} +{%- set new_cable = [] -%} +{%- for std_cable in supported_cable -%} + {% if std_cable | int >= cable | int -%} + {%- if new_cable.append(std_cable) -%}{%- endif -%} + {% endif %} +{%- endfor -%} +{{ new_speed.0 }}_{{ new_cable.0 }} +{%- endmacro -%} + +{% set ingress_lossless_pg_pool_size = [] %} +{% set used_pg_profiles = [] %} +{% for port in PORT %} + {%- if PORT[port].speed -%} + {%- set speed = PORT[port]['speed'] -%} + {% else %} + {%- set speed = supported_speed|last -%} + {%- endif -%} + {%- set cable = cable_length(port) -%} + {%- set port_config = speed|string + '_' + cable -%} + {%- if not port_config in portconfig2profile -%} + {% set port_config = find_closest_greater_config(speed, cable) -%} + {%- endif -%} + {% set profile = portconfig2profile[port_config] -%} + {% if ingress_lossless_pg_pool_size.append(pg_profiles[profile]['size']) %}{% endif %} + {# add to list profiles which were actually used #} + {%- if profile not in used_pg_profiles and used_pg_profiles.append(profile) %}{% endif -%} + { + "BUFFER_PG_TABLE:{{ port }}:{{ pg_range }}": { + "profile" : "[BUFFER_PROFILE_TABLE:{{ profile }}]" + }, + "OP": "SET" + }, +{% endfor -%} + +{# PG profiles declaration #} + +{% for profile_name in used_pg_profiles %} + {%- set profile_config = pg_profiles[profile_name] %} + { + "BUFFER_PROFILE_TABLE:{{ profile_name }}": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossless_pool]", + "xon":"{{ profile_config['xon'] }}", + "xoff":"{{ profile_config['xoff'] }}", + "size":"{{ profile_config['size'] }}", + "dynamic_th":"{{ profile_config['dynamic_th'] }}" + }, + "OP": "SET" + }, +{% endfor -%} + + {# Lossless pool declaration #} + { + "BUFFER_POOL_TABLE:ingress_lossless_pool": { + "size": "{{ ingress_lossless_pg_pool_size | sum + non_pg_lossless_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:{{ port_names }}:0-1": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossy_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:{{ port_names }}:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:q_lossless_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:{{ port_names }}:0-1": { + "profile" : "[BUFFER_PROFILE_TABLE:q_lossy_profile]" + }, + "OP": "SET" + }, + { + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE:AZURE": { + "0": "0", + "1": "1", + "3": "3", + "4": "4" + }, + "OP": "SET" + }, + { + "PORT_QOS_MAP_TABLE:{{ port_names }}": { + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE:AZURE]" + }, + "OP": "SET" + } +] diff --git a/dockers/docker-orchagent/orchagent.sh b/dockers/docker-orchagent/orchagent.sh index 7103afcb81e9..f92dfe5fd543 100755 --- a/dockers/docker-orchagent/orchagent.sh +++ b/dockers/docker-orchagent/orchagent.sh @@ -2,9 +2,7 @@ # Export platform information. Required to be able to write # vendor specific code. -export platform=`sonic-cfggen -v onie_switch_asic` - -ASIC=`sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type` +export platform=`sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type` MAC_ADDRESS=`ip link show eth0 | grep ether | awk '{print $2}'` @@ -16,9 +14,9 @@ ORCHAGENT_ARGS="-d /var/log/swss " ORCHAGENT_ARGS+="-b 8192 " # Add platform specific arguments if necessary -if [ "$ASIC" == "broadcom" ]; then +if [ "$platform" == "broadcom" ]; then ORCHAGENT_ARGS+="-m $MAC_ADDRESS" -elif [ "$ASIC" == "cavium" ]; then +elif [ "$platform" == "cavium" ]; then ORCHAGENT_ARGS+="-m $MAC_ADDRESS" fi diff --git a/dockers/docker-orchagent/start.sh b/dockers/docker-orchagent/start.sh index 0931321a9436..9f3ba3cb078d 100755 --- a/dockers/docker-orchagent/start.sh +++ b/dockers/docker-orchagent/start.sh @@ -2,8 +2,8 @@ mkdir -p /etc/swss/config.d/ +sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/switch.json.j2 > /etc/swss/config.d/switch.json sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json -sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/mirror.json.j2 > /etc/swss/config.d/mirror.json sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json export platform=`sonic-cfggen -v platform` @@ -22,6 +22,10 @@ supervisorctl start neighsyncd supervisorctl start swssconfig +supervisorctl start vlanmgrd + +supervisorctl start intfmgrd + # Start arp_update when VLAN exists VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'` if [ "$VLAN" != "" ]; then diff --git a/dockers/docker-orchagent/supervisord.conf b/dockers/docker-orchagent/supervisord.conf index 09850b13d4a1..95e92be622bb 100644 --- a/dockers/docker-orchagent/supervisord.conf +++ b/dockers/docker-orchagent/supervisord.conf @@ -67,3 +67,19 @@ autostart=false autorestart=true stdout_logfile=syslog stderr_logfile=syslog + +[program:vlanmgrd] +command=/usr/bin/vlanmgrd +priority=9 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:intfmgrd] +command=/usr/bin/intfmgrd +priority=10 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog diff --git a/dockers/docker-orchagent/switch.json.j2 b/dockers/docker-orchagent/switch.json.j2 new file mode 100644 index 000000000000..7a8c3522ecee --- /dev/null +++ b/dockers/docker-orchagent/switch.json.j2 @@ -0,0 +1,18 @@ +{# set default hash seed to 0 #} +{% set hash_seed = 0 %} +{% if DEVICE_METADATA.localhost.type %} +{% if DEVICE_METADATA.localhost.type == "ToRRouter" %} +{% set hash_seed = 10 %} +{% elif DEVICE_METADATA.localhost.type == "LeafRouter" %} +{% set hash_seed = 20 %} +{% endif %} +{% endif %} +[ + { + "SWITCH_TABLE:switch": { + "ecmp_hash_seed": "{{ hash_seed }}", + "lag_hash_seed": "{{ hash_seed }}" + }, + "OP": "SET" + } +] diff --git a/dockers/docker-orchagent/swssconfig.sh b/dockers/docker-orchagent/swssconfig.sh index 55a22c5353c8..3458ddae61e6 100755 --- a/dockers/docker-orchagent/swssconfig.sh +++ b/dockers/docker-orchagent/swssconfig.sh @@ -2,18 +2,6 @@ set -e -function config_acl { - if [ -f "/etc/sonic/acl.json" ]; then - mkdir -p /etc/swss/config.d/acl - rm -rf /etc/swss/config.d/acl/* - translate_acl -m /etc/sonic/minigraph.xml -o /etc/swss/config.d/acl /etc/sonic/acl.json - for filename in /etc/swss/config.d/acl/*.json; do - [ -e "$filename" ] || break - swssconfig $filename - done - fi -} - function fast_reboot { case "$(cat /proc/cmdline)" in *fast-reboot*) @@ -39,7 +27,7 @@ fast_reboot HWSKU=`sonic-cfggen -m /etc/sonic/minigraph.xml -d -v "DEVICE_METADATA['localhost']['hwsku']"` -SWSSCONFIG_ARGS="00-copp.config.json ipinip.json mirror.json ports.json " +SWSSCONFIG_ARGS="00-copp.config.json ipinip.json ports.json switch.json " if [ "$HWSKU" == "Force10-S6000" ]; then SWSSCONFIG_ARGS+="td2.32ports.buffers.json td2.32ports.qos.json " @@ -49,12 +37,10 @@ elif [ "$HWSKU" == "Arista-7050-QX32" ]; then SWSSCONFIG_ARGS+="td2.32ports.buffers.json td2.32ports.qos.json " elif [[ "$HWSKU" == "ACS-MSN27"* ]]; then sonic-cfggen -m /etc/sonic/minigraph.xml -t /usr/share/sonic/templates/msn27xx.32ports.buffers.json.j2 > /etc/swss/config.d/msn27xx.32ports.buffers.json - SWSSCONFIG_ARGS+="msn27xx.32ports.buffers.json msn2700.32ports.qos.json " + SWSSCONFIG_ARGS+="msn27xx.32ports.buffers.json msn27xx.32ports.qos.json " fi for file in $SWSSCONFIG_ARGS; do swssconfig /etc/swss/config.d/$file sleep 1 done - -config_acl diff --git a/dockers/docker-platform-monitor/lm-sensors.sh b/dockers/docker-platform-monitor/lm-sensors.sh index 61e90c09a8e3..2f4768a8cdda 100755 --- a/dockers/docker-platform-monitor/lm-sensors.sh +++ b/dockers/docker-platform-monitor/lm-sensors.sh @@ -3,7 +3,19 @@ # Based off /etc/init.d/lm-sensors # -/usr/bin/sensors -s > /dev/null 2>&1 + +# NOTE: lm-sensors v3.3.5 appears to have a bug. If `sensors -s` is called, it +# will first load /etc/sensors.conf, then load all files in /etc/sensors.d/, +# overriding any values that may have already been specified in +# /etc/sensors.conf. However, it appears this overriding is not taking place. +# As a workaround, as long as a platform-specific sensors.conf has been copied +# to /etc/sensors.d/, we will ONLY load that file, otherwise we load the default. +if [ -e /etc/sensors.d/sensors.conf ]; then + /usr/bin/sensors -s -c /etc/sensors.d/sensors.conf > /dev/null 2>&1 +else + /usr/bin/sensors -s > /dev/null 2>&1 +fi + /usr/bin/sensors > /dev/null 2>&1 # Currently, there is no way to run sensord in the foreground, so we diff --git a/dockers/docker-ptf/Dockerfile.j2 b/dockers/docker-ptf/Dockerfile.j2 index 1d1231d9418e..01312687b93c 100644 --- a/dockers/docker-ptf/Dockerfile.j2 +++ b/dockers/docker-ptf/Dockerfile.j2 @@ -40,6 +40,7 @@ RUN sed --in-place 's/httpredir.debian.org/debian-archive.trafficmanager.net/' / iputils-ping \ hping3 \ curl \ + tcpdump \ python \ python-dev \ python-scapy diff --git a/dockers/docker-snmp/Dockerfile b/dockers/docker-snmp/Dockerfile deleted file mode 100644 index 6a79db976adc..000000000000 --- a/dockers/docker-snmp/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM docker-base - -COPY deps/snmp_*.deb deps/snmpd_*.deb deps/libsnmp-base_*.deb deps/libsnmp30_*.deb /deps/ -COPY deps/python3/*.whl /python3/ - -# enable -O for all Python calls -ENV PYTHONOPTIMIZE 1 - -## Make apt-get non-interactive -ENV DEBIAN_FRONTEND=noninteractive - -## Pre-install the fundamental packages -## Install SNMP subagent -## Note: dpkg_apt function has the benefit to detect missing .deb file -## Clean up -RUN apt-get update && \ - dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } && \ - dpkg_apt /deps/libsnmp-base_*.deb && \ - dpkg_apt /deps/libsnmp30_*.deb && \ - dpkg_apt /deps/snmp_*.deb && \ - dpkg_apt /deps/snmpd_*.deb && \ - rm -rf /deps - -# install subagent -RUN apt-get -y install build-essential wget libssl-dev openssl supervisor && \ - rm -rf /var/lib/apt/lists/* && \ - wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgz && \ - tar xvf Python-3.5.2.tgz && cd Python-3.5.2 && \ - ./configure --without-doc-strings --prefix=/usr --without-pymalloc --enable-shared && \ - make && make install && \ - ldconfig && \ - cd .. && rm -rf Python-3.5.2 && rm Python-3.5.2.tgz && \ - pip3 install --no-cache-dir /python3/*py3*.whl hiredis && \ - rm -rf /python3 && \ - python3 -m acs_ax_impl install && \ - python3 -m pip uninstall -y pip setuptools && \ - /bin/bash -c "rm -rf /usr/lib/python3.5/{unittest,lib2to3,tkinter,idlelib,email,test}" && \ - apt-get -y purge build-essential wget libssl-dev openssl && \ - apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && \ - find / | grep -E "__pycache__" | xargs rm -rf && \ - rm -rf ~/.cache - -COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf - -## Although exposing ports is not need for host net mode, keep it for possible bridge mode -EXPOSE 161/udp 162/udp - -ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-snmp/supervisord.conf b/dockers/docker-snmp/supervisord.conf deleted file mode 100644 index c954add628d0..000000000000 --- a/dockers/docker-snmp/supervisord.conf +++ /dev/null @@ -1,14 +0,0 @@ -[supervisord] -nodaemon=true - -[program:snmpd] -command=/usr/sbin/snmpd -f -LS4d -u Debian-snmp -g Debian-snmp -I -smux,mteTrigger,mteTriggerConf,ifTable,ifXTable -p /run/snmpd.pid -priority=100 - -[program:acs-snmp-subagent] -command=/usr/bin/env python3 -m acs_ax_impl -priority=200 - -[program:rsyslogd] -command=/usr/sbin/rsyslogd -n -priority=1 diff --git a/dockers/docker-sswsyncd/Dockerfile b/dockers/docker-sswsyncd/Dockerfile deleted file mode 100755 index 0f555d8b51bf..000000000000 --- a/dockers/docker-sswsyncd/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM docker-base - -COPY \ - deps/python-tabulate_*.deb \ - deps/libopennsl_*.deb \ - deps/libsaibcm_*.deb \ - deps/libsswsdk_*.deb \ - deps/sswsyncd_*.deb \ - /deps/ - -## Make apt-get non-interactive -ENV DEBIAN_FRONTEND=noninteractive - -## Install packages -## Clean up -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } && \ - dpkg_apt /deps/python-tabulate_*.deb && \ - dpkg_apt /deps/libopennsl_*.deb && \ - dpkg_apt /deps/libsaibcm_*.deb && \ - dpkg_apt /deps/libsswsdk_*.deb && \ - dpkg_apt /deps/sswsyncd_*.deb && \ - apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && \ - rm -rf /deps - -ENTRYPOINT service rsyslog start \ - && service sswsyncd start \ - && /bin/bash diff --git a/dockers/docker-teamd/start.sh b/dockers/docker-teamd/start.sh index 6b0a3d785894..6e80f6eb9a83 100755 --- a/dockers/docker-teamd/start.sh +++ b/dockers/docker-teamd/start.sh @@ -17,6 +17,12 @@ fi for pc in `sonic-cfggen -d -v "PORTCHANNEL.keys() | join(' ') if PORTCHANNEL"`; do sonic-cfggen -d -a '{"pc":"'$pc'","hwaddr":"'$MAC_ADDRESS'"}' -t /usr/share/sonic/templates/teamd.j2 > $TEAMD_CONF_PATH/$pc.conf + # bring down all member ports before starting teamd + for member in $(sonic-cfggen -d -v "PORTCHANNEL['$pc']['members'] | join(' ')" ); do + if [ -L /sys/class/net/$member ]; then + ip link set $member down + fi + done done mkdir -p /var/sonic diff --git a/files/Aboot/boot0.j2 b/files/Aboot/boot0.j2 index b88c0ec35b39..8ea085bf5e8d 100644 --- a/files/Aboot/boot0.j2 +++ b/files/Aboot/boot0.j2 @@ -65,9 +65,6 @@ extract_image() { ## vfat does not support symbol link if [ -n "$sonic_upgrade" ] || [ "$rootfs_type" != "vfat" ]; then - ## on ext4, other doesn't have access to the flash by default - chmod o+rx "$target_path" - mkdir -p "$image_path/{{ DOCKERFS_DIR }}" if [ -n "$sonic_upgrade" ]; then diff --git a/files/build_templates/snmp.service.j2 b/files/build_templates/snmp.service.j2 index 493d6bd8fcfd..08c41a52a5f7 100644 --- a/files/build_templates/snmp.service.j2 +++ b/files/build_templates/snmp.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=SNMP container -Requires=database.service -After=database.service +Requires=database.service swss.service +After=database.service swss.service [Service] User={{ sonicadmin_user }} diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 04f5181ff610..37fcfbc56fcb 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -188,12 +188,20 @@ sudo dpkg --root=$FILESYSTEM_ROOT -P {{ debname }} sudo rm -f $FILESYSTEM_ROOT/usr/sbin/policy-rc.d +## Revise /etc/init.d/networking for Arista switches +if [ "$image_type" = "aboot" ]; then + sudo sed -i 's/udevadm settle/udevadm settle -E \/sys\/class\/net\/eth0/' $FILESYSTEM_ROOT/etc/init.d/networking +fi + ## copy platform rc.local sudo cp $IMAGE_CONFIGS/platform/rc.local $FILESYSTEM_ROOT/etc/ {% if installer_images.strip() -%} {% for image in installer_images.strip().split(' ') -%} +{% set imagefilename = image.split('/')|last -%} +{% set imagename = imagefilename.split('.')|first -%} sudo LANG=C chroot $FILESYSTEM_ROOT docker load < {{image}} +sudo LANG=C chroot $FILESYSTEM_ROOT docker tag {{imagename}}:latest {{imagename}}:$(sonic_get_version) {% endfor %} sudo chroot $FILESYSTEM_ROOT service docker stop {% for script in installer_start_scripts.split(' ') -%} diff --git a/files/build_templates/swss.service.j2 b/files/build_templates/swss.service.j2 index af922530d8a2..74fafb003767 100644 --- a/files/build_templates/swss.service.j2 +++ b/files/build_templates/swss.service.j2 @@ -17,6 +17,7 @@ ExecStartPre=/bin/bash -c "while true; do if [ \"$(/usr/bin/docker exec database ExecStartPre=/usr/bin/docker exec database redis-cli -n 0 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 1 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 2 FLUSHDB +ExecStartPre=/usr/bin/docker exec database redis-cli -n 5 FLUSHDB {% if sonic_asic_platform == 'mellanox' %} TimeoutStartSec=3min diff --git a/files/dhcp/graphserviceurl b/files/dhcp/graphserviceurl index f255cdff9877..5c5d801cbc8c 100644 --- a/files/dhcp/graphserviceurl +++ b/files/dhcp/graphserviceurl @@ -3,7 +3,7 @@ case $reason in if [ -n "$new_minigraph_url" ]; then echo $new_minigraph_url > /tmp/dhcp_graph_url else - echo "N/A" > /tmp/dhcp_graph_url + echo "default" > /tmp/dhcp_graph_url fi if [ -n "$new_acl_url" ]; then echo $new_acl_url > /tmp/dhcp_acl_url diff --git a/files/image_config/interfaces/interfaces-config.sh b/files/image_config/interfaces/interfaces-config.sh index 400b89a594c7..28396774bfa1 100755 --- a/files/image_config/interfaces/interfaces-config.sh +++ b/files/image_config/interfaces/interfaces-config.sh @@ -1,6 +1,22 @@ #!/bin/bash -sonic-cfggen -d -t /usr/share/sonic/templates/interfaces.j2 >/etc/network/interfaces +SONIC_ASIC_TYPE=$(sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type) +SYSTEM_MAC_ADDRESS=$(ip link show eth0 | grep ether | awk '{print $2}') + +# Align last byte of MAC if necessary +if [ "$SONIC_ASIC_TYPE" == "mellanox" -o "$SONIC_ASIC_TYPE" == "centec" ]; then + last_byte=$(python -c "print '$SYSTEM_MAC_ADDRESS'[-2:]") + aligned_last_byte=$(python -c "print format(int(int('$last_byte', 16) & 0b11000000), '02x')") # put mask and take away the 0x prefix + SYSTEM_MAC_ADDRESS=$(python -c "print '$SYSTEM_MAC_ADDRESS'[:-2] + '$aligned_last_byte'") # put aligned byte into the end of MAC +fi + +sonic-cfggen -d -a '{"hwaddr":"'$SYSTEM_MAC_ADDRESS'"}' -t /usr/share/sonic/templates/interfaces.j2 > /etc/network/interfaces + +# Also store the system mac to configDB switch table. User configured switch_mac is not supported for now. +/usr/bin/docker exec database redis-cli -n 4 hset SWITCH\|SWITCH_ATTR switch_mac $SYSTEM_MAC_ADDRESS + [ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid -service networking restart + +systemctl restart networking + ifdown lo && ifup lo diff --git a/files/image_config/interfaces/interfaces.j2 b/files/image_config/interfaces/interfaces.j2 index 6521eb7a67e1..a06ff91518a7 100644 --- a/files/image_config/interfaces/interfaces.j2 +++ b/files/image_config/interfaces/interfaces.j2 @@ -55,19 +55,6 @@ iface {{ name }} {{ 'inet' if prefix | ipv4 else 'inet6' }} static netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} # {% endfor %} -{% if VLAN %} -# "|| true" is added to suppress the error when interface is already a member of VLAN -{% for vlan in VLAN.keys()|sort %} -{% for member in VLAN[vlan]['members'] %} -allow-hotplug {{ member }} -iface {{ member }} inet manual - pre-up ifconfig {{ member }} up mtu 9100 - post-up brctl addif {{ vlan }} {{ member }} || true - post-down ifconfig {{ member }} down -# -{% endfor %} -{% endfor %} -{% endif %} {% if PORTCHANNEL %} # "|| true" is added to suppress the error when interface is already a member of LAG # "ip link show | grep -q master" is added to ensure interface is enslaved @@ -83,19 +70,6 @@ iface {{ member }} inet manual {% endfor %} {% endif %} {% endblock front_panel_interfaces %} -{% block vlan_interfaces %} -{% if VLAN_INTERFACE %} -# Vlan interfaces -{% for (name, prefix) in VLAN_INTERFACE.keys() | sort %} -auto {{ name }} -iface {{ name }} {{ 'inet' if prefix | ipv4 else 'inet6' }} static - bridge_ports none - address {{ prefix | ip }} - netmask {{ prefix | netmask if prefix | ipv4 else prefix | prefixlen }} -{% endfor %} -# -{% endif %} -{% endblock vlan_interfaces %} {% block pc_interfaces %} {% if PORTCHANNEL_INTERFACE %} # Portchannel interfaces diff --git a/files/image_config/ntp/ntp.conf.j2 b/files/image_config/ntp/ntp.conf.j2 index ae72820339be..d7df6bcd2e04 100644 --- a/files/image_config/ntp/ntp.conf.j2 +++ b/files/image_config/ntp/ntp.conf.j2 @@ -29,9 +29,13 @@ server {{ ntp_server }} iburst #only listen on localhost and eth0 ips (default is to listen on all ip addresses) interface ignore wildcard +{% if MGMT_INTERFACE %} {% for (mgmt_intf, mgmt_prefix) in MGMT_INTERFACE %} interface listen {{ mgmt_prefix | ip }} {% endfor %} +{% else %} +interface listen eth0 +{% endif %} interface listen 127.0.0.1 # Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index 4e9846fba024..b72bc6e2c1c8 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -20,8 +20,25 @@ if [ "$src" = "dhcp" ]; then sleep 1 done + if [ "`cat /tmp/dhcp_graph_url`" = "default" ]; then + echo "No graph_url option in DHCP response. Skipping graph update and using existing minigraph." + if [ "$dhcp_as_static" = "true" ]; then + sed -i "/enabled=/d" /etc/sonic/updategraph.conf + echo "enabled=false" >> /etc/sonic/updategraph.conf + fi + exit 0 + fi if [ "`cat /tmp/dhcp_graph_url`" = "N/A" ]; then - echo "No graph_url option in DHCP response. Skipping graph update." + echo "'N/A' found in DHCP response. Skipping graph update and generating an empty configuration." + echo '{"DEVICE_METADATA":' > /tmp/device_meta.json + sonic-cfggen -m /etc/sonic/minigraph.xml --var-json DEVICE_METADATA >> /tmp/device_meta.json + echo '}' >> /tmp/device_meta.json + if [ -f /etc/sonic/init_cfg.json ]; then + sonic-cfggen -j /tmp/device_meta.json -j /etc/sonic/init_cfg.json --print-data > /etc/sonic/config_db.json + else + cp -f /tmp/device_meta.json /etc/sonic/config_db.json + fi + if [ "$dhcp_as_static" = "true" ]; then sed -i "/enabled=/d" /etc/sonic/updategraph.conf echo "enabled=false" >> /etc/sonic/updategraph.conf @@ -29,6 +46,7 @@ if [ "$src" = "dhcp" ]; then exit 0 fi + HOSTNAME=`hostname -s` GRAPH_URL=`sonic-cfggen -t /tmp/dhcp_graph_url -a "{\"hostname\": \"$HOSTNAME\"}"` URL_REGEX='^(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]$' diff --git a/files/initramfs-tools/arista-convertfs.j2 b/files/initramfs-tools/arista-convertfs.j2 index 75ce011e839a..cea25bd39837 100644 --- a/files/initramfs-tools/arista-convertfs.j2 +++ b/files/initramfs-tools/arista-convertfs.j2 @@ -82,6 +82,13 @@ run_cmd() { fi } +fixup_flash_permissions() { + # properly set flash permissions for others + # this allows the sonic admin user to have read access on the flash + local flash_mnt="$1" + chmod o+rx "$flash_mnt" +} + # Extract kernel parameters set -- $(cat /proc/cmdline) for x in "$@"; do @@ -111,7 +118,14 @@ if ! wait_for_root_dev; then fi # exit when the root is ext4 -blkid | grep "$root_dev.*vfat" -q || exit 0 +if ! blkid | grep "$root_dev.*vfat" -q; then + mkdir -p "$root_mnt" + mount -t ext4 "$root_dev" "$root_mnt" + fixup_flash_permissions "$root_mnt" + umount "$root_mnt" + rmdir "$root_mnt" + exit 0 +fi # Get flash dev name if [ -z "$block_flash" ]; then @@ -176,3 +190,5 @@ run_cmd "$cmd" "$err_msg" err_msg="Error: copying files form $tmp_mnt to $root_mnt failed" cmd="cp -a $tmp_mnt/. $root_mnt/" run_cmd "$cmd" "$err_msg" + +fixup_flash_permissions "$root_mnt" diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 2340177fd18b..60305c292b6b 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -13,6 +13,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(INGRASYS_S8810_32Q_PLATFORM_MODULE) \ $(ACCTON_AS7712_32X_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ + $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(CEL_DX010_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/broadcom/platform-modules-inventec.mk b/platform/broadcom/platform-modules-inventec.mk index 0d00fe1f7368..f4a2e65e5147 100755 --- a/platform/broadcom/platform-modules-inventec.mk +++ b/platform/broadcom/platform-modules-inventec.mk @@ -1,12 +1,17 @@ -# Inventec d7032q28b Platform modules +# Inventec d7032q28b and d7054q28b Platform modules -INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION = 1.0.0 +INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION = 1.1.0 +INVENTEC_D7054Q28B_PLATFORM_MODULE_VERSION = 1.1.0 export INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION +export INVENTEC_D7054Q28B_PLATFORM_MODULE_VERSION INVENTEC_D7032Q28B_PLATFORM_MODULE = platform-modules-d7032q28b_$(INVENTEC_D7032Q28B_PLATFORM_MODULE_VERSION)_amd64.deb $(INVENTEC_D7032Q28B_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-inventec $(INVENTEC_D7032Q28B_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(INVENTEC_D7032Q28B_PLATFORM_MODULE)_PLATFORM = x86_64-inventec_d7032q28b-r0 SONIC_DPKG_DEBS += $(INVENTEC_D7032Q28B_PLATFORM_MODULE) -$(eval $(call add_extra_package,$(INVENTEC_D7032Q28B_PLATFORM_MODULE))) + +INVENTEC_D7054Q28B_PLATFORM_MODULE = platform-modules-d7054q28b_$(INVENTEC_D7054Q28B_PLATFORM_MODULE_VERSION)_amd64.deb +$(INVENTEC_D7054Q28B_PLATFORM_MODULE)_PLATFORM = x86_64-inventec_d7054q28b-r0 +$(eval $(call add_extra_package,$(INVENTEC_D7032Q28B_PLATFORM_MODULE),$(INVENTEC_D7054Q28B_PLATFORM_MODULE))) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index ea804a69c0eb..5b66026f297f 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_3.0.3.2-5_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_3.0.3.2-5_amd64.deb?sv=2015-04-05&sr=b&sig=MQE6FrxHs%2BIUPjRaSpWagcSjY6bbHLCUYasusxILkEs%3D&se=2031-06-07T21%3A50%3A36Z&sp=r" +BRCM_SAI = libsaibcm_3.0.3.2-10_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm_3.0.3.2-10_amd64.deb?sv=2015-04-05&sr=b&sig=tByZ7QDBsYlJ4UHbapnzqHYrbA8rD92%2FQXEpupITTmM%3D&se=2031-07-06T19%3A19%3A32Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_3.0.3.2-5_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_3.0.3.2-10_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_3.0.3.2-5_amd64.deb?sv=2015-04-05&sr=b&sig=o8bjWlxxYAM%2F95aSshRFJE57JwKVjRaH4jDU2lDEoMg%3D&se=2031-06-07T21%3A50%3A19Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/libsaibcm-dev_3.0.3.2-10_amd64.deb?sv=2015-04-05&sr=b&sig=T6U8sF%2BW8B%2FffBzPoUJ9peLcg2O9MunHBBKSu7SZOKo%3D&se=2031-07-06T19%3A19%3A52Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) diff --git a/platform/broadcom/sdk.mk b/platform/broadcom/sdk.mk index 04d540c64582..aff0cf07fe5c 100644 --- a/platform/broadcom/sdk.mk +++ b/platform/broadcom/sdk.mk @@ -1,4 +1,4 @@ -BRCM_OPENNSL_KERNEL = opennsl-modules-3.16.0-4-amd64_3.2.3.3-1_amd64.deb -$(BRCM_OPENNSL_KERNEL)_URL = "https://sonicstorage.blob.core.windows.net/packages/opennsl-modules-3.16.0-4-amd64_3.2.3.3-1_amd64.deb?sv=2015-04-05&sr=b&sig=Uepf4z2wOadX%2F6OR%2BCoQzjv2tkwEZ2AspBiuo5sb25s%3D&se=2031-05-30T19%3A37%3A19Z&sp=r" +BRCM_OPENNSL_KERNEL = opennsl-modules-3.16.0-4-amd64_3.2.3.3-2_amd64.deb +$(BRCM_OPENNSL_KERNEL)_URL = "https://sonicstorage.blob.core.windows.net/packages/opennsl-modules-3.16.0-4-amd64_3.2.3.3-2_amd64.deb?sv=2015-04-05&sr=b&sig=RADtBDA9oZmwHnTzBY76ewajyJ8Af%2BchVCzNbe%2BPsbc%3D&se=2031-07-06T19%3A18%3A56Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_OPENNSL_KERNEL) diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index d1417bff1778..f985b188326e 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit d1417bff17780255d4cc371b315f620087673eb8 +Subproject commit f985b188326e480124ec49541b4fecc51a213889 diff --git a/platform/broadcom/sonic-platform-modules-dell b/platform/broadcom/sonic-platform-modules-dell index 1abd4e6c41f6..f0e808fe518f 160000 --- a/platform/broadcom/sonic-platform-modules-dell +++ b/platform/broadcom/sonic-platform-modules-dell @@ -1 +1 @@ -Subproject commit 1abd4e6c41f633272667a5833a63ab6f8da15199 +Subproject commit f0e808fe518f336e4cb97fdaf25e35a752c24d89 diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf deleted file mode 100644 index 29d4d50a4f9a..000000000000 --- a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/conf/d7032q28b-modules.conf +++ /dev/null @@ -1,10 +0,0 @@ -# /etc/modules: kernel modules to load at boot time. -# -# This file contains the names of kernel modules that should be loaded -# at boot time, one per line. Lines beginning with "#" are ignored. - -lpc_ich -i2c-i801 -i2c-mux -i2c-mux-pca954x -i2c-dev diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile index cdabd612a66d..c43c47745229 100755 --- a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/Makefile @@ -1,3 +1,7 @@ obj-m += inv_cpld.o inv_psoc.o obj-m += inv_platform.o +obj-m += inv_eeprom.o +obj-m += swps.o +swps-objs := inv_swps.o io_expander.o transceiver.o + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c new file mode 100644 index 000000000000..b2dde612b610 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_eeprom.c @@ -0,0 +1,181 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* Size of EEPROM in bytes */ +#define EEPROM_SIZE 256 + +#define SLICE_BITS (6) +#define SLICE_SIZE (1 << SLICE_BITS) +#define SLICE_NUM (EEPROM_SIZE/SLICE_SIZE) + +/* Each client has this additional data */ +struct eeprom_data { + struct mutex update_lock; + u8 valid; /* bitfield, bit!=0 if slice is valid */ + unsigned long last_updated[SLICE_NUM]; /* In jiffies, 8 slices */ + u8 data[EEPROM_SIZE]; /* Register values */ +}; + + +static void inv_eeprom_update_client(struct i2c_client *client, u8 slice) +{ + struct eeprom_data *data = i2c_get_clientdata(client); + int i, j; + int ret; + int addr; + + + mutex_lock(&data->update_lock); + + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { + dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); + + addr = slice << SLICE_BITS; + + ret = i2c_smbus_write_byte_data(client, ((u8)addr >> 8) & 0xFF, (u8)addr & 0xFF); + /* select the eeprom address */ + if (ret < 0) { + dev_err(&client->dev, "address set failed\n"); + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) { + goto exit; + } + + for (i = slice << SLICE_BITS; i < (slice + 1) << SLICE_BITS; i+= SLICE_SIZE) { + for (j = i; j < (i+SLICE_SIZE); j++) { + int res; + + res = i2c_smbus_read_byte(client); + if (res < 0) { + goto exit; + } + + data->data[j] = res & 0xFF; + } + } + + data->last_updated[slice] = jiffies; + data->valid |= (1 << slice); + } + +exit: + mutex_unlock(&data->update_lock); +} + +static ssize_t inv_eeprom_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct eeprom_data *data = i2c_get_clientdata(client); + u8 slice; + + + if (off > EEPROM_SIZE) { + return 0; + } + if (off + count > EEPROM_SIZE) { + count = EEPROM_SIZE - off; + } + if (count == 0) { + return 0; + } + + /* Only refresh slices which contain requested bytes */ + for (slice = off >> SLICE_BITS; slice <= (off + count - 1) >> SLICE_BITS; slice++) { + inv_eeprom_update_client(client, slice); + } + + memcpy(buf, &data->data[off], count); + + return count; +} + +static struct bin_attribute inv_eeprom_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + }, + .size = EEPROM_SIZE, + .read = inv_eeprom_read, +}; + +static int inv_eeprom_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct eeprom_data *data; + int err; + + if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data->data, 0xff, EEPROM_SIZE); + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* create the sysfs eeprom file */ + err = sysfs_create_bin_file(&client->dev.kobj, &inv_eeprom_attr); + if (err) { + goto exit_kfree; + } + + return 0; + +exit_kfree: + kfree(data); +exit: + return err; +} + +static int inv_eeprom_remove(struct i2c_client *client) +{ + sysfs_remove_bin_file(&client->dev.kobj, &inv_eeprom_attr); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id inv_eeprom_id[] = { + { "inv_eeprom", 0 }, + { } +}; + +static struct i2c_driver inv_eeprom_driver = { + .driver = { + .name = "inv_eeprom", + }, + .probe = inv_eeprom_probe, + .remove = inv_eeprom_remove, + .id_table = inv_eeprom_id, +}; + +module_i2c_driver(inv_eeprom_driver); + +MODULE_AUTHOR("Inventec"); +MODULE_DESCRIPTION("Inventec D7032 Mother Board EEPROM driver"); +MODULE_LICENSE("GPL"); + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c index 71dda75b252f..52f6a5691d3e 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_platform.c @@ -1,197 +1,198 @@ -#include -//#include -#include -#include -#include -#include -#include - -#include -#include -#include - -//#include -#define IO_EXPAND_BASE 64 -#define IO_EXPAND_NGPIO 16 - -struct inv_i2c_board_info { - int ch; - int size; - struct i2c_board_info *board_info; -}; - -#define bus_id(id) (id) -static struct pca954x_platform_mode mux_modes_0[] = { - {.adap_id = bus_id(2),}, {.adap_id = bus_id(3),}, - {.adap_id = bus_id(4),}, {.adap_id = bus_id(5),}, -}; -static struct pca954x_platform_mode mux_modes_0_0[] = { - {.adap_id = bus_id(6),}, {.adap_id = bus_id(7),}, - {.adap_id = bus_id(8),}, {.adap_id = bus_id(9),}, - {.adap_id = bus_id(10),}, {.adap_id = bus_id(11),}, - {.adap_id = bus_id(12),}, {.adap_id = bus_id(13),}, -}; - -static struct pca954x_platform_mode mux_modes_0_1[] = { - {.adap_id = bus_id(14),}, {.adap_id = bus_id(15),}, - {.adap_id = bus_id(16),}, {.adap_id = bus_id(17),}, - {.adap_id = bus_id(18),}, {.adap_id = bus_id(19),}, - {.adap_id = bus_id(20),}, {.adap_id = bus_id(21),}, -}; - -static struct pca954x_platform_mode mux_modes_0_2[] = { - {.adap_id = bus_id(22),}, {.adap_id = bus_id(23),}, - {.adap_id = bus_id(24),}, {.adap_id = bus_id(25),}, - {.adap_id = bus_id(26),}, {.adap_id = bus_id(27),}, - {.adap_id = bus_id(28),}, {.adap_id = bus_id(29),}, -}; - -static struct pca954x_platform_mode mux_modes_0_3[] = { - {.adap_id = bus_id(30),}, {.adap_id = bus_id(31),}, - {.adap_id = bus_id(32),}, {.adap_id = bus_id(33),}, - {.adap_id = bus_id(34),}, {.adap_id = bus_id(35),}, - {.adap_id = bus_id(36),}, {.adap_id = bus_id(37),}, -}; - -static struct pca954x_platform_data mux_data_0 = { - .modes = mux_modes_0, - .num_modes = 4, -}; -static struct pca954x_platform_data mux_data_0_0 = { - .modes = mux_modes_0_0, - .num_modes = 8, -}; -static struct pca954x_platform_data mux_data_0_1 = { - .modes = mux_modes_0_1, - .num_modes = 8, -}; -static struct pca954x_platform_data mux_data_0_2 = { - .modes = mux_modes_0_2, - .num_modes = 8, -}; -static struct pca954x_platform_data mux_data_0_3 = { - .modes = mux_modes_0_3, - .num_modes = 8, -}; - -static struct i2c_board_info i2c_device_info0[] __initdata = { - {"inv_psoc", 0, 0x66, 0, 0, 0},//psoc - {"inv_cpld", 0, 0x55, 0, 0, 0},//cpld - {"pca9545", 0, 0x70, &mux_data_0, 0, 0}, -}; - -static struct i2c_board_info i2c_device_info1[] __initdata = { - {"pca9545", 0, 0x70, &mux_data_0, 0, 0}, -}; - -static struct i2c_board_info i2c_device_info2[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0}, -}; - -static struct i2c_board_info i2c_device_info3[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0}, -}; - -static struct i2c_board_info i2c_device_info4[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0}, -}; - -static struct i2c_board_info i2c_device_info5[] __initdata = { - {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0}, -}; - - -static struct inv_i2c_board_info i2cdev_list[] = { - {0, ARRAY_SIZE(i2c_device_info0), i2c_device_info0 }, //smbus 0 - {1, ARRAY_SIZE(i2c_device_info1), i2c_device_info1 }, //smbus 1 or gpio11+12 - - {bus_id(2), ARRAY_SIZE(i2c_device_info2), i2c_device_info2 }, //mux 0 - {bus_id(3), ARRAY_SIZE(i2c_device_info3), i2c_device_info3 }, //mux 1 - {bus_id(4), ARRAY_SIZE(i2c_device_info4), i2c_device_info4 }, //mux 2 - {bus_id(5), ARRAY_SIZE(i2c_device_info5), i2c_device_info5 }, //mux 3 -}; - -///////////////////////////////////////////////////////////////////////////////////////// -static struct i2c_gpio_platform_data i2c_gpio_platdata0 = { - .scl_pin = 8, - .sda_pin = 9, - - .udelay = 5, //5:100kHz - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, - .scl_is_output_only = 0 -}; - -static struct i2c_gpio_platform_data i2c_gpio_platdata1 = { - .scl_pin = 12, - .sda_pin = 11, - - .udelay = 5, //5:100kHz - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, - .scl_is_output_only = 0 -}; - -static struct platform_device device_i2c_gpio0 = { - .name = "i2c-gpio", - .id = 0, // adapter number - .dev.platform_data = &i2c_gpio_platdata0, -}; - -static struct platform_device device_i2c_gpio1 = { - .name = "i2c-gpio", - .id = 1, // adapter number - .dev.platform_data = &i2c_gpio_platdata1, -}; - -static int __init plat_redwood_x86_init(void) -{ - struct i2c_adapter *adap = NULL; - struct i2c_client *e = NULL; - int ret = 0; - int i,j; - - printk("el6661 plat_redwood_x86_init \n"); - -#if 0 //disable for ICOS - //use i2c-gpio - //register i2c gpio - //config gpio8,9 to gpio function - outl( inl(0x500) | (1<<8 | 1<<9), 0x500); - - ret = platform_device_register(&device_i2c_gpio0); - if (ret) { - printk(KERN_ERR "i2c-gpio: device_i2c_gpio0 register fail %d\n", ret); - } - - outl( inl(0x500) | (1<<11 | 1<<12), 0x500); - ret = platform_device_register(&device_i2c_gpio1); - if (ret) { - printk(KERN_ERR "i2c-gpio: device_i2c_gpio1 register fail %d\n", ret); - } -#endif - - for(i=0; i +//#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//#include +#define IO_EXPAND_BASE 64 +#define IO_EXPAND_NGPIO 16 + +struct inv_i2c_board_info { + int ch; + int size; + struct i2c_board_info *board_info; +}; + +#define bus_id(id) (id) +static struct pca954x_platform_mode mux_modes_0[] = { + {.adap_id = bus_id(2),}, {.adap_id = bus_id(3),}, + {.adap_id = bus_id(4),}, {.adap_id = bus_id(5),}, +}; +static struct pca954x_platform_mode mux_modes_0_0[] = { + {.adap_id = bus_id(6),}, {.adap_id = bus_id(7),}, + {.adap_id = bus_id(8),}, {.adap_id = bus_id(9),}, + {.adap_id = bus_id(10),}, {.adap_id = bus_id(11),}, + {.adap_id = bus_id(12),}, {.adap_id = bus_id(13),}, +}; + +static struct pca954x_platform_mode mux_modes_0_1[] = { + {.adap_id = bus_id(14),}, {.adap_id = bus_id(15),}, + {.adap_id = bus_id(16),}, {.adap_id = bus_id(17),}, + {.adap_id = bus_id(18),}, {.adap_id = bus_id(19),}, + {.adap_id = bus_id(20),}, {.adap_id = bus_id(21),}, +}; + +static struct pca954x_platform_mode mux_modes_0_2[] = { + {.adap_id = bus_id(22),}, {.adap_id = bus_id(23),}, + {.adap_id = bus_id(24),}, {.adap_id = bus_id(25),}, + {.adap_id = bus_id(26),}, {.adap_id = bus_id(27),}, + {.adap_id = bus_id(28),}, {.adap_id = bus_id(29),}, +}; + +static struct pca954x_platform_mode mux_modes_0_3[] = { + {.adap_id = bus_id(30),}, {.adap_id = bus_id(31),}, + {.adap_id = bus_id(32),}, {.adap_id = bus_id(33),}, + {.adap_id = bus_id(34),}, {.adap_id = bus_id(35),}, + {.adap_id = bus_id(36),}, {.adap_id = bus_id(37),}, +}; + +static struct pca954x_platform_data mux_data_0 = { + .modes = mux_modes_0, + .num_modes = 4, +}; +static struct pca954x_platform_data mux_data_0_0 = { + .modes = mux_modes_0_0, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_1 = { + .modes = mux_modes_0_1, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_2 = { + .modes = mux_modes_0_2, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_3 = { + .modes = mux_modes_0_3, + .num_modes = 8, +}; + +static struct i2c_board_info i2c_device_info0[] __initdata = { + {"inv_psoc", 0, 0x66, 0, 0, 0},//psoc + {"inv_cpld", 0, 0x55, 0, 0, 0},//cpld + {"pca9545", 0, 0x70, &mux_data_0, 0, 0}, +}; + +static struct i2c_board_info i2c_device_info1[] __initdata = { + {"pca9545", 0, 0x70, &mux_data_0, 0, 0}, +}; + +static struct i2c_board_info i2c_device_info2[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0}, +}; + +static struct i2c_board_info i2c_device_info3[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0}, +}; + +static struct i2c_board_info i2c_device_info4[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0}, +}; + +static struct i2c_board_info i2c_device_info5[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0}, +}; + + +static struct inv_i2c_board_info i2cdev_list[] = { + {0, ARRAY_SIZE(i2c_device_info0), i2c_device_info0 }, //smbus 0 + {1, ARRAY_SIZE(i2c_device_info1), i2c_device_info1 }, //smbus 1 or gpio11+12 + + {bus_id(2), ARRAY_SIZE(i2c_device_info2), i2c_device_info2 }, //mux 0 + {bus_id(3), ARRAY_SIZE(i2c_device_info3), i2c_device_info3 }, //mux 1 + {bus_id(4), ARRAY_SIZE(i2c_device_info4), i2c_device_info4 }, //mux 2 + {bus_id(5), ARRAY_SIZE(i2c_device_info5), i2c_device_info5 }, //mux 3 +}; + +///////////////////////////////////////////////////////////////////////////////////////// +static struct i2c_gpio_platform_data i2c_gpio_platdata0 = { + .scl_pin = 8, + .sda_pin = 9, + + .udelay = 5, //5:100kHz + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0 +}; + +static struct i2c_gpio_platform_data i2c_gpio_platdata1 = { + .scl_pin = 12, + .sda_pin = 11, + + .udelay = 5, //5:100kHz + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0 +}; + +static struct platform_device device_i2c_gpio0 = { + .name = "i2c-gpio", + .id = 0, // adapter number + .dev.platform_data = &i2c_gpio_platdata0, +}; + +static struct platform_device device_i2c_gpio1 = { + .name = "i2c-gpio", + .id = 1, // adapter number + .dev.platform_data = &i2c_gpio_platdata1, +}; + +static int __init plat_redwood_x86_init(void) +{ + struct i2c_adapter *adap = NULL; + struct i2c_client *e = NULL; + int ret = 0; + int i,j; + + printk("el6661 plat_redwood_x86_init \n"); + +#if 0 //disable for ICOS + //use i2c-gpio + //register i2c gpio + //config gpio8,9 to gpio function + outl( inl(0x500) | (1<<8 | 1<<9), 0x500); + + ret = platform_device_register(&device_i2c_gpio0); + if (ret) { + printk(KERN_ERR "i2c-gpio: device_i2c_gpio0 register fail %d\n", ret); + } + + outl( inl(0x500) | (1<<11 | 1<<12), 0x500); + ret = platform_device_register(&device_i2c_gpio1); + if (ret) { + printk(KERN_ERR "i2c-gpio: device_i2c_gpio1 register fail %d\n", ret); + } +#endif + + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_swps.h" + +static int port_major; +static int ioexp_total; +static int port_total; +static struct class *swp_class_p = NULL; +static struct inv_platform_s *platform_p = NULL; +static struct inv_ioexp_layout_s *ioexp_layout = NULL; +static struct inv_port_layout_s *port_layout = NULL; + +static int +__swp_match(struct device *dev, +#ifdef SWPS_KERN_VER_AF_3_10 + + const void *data){ +#else + void *data){ +#endif + + char *name = (char *)data; + if (strcmp(dev_name(dev), name) == 0) + return 1; + return 0; +} + + +struct device * +get_swpdev_by_name(char *name){ + struct device *dev = class_find_device(swp_class_p, + NULL, + name, + (const void *)__swp_match); + return dev; +} + + +static int +sscanf_2_int(const char *buf) { + + int result = -EBFONT; + char *hex_tag = "0x"; + + if (strcspn(buf, hex_tag) == 0) { + if (sscanf(buf,"%x",&result)) { + return result; + } + } else { + if (sscanf(buf,"%d",&result)) { + return result; + } + if(sscanf(buf,"-%d",&result)) { + return -result; + } + if (sscanf(buf,"%x",&result)) { + return result; + } + } + return -EBFONT; +} + + +static int +sscanf_2_binary(const char *buf) { + + int result = sscanf_2_int(buf); + + if (result < 0){ + return -EBFONT; + } + switch (result) { + case 0: + case 1: + return result; + default: + break; + } + return -EBFONT; +} + +/* ========== Show functions: For I/O Expander attribute ========== + */ +static ssize_t +_show_ioexp_binary_attr(struct transvr_obj_s *tobj_p, + int (*get_func)(struct ioexp_obj_s *ioexp_p, int voffset), + char *buf_p) { + size_t len; + struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p; + + if (!ioexp_p) { + SWPS_ERR(" %s: data corruption! :%s\n", __func__, tobj_p->swp_name); + return -ENODATA; + } + mutex_lock(&ioexp_p->lock); + len = snprintf(buf_p, 8, "%d\n", get_func(ioexp_p, tobj_p->ioexp_virt_offset)); + mutex_unlock(&ioexp_p->lock); + return len; +} + + +static ssize_t +show_attr_present(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_present, + buf_p); +} + +static ssize_t +show_attr_reset(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_reset, + buf_p); +} + +static ssize_t +show_attr_lpmod(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_lpmod, + buf_p); +} + + +static ssize_t +show_attr_modsel(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_modsel, + buf_p); +} + +/* ========== Store functions: For I/O Expander (R/W) attribute ========== + */ +static ssize_t +_store_ioexp_binary_attr(struct transvr_obj_s *tobj_p, + int (*set_func)(struct ioexp_obj_s *ioexp_p, + int virt_offset, int input_val), + const char *buf_p, + size_t count) { + + int input, err; + struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p; + + if (!ioexp_p) { + SWPS_ERR("%s: data corruption! :%s\n", + __func__, tobj_p->swp_name); + return -ENODATA; + } + input = sscanf_2_binary(buf_p); + if (input < 0) { + return -EBFONT; + } + mutex_lock(&ioexp_p->lock); + err = set_func(ioexp_p, tobj_p->ioexp_virt_offset, input); + mutex_unlock(&ioexp_p->lock); + if (err < 0){ + return err; + } + return count; +} + +static ssize_t +store_attr_reset(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_reset, + buf_p, + count); +} + + +static ssize_t +store_attr_lpmod(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_lpmod, + buf_p, + count); +} + + +static ssize_t +store_attr_modsel(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_modsel, + buf_p, + count); +} + +/* ========== IO Expander attribute: from expander ========== + */ +static DEVICE_ATTR(present, S_IRUGO, show_attr_present, NULL); +static DEVICE_ATTR(reset, S_IRUGO|S_IWUSR, show_attr_reset, store_attr_reset); +static DEVICE_ATTR(lpmod, S_IRUGO|S_IWUSR, show_attr_lpmod, store_attr_lpmod); +static DEVICE_ATTR(modsel, S_IRUGO|S_IWUSR, show_attr_modsel, store_attr_modsel); + +/* ========== Functions for module handling ========== + */ +static void +clean_port_obj(void){ + + dev_t dev_num; + char dev_name[32]; + struct device *device_p; + struct transvr_obj_s *transvr_obj_p; + int minor_curr, port_id; + + for (minor_curr=0; minor_curri2c_client_p); + kfree(transvr_obj_p); + } + dev_num = MKDEV(port_major, minor_curr); + device_unregister(device_p); + device_destroy(swp_class_p, dev_num); + } + SWPS_DEBUG("%s: done.\n", __func__); +} + + +static int +get_platform_type(void){ + + char log_msg[64] = "ERROR"; + + platform_p = kzalloc(sizeof(struct inv_platform_s), GFP_KERNEL); + if (!platform_p){ + snprintf(log_msg, sizeof(log_msg), "kzalloc fail"); + goto err_get_platform_type_1; + } + platform_p->id = PLATFORM_SETTINGS; + memset(platform_p->name, 0, sizeof(platform_p->name)); + snprintf(platform_p->name, (sizeof(platform_p->name) - 1), + "%s", platform_map.name); + snprintf(log_msg, sizeof(log_msg), + "User setup platform: %d (%s)", + platform_p->id, platform_p->name); + SWPS_DEBUG("%s: %s, :%d\n", __func__, log_msg, PLATFORM_SETTINGS); + return 0; + +err_get_platform_type_1: + SWPS_ERR("%s: %s :%d\n", __func__, log_msg, PLATFORM_SETTINGS); + return -1; +} + + +static int +get_layout_info(void){ + + ioexp_layout = redwood_ioexp_layout; + port_layout = redwood_port_layout; + ioexp_total = ARRAY_SIZE(redwood_ioexp_layout); + port_total = ARRAY_SIZE(redwood_port_layout); + + SWPS_INFO("Start to initial platform: %d (%s)\n", + platform_p->id, platform_p->name); + return 0; +} + +/* ========== Functions for register something ========== + */ + +static int +register_ioexp_attr_qsfp_1(struct device *device_p){ + /* Support machine type: + * - QSFP : Magnolia, Redwood, Hudson32i + * - QSFP+ : Magnolia, Redwood, Hudson32i + * - QSFP28: Redwood + */ + char *err_attr = NULL; + + if (device_create_file(device_p, &dev_attr_present) < 0) { + err_attr = "dev_attr_present"; + goto err_ioexp_qsfp1_attr; + } + if (device_create_file(device_p, &dev_attr_reset) < 0) { + err_attr = "dev_attr_reset"; + goto err_ioexp_qsfp1_attr; + } + if (device_create_file(device_p, &dev_attr_lpmod) < 0) { + err_attr = "dev_attr_lpmod"; + goto err_ioexp_qsfp1_attr; + } + if (device_create_file(device_p, &dev_attr_modsel) < 0) { + err_attr = "dev_attr_modsel"; + goto err_ioexp_qsfp1_attr; + } + return 0; + +err_ioexp_qsfp1_attr: + SWPS_ERR("Add device attribute:%s failure! \n",err_attr); + return -1; +} + +static int +register_ioexp_attr(struct device *device_p, + struct transvr_obj_s *transvr_obj){ + + char *err_msg = "ERR"; + + switch (transvr_obj->ioexp_obj_p->ioexp_type){ + case IOEXP_TYPE_REDWOOD_P01P08: + case IOEXP_TYPE_REDWOOD_P09P16: + if (register_ioexp_attr_qsfp_1(device_p) < 0){ + err_msg = "register_ioexp_attr_qsfp_1 fail"; + goto err_reg_ioexp_attr; + } + break; + + default: + err_msg = "Unknow type"; + goto err_reg_ioexp_attr; + } + return 0; + +err_reg_ioexp_attr: + SWPS_ERR("%s: %s :%d \n", + __func__, err_msg, transvr_obj->ioexp_obj_p->ioexp_type); + return -1; +} + + +static int +register_port_device(char *dev_name, + dev_t dev_num, + struct transvr_obj_s *transvr_obj){ + + struct device *device_p = NULL; + device_p = device_create(swp_class_p, /* struct class *cls */ + NULL, /* struct device *parent */ + dev_num, /* dev_t devt */ + transvr_obj, /* void *private_data */ + dev_name); /* const char *fmt */ + if (IS_ERR(device_p)){ + goto err_regswp_create_dev; + } + if (register_ioexp_attr(device_p, transvr_obj) < 0){ + goto err_regswp_reg_attr; + } + return 0; + +err_regswp_reg_attr: + device_unregister(device_p); + device_destroy(swp_class_p, dev_num); +err_regswp_create_dev: + SWPS_ERR("%s fail! :%s\n", __func__, dev_name); + return -1; +} + + +static int +register_swp_module(void){ + + dev_t port_devt = 0; + int dev_total = port_total + 1; /* char_dev for module control */ + + if (alloc_chrdev_region(&port_devt, 0, dev_total, SWP_CLS_NAME) < 0){ + SWPS_WARN("Allocate PORT MAJOR failure! \n"); + goto err_register_swp_module_3; + } + port_major = MAJOR(port_devt); + + /* Create class object */ + swp_class_p = class_create(THIS_MODULE, SWP_CLS_NAME); + if (IS_ERR(swp_class_p)) { + SWPS_ERR("Create class failure! \n"); + goto err_register_swp_module_3; + } + return 0; + +err_register_swp_module_3: + unregister_chrdev_region(MKDEV(port_major, 0), port_total); + return -1; +} + + +/* ========== Module initial relate ========== + */ +static int +create_ioexp_objs(void) { + + int i, run_mod; + + /* Clean IOEXP object */ + clean_ioexp_objs(); + /* Get running mode */ + run_mod = IOEXP_MODE_DIRECT; + /* Create IOEXP object */ + for(i=0; i devlen_max) { + snprintf(err_msg, sizeof(err_msg), + "SWP_DEV_PORT too long!"); + goto err_initport_create_tranobj; + } + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, devlen_max, "%s%d", SWP_DEV_PORT, port_id); + /* Create transceiver object */ + ioexp_obj_p = get_ioexp_obj(ioexp_id); + if (!ioexp_obj_p){ + snprintf(err_msg, sizeof(err_msg), + "IOEXP object:%d not exist", ioexp_id); + goto err_initport_create_tranobj; + } + transvr_obj_p = create_transvr_obj(dev_name, chan_id, ioexp_obj_p, + ioexp_virt_offset, transvr_type, + chipset_type, run_mod); + if (!transvr_obj_p){ + snprintf(err_msg, sizeof(err_msg), + "Create transceiver object fail :%s", dev_name); + goto err_initport_create_tranobj; + } + /* Setup Lane_ID mapping */ + i = ARRAY_SIZE(port_layout[minor_curr].lane_id); + j = ARRAY_SIZE(transvr_obj_p->lane_id); + if (i != j) { + snprintf(err_msg, sizeof(err_msg), + "Lane_id size inconsistent %d/%d", i, j); + goto err_initport_reg_device; + } + memcpy(transvr_obj_p->lane_id, port_layout[minor_curr].lane_id, i*sizeof(int)); + /* Create and register device object */ + if (register_port_device(dev_name, MKDEV(port_major, minor_curr), transvr_obj_p) < 0){ + snprintf(err_msg, sizeof(err_msg), + "register_port_device fail"); + goto err_initport_reg_device; + } + /* Setup device_ptr of transvr_obj */ + dev_p = get_swpdev_by_name(dev_name); + if (!dev_p){ + snprintf(err_msg, sizeof(err_msg), + "get_swpdev_by_name fail"); + goto err_initport_reg_device; + } + transvr_obj_p->transvr_dev_p = dev_p; + /* Success */ + ok_count++; + } + SWPS_INFO("%s: initialed %d port-dev",__func__, ok_count); + return 0; + +err_initport_reg_device: + kfree(transvr_obj_p); +err_initport_create_tranobj: + clean_port_obj(); + SWPS_ERR("%s: %s", __func__, err_msg); + SWPS_ERR("Dump: :%d :%d :%d :%d :%d :%d\n", + port_id, chan_id, ioexp_id, ioexp_virt_offset, transvr_type, run_mod); + return -1; +} + +static int __init +swp_module_init(void){ + + if (get_platform_type() < 0){ + goto err_init_out; + } + if (get_layout_info() < 0){ + goto err_init_out; + } + if (register_swp_module() < 0){ + goto err_init_out; + } + if (create_ioexp_objs() < 0){ + goto err_init_ioexp; + } + if (create_port_objs() < 0){ + goto err_init_portobj; + } + if (init_ioexp_objs() < 0){ + goto err_init_portobj; + } + SWPS_INFO("Inventec switch-port module V.%s initial success.\n", SWP_VERSION); + return 0; + + +err_init_portobj: + clean_ioexp_objs(); +err_init_ioexp: + class_unregister(swp_class_p); + class_destroy(swp_class_p); + unregister_chrdev_region(MKDEV(port_major, 0), port_total); +err_init_out: + SWPS_ERR("Inventec switch-port module V.%s initial failure.\n", SWP_VERSION); + return -1; +} + + +static void __exit +swp_module_exit(void){ + clean_port_obj(); + clean_ioexp_objs(); + class_unregister(swp_class_p); + class_destroy(swp_class_p); + unregister_chrdev_region(MKDEV(port_major, 0), port_total); + SWPS_INFO("Remove Inventec switch-port module success.\n"); +} + + +/* Module information */ +MODULE_AUTHOR(SWP_AUTHOR); +MODULE_DESCRIPTION(SWP_DESC); +MODULE_VERSION(SWP_VERSION); +MODULE_LICENSE(SWP_LICENSE); + +module_init(swp_module_init); +module_exit(swp_module_exit); + + + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h new file mode 100644 index 000000000000..b186c2202381 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/inv_swps.h @@ -0,0 +1,131 @@ +#ifndef INV_SWPS_H +#define INV_SWPS_H + +#include "transceiver.h" +#include "io_expander.h" + +/* Module settings */ +#define SWP_CLS_NAME "swps" +#define SWP_DEV_PORT "port" +#define SWP_AUTOCONFIG_ENABLE (1) + +/* Module information */ +#define SWP_AUTHOR "Neil " +#define SWP_DESC "Inventec port and transceiver driver" +#define SWP_VERSION "4.2.3" +#define SWP_LICENSE "GPL" + +/* Module status define */ +#define SWP_STATE_NORMAL (0) +#define SWP_STATE_I2C_DIE (-91) + +/* [Note]: + * Functions and mechanism for auto-detect platform type is ready, + * But HW and BIOS not ready! We need to wait them. + * So, please do not use PLATFORM_TYPE_AUTO until they are ready. + * (2016.06.13) + */ +#define PLATFORM_TYPE_REDWOOD (121) +/* Current running platfrom */ +#define PLATFORM_SETTINGS PLATFORM_TYPE_REDWOOD + +/* Define platform flag and kernel version */ +#if (PLATFORM_SETTINGS == PLATFORM_TYPE_REDWOOD) + #define SWPS_KERN_VER_BF_3_8 (1) +#endif + +struct inv_platform_s { + int id; + char name[64]; +}; + +struct inv_ioexp_layout_s { + int ioexp_id; + int ioexp_type; + struct ioexp_addr_s addr[4]; +}; + +struct inv_port_layout_s { + int port_id; + int chan_id; + int ioexp_id; + int ioexp_offset; + int transvr_type; + int chipset_type; + int lane_id[8]; +}; + +/* ========================================== + * Inventec Platform Settings + * ========================================== + */ +struct inv_platform_s platform_map = {PLATFORM_TYPE_REDWOOD, "D7032Q28B" }; + +/* ========================================== + * Redwood Layout configuration + * ========================================== + */ +struct inv_ioexp_layout_s redwood_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_REDWOOD_P01P08, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */ + {0, 0x25, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */ + }, + {1, IOEXP_TYPE_REDWOOD_P09P16, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */ + {0, 0x25, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */ + }, + {2, IOEXP_TYPE_REDWOOD_P01P08, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */ + {0, 0x24, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */ + }, + {3, IOEXP_TYPE_REDWOOD_P09P16, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[0] = I/O Expander 1-4 A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0x00}, {0x00, 0x0f}, }, /* addr[1] = I/O Expander 1-4 B */ + {0, 0x24, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 5 B */ + }, +}; + +struct inv_port_layout_s redwood_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + { 0, 22, 0, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 1, 2, 3, 4} }, + { 1, 23, 0, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 5, 6, 7, 8} }, + { 2, 24, 0, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 9, 10, 11, 12} }, + { 3, 25, 0, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 13, 14, 15, 16} }, + { 4, 26, 0, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 17, 18, 19, 20} }, + { 5, 27, 0, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 21, 22, 23, 24} }, + { 6, 28, 0, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 25, 26, 27, 28} }, + { 7, 29, 0, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 29, 30, 31, 32} }, + { 8, 30, 1, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 33, 34, 35, 36} }, + { 9, 31, 1, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 37, 38, 39, 40} }, + {10, 32, 1, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 41, 42, 43, 44} }, + {11, 33, 1, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 45, 46, 47, 48} }, + {12, 34, 1, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 49, 50, 51, 52} }, + {13, 35, 1, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 53, 54, 55, 56} }, + {14, 36, 1, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 57, 58, 59, 60} }, + {15, 37, 1, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 61, 62, 63, 64} }, + {16, 6, 2, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 65, 66, 67, 68} }, + {17, 7, 2, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 69, 70, 71, 72} }, + {18, 8, 2, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 73, 74, 75, 76} }, + {19, 9, 2, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 77, 78, 79, 80} }, + {20, 10, 2, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 81, 82, 83, 84} }, + {21, 11, 2, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 85, 86, 87, 88} }, + {22, 12, 2, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 89, 90, 91, 92} }, + {23, 13, 2, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 93, 94, 95, 96} }, + {24, 14, 3, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 97, 98, 99,100} }, + {25, 15, 3, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {101,102,103,104} }, + {26, 16, 3, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {105,106,107,108} }, + {27, 17, 3, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {109,110,111,112} }, + {28, 18, 3, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {113,114,115,116} }, + {29, 19, 3, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {117,118,119,120} }, + {30, 20, 3, 6, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {121,122,123,124} }, + {31, 21, 3, 7, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {125,126,127,128} }, +}; + +#endif /* INV_SWPS_H */ + + + + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c new file mode 100644 index 000000000000..7c9f8a66aec7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.c @@ -0,0 +1,887 @@ +#include +#include +#include +#include "io_expander.h" + +static struct ioexp_obj_s *ioexp_head_p = NULL; +static struct ioexp_obj_s *ioexp_tail_p = NULL; + +struct ioexp_map_s ioexp_map_redwood_p01p08_p17p24 = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {2, 0, 0}, /* map_present[0] = MOD_ABS_PORT(X) */ + {2, 0, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {2, 0, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {2, 0, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {2, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {2, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {2, 0, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {2, 0, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP28_N_P(X) */ + {0, 0, 1}, /* map_reset[1] = QRESET_QSFP28_N_P(X+1) */ + {0, 0, 2}, /* map_reset[2] = QRESET_QSFP28_N_P(X+2) */ + {0, 0, 3}, /* map_reset[3] = QRESET_QSFP28_N_P(X+3) */ + {1, 0, 0}, /* map_reset[4] = QRESET_QSFP28_N_P(X+4) */ + {1, 0, 1}, /* map_reset[5] = QRESET_QSFP28_N_P(X+5) */ + {1, 0, 2}, /* map_reset[6] = QRESET_QSFP28_N_P(X+6) */ + {1, 0, 3}, /* map_reset[7] = QRESET_QSFP28_N_P(X+7) */ + }, + .map_lpmod = { {0, 0, 4}, /* map_lpmod[0] = LPMODE_QSFP28_P(X) */ + {0, 0, 5}, /* map_lpmod[1] = LPMODE_QSFP28_P(X+1) */ + {0, 0, 6}, /* map_lpmod[2] = LPMODE_QSFP28_P(X+2) */ + {0, 0, 7}, /* map_lpmod[3] = LPMODE_QSFP28_P(X+3) */ + {1, 0, 4}, /* map_lpmod[4] = LPMODE_QSFP28_P(X+4) */ + {1, 0, 5}, /* map_lpmod[5] = LPMODE_QSFP28_P(X+5) */ + {1, 0, 6}, /* map_lpmod[6] = LPMODE_QSFP28_P(X+6) */ + {1, 0, 7}, /* map_lpmod[7] = LPMODE_QSFP28_P(X+7) */ + }, + .map_modsel = { {0, 1, 4}, /* map_modsel[0] = MODSEL_QSFP28_N_P(X) */ + {0, 1, 5}, /* map_modsel[1] = MODSEL_QSFP28_N_P(X+1) */ + {0, 1, 6}, /* map_modsel[2] = MODSEL_QSFP28_N_P(X+2) */ + {0, 1, 7}, /* map_modsel[3] = MODSEL_QSFP28_N_P(X+3) */ + {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP28_N_P(X+4) */ + {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP28_N_P(X+5) */ + {1, 1, 6}, /* map_modsel[6] = MODSEL_QSFP28_N_P(X+6) */ + {1, 1, 7}, /* map_modsel[7] = MODSEL_QSFP28_N_P(X+7) */ + }, +}; + + +struct ioexp_map_s ioexp_map_redwood_p09p16_p25p32 = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {2, 1, 0}, /* map_present[0] = MOD_ABS_PORT(X) */ + {2, 1, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {2, 1, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {2, 1, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {2, 1, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {2, 1, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {2, 1, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {2, 1, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP28_N_P(X) */ + {0, 0, 1}, /* map_reset[1] = QRESET_QSFP28_N_P(X+1) */ + {0, 0, 2}, /* map_reset[2] = QRESET_QSFP28_N_P(X+2) */ + {0, 0, 3}, /* map_reset[3] = QRESET_QSFP28_N_P(X+3) */ + {1, 0, 0}, /* map_reset[4] = QRESET_QSFP28_N_P(X+4) */ + {1, 0, 1}, /* map_reset[5] = QRESET_QSFP28_N_P(X+5) */ + {1, 0, 2}, /* map_reset[6] = QRESET_QSFP28_N_P(X+6) */ + {1, 0, 3}, /* map_reset[7] = QRESET_QSFP28_N_P(X+7) */ + }, + .map_lpmod = { {0, 0, 4}, /* map_lpmod[0] = LPMODE_QSFP28_P(X) */ + {0, 0, 5}, /* map_lpmod[1] = LPMODE_QSFP28_P(X+1) */ + {0, 0, 6}, /* map_lpmod[2] = LPMODE_QSFP28_P(X+2) */ + {0, 0, 7}, /* map_lpmod[3] = LPMODE_QSFP28_P(X+3) */ + {1, 0, 4}, /* map_lpmod[4] = LPMODE_QSFP28_P(X+4) */ + {1, 0, 5}, /* map_lpmod[5] = LPMODE_QSFP28_P(X+5) */ + {1, 0, 6}, /* map_lpmod[6] = LPMODE_QSFP28_P(X+6) */ + {1, 0, 7}, /* map_lpmod[7] = LPMODE_QSFP28_P(X+7) */ + }, + .map_modsel = { {0, 1, 4}, /* map_modsel[0] = MODSEL_QSFP28_N_P(X) */ + {0, 1, 5}, /* map_modsel[1] = MODSEL_QSFP28_N_P(X+1) */ + {0, 1, 6}, /* map_modsel[2] = MODSEL_QSFP28_N_P(X+2) */ + {0, 1, 7}, /* map_modsel[3] = MODSEL_QSFP28_N_P(X+3) */ + {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP28_N_P(X+4) */ + {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP28_N_P(X+5) */ + {1, 1, 6}, /* map_modsel[6] = MODSEL_QSFP28_N_P(X+6) */ + {1, 1, 7}, /* map_modsel[7] = MODSEL_QSFP28_N_P(X+7) */ + }, +}; + +/* ========== Private functions ========== + */ +int check_channel_tier_1(void); + +struct i2c_client * +_get_i2c_client(struct ioexp_obj_s *self, + int chip_id){ + + struct ioexp_i2c_s *i2c_curr_p = self->i2c_head_p; + + if (!(i2c_curr_p)){ + SWPS_ERR("%s: i2c_curr_p is NULL\n", __func__); + return NULL; + } + while (i2c_curr_p){ + if ((i2c_curr_p->chip_id) == chip_id){ + return i2c_curr_p->i2c_client_p; + } + i2c_curr_p = i2c_curr_p->next; + } + SWPS_ERR("%s: not exist! :%d\n", __func__, chip_id); + return NULL; +} + + +static int +_common_ioexp_update_one(struct ioexp_obj_s *self, + struct ioexp_addr_s *ioexp_addr, + int chip_id, + int data_width, + int show_err, + char *caller_name) { + int buf = 0; + int err = 0; + int data_id = 0; + int r_offset = 0; + + for(data_id=0; data_idread_offset[data_id]; + buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), r_offset); + /* Check error */ + if (buf < 0) { + err = 1; + if (show_err) { + SWPS_INFO("IOEXP-%d read fail! :%d \n", self->ioexp_id, buf); + SWPS_INFO("Dump: :%d :0x%02x :%d, :%s\n", + ioexp_addr->chan_id, ioexp_addr->chip_addr, + ioexp_addr->read_offset[data_id], caller_name); + } + continue; + } + /* Update IOEXP object */ + self->chip_data[chip_id].data[data_id] = (uint8_t)buf; + } + if (err) { + return ERR_IOEXP_UNEXCPT; + } + return 0; +} + + +static int +common_ioexp_update_all(struct ioexp_obj_s *self, + int show_err, + char *caller_name){ + + int err = 0; + int chip_id = 0; + int chip_amount = self->ioexp_map_p->chip_amount; + + for (chip_id=0; chip_idioexp_map_p->map_addr[chip_id]), + chip_id, + self->ioexp_map_p->data_width, + show_err, + caller_name) < 0) { + err = 1; + } + } + if (err) { + return ERR_IOEXP_UNEXCPT; + } + return 0; +} + +static int +_common_get_bit(struct ioexp_obj_s *self, + struct ioexp_bitmap_s *bitmap_obj_p, + char *func_mane){ + uint8_t buf; + int err_code; + + /* Get address */ + err_code = self->fsm_4_direct(self); + if (err_code < 0){ + return err_code; + } + + if (!bitmap_obj_p){ + SWPS_ERR("Layout config incorrect! :%d :%s\n", + self->ioexp_id, func_mane); + return ERR_IOEXP_BADCONF; + } + /* Get data form cache */ + buf = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset]; + return (int)(buf >> bitmap_obj_p->bit_shift & 0x01); +} + + +static int +_common_set_bit(struct ioexp_obj_s *self, + struct ioexp_bitmap_s *bitmap_obj_p, + int input_val, + char *func_mane){ + int err_code, target_offset; + uint8_t origin_byte; + uint8_t modify_byte; + + /* Get address */ + err_code = self->fsm_4_direct(self); + if (err_code < 0){ + return err_code; + } + if (!bitmap_obj_p){ + SWPS_ERR("Layout config incorrect! :%d :%s\n", + self->ioexp_id, func_mane); + return ERR_IOEXP_BADCONF; + } + /* Prepare write date */ + origin_byte = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset]; + switch (input_val) { + case 0: + modify_byte = origin_byte; + SWP_BIT_CLEAR(modify_byte, bitmap_obj_p->bit_shift); + break; + case 1: + modify_byte = origin_byte; + SWP_BIT_SET(modify_byte, bitmap_obj_p->bit_shift); + break; + default: + SWPS_ERR("Input value incorrect! :%d :%d :%s\n", + input_val, self->ioexp_id, func_mane); + return ERR_IOEXP_BADINPUT; + } + /* Setup i2c client */ + target_offset = self->ioexp_map_p->map_addr[bitmap_obj_p->chip_id].write_offset[bitmap_obj_p->ioexp_voffset]; + /* Write byte to chip via I2C */ + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, bitmap_obj_p->chip_id), + target_offset, + modify_byte); + /* Update or bollback object */ + if (err_code < 0){ + self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = origin_byte; + SWPS_ERR("I2C write fail! :%d :%d :%s :%d\n", + input_val, self->ioexp_id, func_mane, err_code); + return err_code; + } + self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = modify_byte; + return 0; +} + + +/* ========== Object public functions ========== + */ +int +common_get_present(struct ioexp_obj_s *self, + int virt_offset){ + + int UNPLUG = 1; + int retval = ERR_IOEXP_UNEXCPT; + + retval = _common_get_bit(self, + &(self->ioexp_map_p->map_present[virt_offset]), + "common_get_present"); + if (retval < 0) { + /* [Note] + * => Transceiver object does not need to handle IOEXP layer issues. + */ + return UNPLUG; + } + return retval; +} + + +int +common_get_reset(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_reset[virt_offset]), + "common_get_reset"); +} + + +int +common_get_lpmod(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_lpmod[virt_offset]), + "common_get_lpmod"); +} + + +int +common_get_modsel(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_modsel[virt_offset]), + "common_get_modsel"); +} + +int +common_set_reset(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_reset[virt_offset]), + input_val, + "common_set_reset"); +} + + +int +common_set_lpmod(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_lpmod[virt_offset]), + input_val, + "common_set_lpmod"); +} + + +int +common_set_modsel(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_modsel[virt_offset]), + input_val, + "common_set_modsel"); +} + +int +ioexp_get_not_support(struct ioexp_obj_s *self, + int virt_offset){ + return ERR_IOEXP_NOTSUPPORT; +} + + +int +ioexp_set_not_support(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + return ERR_IOEXP_NOTSUPPORT; +} + +/* ========== Initial functions for IO Expander ========== + */ +int +common_ioexp_init(struct ioexp_obj_s *self) { + + int chip_id, offset, err_code; + struct ioexp_addr_s *addr_p; + + if (self->mode == IOEXP_MODE_DIRECT) { ///important + goto update_common_ioexp_init; + } + /* Setup default value to each physical IO Expander */ + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + /* Get address mapping */ + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + if (!addr_p){ + SWPS_ERR("%s: IOEXP config incorrect! :%d \n", + __func__, chip_id); + return -1; + } + /* Setup default value */ + for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), + addr_p->write_offset[offset], + addr_p->data_default[offset]); + if (err_code < 0){ + SWPS_ERR("%s: set default fail! :%d \n", + __func__, err_code); + return ERR_IOEXP_UNEXCPT; + } + } + } + +update_common_ioexp_init: + /* Check and update info to object */ + err_code = self->update_all(self, 1, "common_ioexp_init"); + if (err_code < 0) { + SWPS_ERR("%s: update_all() fail! :%d \n", + __func__, err_code); + return ERR_IOEXP_UNEXCPT; + } + return 0; +} + + +/* ========== Object functions for Final State Machine ========== + */ +int +_is_channel_ready(struct ioexp_obj_s *self){ + + int buf = 0; + int chip_id = 0; /* Use first chip which be registered */ + int data_id = 0; /* Use first byte which be registered */ + struct ioexp_addr_s *ioexp_addr = NULL; + + ioexp_addr = &(self->ioexp_map_p->map_addr[chip_id]); + if (!ioexp_addr){ + SWPS_ERR("%s: config incorrect!\n", __func__); + return ERR_IOEXP_UNEXCPT; + } + buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), + ioexp_addr->read_offset[data_id]); + if (buf >= 0){ + return 1; + } + return 0; +} + +int +_ioexp_init_handler(struct ioexp_obj_s *self){ + + int return_val; + + switch (self->mode) { + case IOEXP_MODE_DIRECT: + return_val = self->init(self); + if (return_val < 0){ + self->state = STATE_IOEXP_ABNORMAL; + } else { + self->state = STATE_IOEXP_NORMAL; + } + return return_val; + default: + break; + } + SWPS_ERR("%s: exception occur :%d\n", __func__, self->mode); + return ERR_IOEXP_UNEXCPT; +} + + +int +common_ioexp_fsm_4_direct(struct ioexp_obj_s *self){ + + int result_val; + int show_err = 1; + char *func_mane = "common_ioexp_fsm_4_direct"; + + switch (self->state){ + case STATE_IOEXP_INIT: + result_val = _ioexp_init_handler(self); + /* Exception case: terminate initial procedure */ + if(result_val < 0){ + /* Initial fail */ + return result_val; + } + if(self->state == STATE_IOEXP_INIT){ + /* Keep in INIT state, and return error */ + return ERR_IOEXP_UNINIT; + } + /* Case: Initial done */ + return 0; + + case STATE_IOEXP_NORMAL: + result_val = self->update_all(self, show_err, func_mane); + if (result_val < 0){ + SWPS_INFO("%s: NORMAL -> ABNORMAL :%d\n", + __func__, result_val); + self->state = STATE_IOEXP_ABNORMAL; + return result_val; + } + self->state = STATE_IOEXP_NORMAL; + return 0; + + case STATE_IOEXP_ABNORMAL: + result_val = self->update_all(self, show_err, func_mane); + if (result_val < 0){ + self->state = STATE_IOEXP_ABNORMAL; + return result_val; + } + SWPS_DEBUG("%s: ABNORMAL -> NORMAL :%d\n", + __func__, result_val); + self->state = STATE_IOEXP_NORMAL; + return 0; + + default: + break; + } + SWPS_ERR("%s: Exception occurs :%d\n", + __func__, self->state); + return ERR_IOEXP_UNEXCPT; +} + +/* ========== Functions for Factory pattern ========== + */ +static struct ioexp_map_s * +get_ioexp_map(int ioexp_type){ + switch (ioexp_type){ + case IOEXP_TYPE_REDWOOD_P01P08: + return &ioexp_map_redwood_p01p08_p17p24; + case IOEXP_TYPE_REDWOOD_P09P16: + return &ioexp_map_redwood_p09p16_p25p32; + default: + return NULL; + } +} + + +int +setup_ioexp_ssize_attr(struct ioexp_obj_s *self, + struct ioexp_map_s *ioexp_map_p, + int ioexp_id, + int ioexp_type, + int run_mode){ + switch (run_mode){ + case IOEXP_MODE_DIRECT: /* Direct access device mode */ + self->mode = run_mode; + break; + default: + SWPS_ERR("%s: non-defined run_mode:%d\n", + __func__, run_mode); + self->mode = ERR_IOEXP_UNEXCPT; + return ERR_IOEXP_UNEXCPT; + } + self->ioexp_id = ioexp_id; + self->ioexp_type = ioexp_type; + self->ioexp_map_p = ioexp_map_p; + self->state = STATE_IOEXP_INIT; + mutex_init(&self->lock); + return 0; +} + + +static int +setup_addr_mapping(struct ioexp_obj_s *self, + struct ioexp_addr_s *addr_map_p){ + if (!addr_map_p){ + SWPS_ERR("%s: map is null\n", __func__); + return -1; + } + self->ioexp_map_p->map_addr = addr_map_p; + return 0; +} + + +static int +setup_ioexp_public_cb(struct ioexp_obj_s *self, + int ioexp_type){ + switch (ioexp_type){ + case IOEXP_TYPE_REDWOOD_P01P08: + case IOEXP_TYPE_REDWOOD_P09P16: + self->get_present = common_get_present; + self->get_reset = common_get_reset; + self->get_lpmod = common_get_lpmod; + self->get_modsel = common_get_modsel; + self->set_reset = common_set_reset; + self->set_lpmod = common_set_lpmod; + self->set_modsel = common_set_modsel; + return 0; + default: + SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type); + break; + } + return ERR_IOEXP_UNEXCPT; +} + + +static int +setup_ioexp_private_cb(struct ioexp_obj_s *self, + int ioexp_type){ + + switch (ioexp_type){ + case IOEXP_TYPE_REDWOOD_P01P08: + case IOEXP_TYPE_REDWOOD_P09P16: + + self->init = common_ioexp_init; + self->update_all = common_ioexp_update_all; + self->fsm_4_direct = common_ioexp_fsm_4_direct; + return 0; + + default: + SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type); + break; + } + return ERR_IOEXP_UNEXCPT; +} + + +static int +setup_i2c_client_one(struct ioexp_obj_s *self, + int chip_id){ + + char *err_msg = "ERROR"; + struct i2c_adapter *adap = NULL; + struct i2c_client *client = NULL; + struct ioexp_i2c_s *i2c_obj_p = NULL; + struct ioexp_i2c_s *i2c_curr_p = NULL; + + int chan_id = self->ioexp_map_p->map_addr[chip_id].chan_id; + adap = i2c_get_adapter(chan_id); + if(!adap){ + err_msg = "Can not get adap!"; + goto err_ioexp_setup_i2c_1; + } + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client){ + err_msg = "Can not kzalloc client!"; + goto err_ioexp_setup_i2c_1; + } + i2c_obj_p = kzalloc(sizeof(*i2c_obj_p), GFP_KERNEL); + if (!i2c_obj_p){ + err_msg = "Can not kzalloc i2c_obj_p!"; + goto err_ioexp_setup_i2c_2; + } + client->adapter = adap; + client->addr = self->ioexp_map_p->map_addr[chip_id].chip_addr; + i2c_obj_p->i2c_client_p = client; + i2c_obj_p->chip_id = chip_id; + i2c_obj_p->next = NULL; + if (!self->i2c_head_p){ + self->i2c_head_p = i2c_obj_p; + } else { + i2c_curr_p = self->i2c_head_p; + while (i2c_curr_p->next){ + i2c_curr_p = i2c_curr_p->next; + } + i2c_curr_p->next = i2c_obj_p; + } + return 0; + +err_ioexp_setup_i2c_2: + kfree(client); +err_ioexp_setup_i2c_1: + SWPS_ERR("%s: %s :%d\n", __func__, err_msg, chan_id); + return -1; +} + + +static int +setup_i2c_client(struct ioexp_obj_s* self){ + + int result; + int chip_id = 0; + + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + result = setup_i2c_client_one(self, chip_id); + if (result < 0){ + SWPS_ERR("%s fail! :%d\n", __func__, chip_id); + return -1; + } + } + return 0; +} + +static int +setup_ioexp_config(struct ioexp_obj_s *self) { + + int chip_id, offset, err_code; + struct ioexp_addr_s *addr_p; + + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + if (!addr_p){ + SWPS_ERR("IOEXP config incorrect! :%d \n",chip_id); + return -1; + } + for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ + + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), + addr_p->conf_offset[offset], + addr_p->conf_default[offset]); + + if (err_code < 0){ + SWPS_INFO("%s: set conf fail! :%d \n", __func__, err_code); + return -2; + } + } + } + return 0; +} + +struct ioexp_obj_s * +_create_ioexp_obj(int ioexp_id, + int ioexp_type, + struct ioexp_addr_s *addr_map_p, + int run_mode){ + + struct ioexp_map_s* ioexp_map_p; + struct ioexp_obj_s* result_p; + struct ioexp_i2c_s *i2c_curr_p; + struct ioexp_i2c_s *i2c_next_p; + + /* Get layout */ + ioexp_map_p = get_ioexp_map(ioexp_type); + if (!ioexp_map_p){ + SWPS_ERR("%s: Invalid ioexp_type\n", __func__); + goto err_create_ioexp_fail; + } + /* Prepare IOEXP object */ + result_p = kzalloc(sizeof(*result_p), GFP_KERNEL); + if (!result_p){ + SWPS_ERR("%s: kzalloc failure!\n", __func__); + goto err_create_ioexp_fail; + } + /* Prepare static size attributes */ + if (setup_ioexp_ssize_attr(result_p, + ioexp_map_p, + ioexp_id, + ioexp_type, + run_mode) < 0){ + goto err_create_ioexp_setup_attr_fail; + } + /* Prepare address mapping */ + if (setup_addr_mapping(result_p, addr_map_p) < 0){ + goto err_create_ioexp_setup_attr_fail; + } + if (setup_i2c_client(result_p) < 0){ + goto err_create_ioexp_setup_i2c_fail; + } + /* Prepare call back functions of object */ + if (setup_ioexp_public_cb(result_p, ioexp_type) < 0){ + goto err_create_ioexp_setup_i2c_fail; + } + if (setup_ioexp_private_cb(result_p, ioexp_type) < 0){ + goto err_create_ioexp_setup_i2c_fail; + } + return result_p; + +err_create_ioexp_setup_i2c_fail: + i2c_curr_p = result_p->i2c_head_p; + i2c_next_p = result_p->i2c_head_p; + while (i2c_curr_p){ + i2c_next_p = i2c_curr_p->next; + kfree(i2c_curr_p->i2c_client_p); + kfree(i2c_curr_p); + i2c_curr_p = i2c_next_p; + } +err_create_ioexp_setup_attr_fail: + kfree(result_p); +err_create_ioexp_fail: + SWPS_ERR("%s: fail! :%d :%d \n", + __func__, ioexp_id, ioexp_type); + return NULL; +} + + +int +create_ioexp_obj(int ioexp_id, + int ioexp_type, + struct ioexp_addr_s *addr_map_p, + int run_mode){ + + struct ioexp_obj_s *ioexp_p = NULL; + + ioexp_p = _create_ioexp_obj(ioexp_id, ioexp_type, + addr_map_p, run_mode); + if (!ioexp_p){ + return -1; + } + if (ioexp_head_p == NULL){ + ioexp_head_p = ioexp_p; + ioexp_tail_p = ioexp_p; + return 0; + } + ioexp_tail_p->next = ioexp_p; + ioexp_tail_p = ioexp_p; + return 0; +} + +static int +_init_ioexp_obj(struct ioexp_obj_s* self) { + + char *err_msg = "ERR"; + char *func_name = "_init_ioexp_obj"; + + /* Setup IOEXP configure byte */ + if (setup_ioexp_config(self) < 0){ + err_msg = "setup_ioexp_config fail"; + goto err_init_ioexp_obj; + } + /* Setup default data */ + if (_ioexp_init_handler(self) < 0){ + err_msg = "_ioexp_init_handler fail"; + goto err_init_ioexp_obj; + } + /* Update all */ + if (self->state == STATE_IOEXP_NORMAL){ + if (self->update_all(self, 1, func_name) < 0){ + err_msg = "update_all() fail"; + goto err_init_ioexp_obj; + } + } + return 0; + +err_init_ioexp_obj: + SWPS_DEBUG("%s: %s\n", __func__, err_msg); + return -1; +} + +int +init_ioexp_objs(void){ + /* Return value: + * 0: Success + * -1: Detect topology error + * -2: SWPS internal error + */ + + struct ioexp_obj_s *curr_p = ioexp_head_p; + + if (!curr_p) { + SWPS_ERR("%s: ioexp_head_p is NULL\n", __func__); + return -2; + } + while (curr_p) { + if (_init_ioexp_obj(curr_p) < 0) { + SWPS_DEBUG("%s: _init_ioexp_obj() fail\n", __func__); + return -1; + } + curr_p = curr_p->next; + } + SWPS_DEBUG("%s: done.\n", __func__); + return 0; +} + +void +clean_ioexp_objs(void){ + + struct ioexp_i2c_s *i2c_curr_p = NULL; + struct ioexp_i2c_s *i2c_next_p = NULL; + struct ioexp_obj_s *ioexp_next_p = NULL; + struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p; + + if (ioexp_head_p == NULL){ + ioexp_tail_p = NULL; + return; + } + while(ioexp_curr_p){ + ioexp_next_p = ioexp_curr_p->next; + i2c_curr_p = ioexp_curr_p->i2c_head_p; + while (i2c_curr_p) { + i2c_next_p = i2c_curr_p->next; + kfree(i2c_curr_p->i2c_client_p); + kfree(i2c_curr_p); + i2c_curr_p = i2c_next_p; + } + kfree(ioexp_curr_p); + ioexp_curr_p = ioexp_next_p; + } + ioexp_tail_p = NULL; + SWPS_DEBUG("%s: done.\n", __func__); +} + +struct ioexp_obj_s * +get_ioexp_obj(int ioexp_id){ + + struct ioexp_obj_s *result_p = NULL; + struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p; + + while(ioexp_curr_p){ + if (ioexp_curr_p->ioexp_id == ioexp_id){ + result_p = ioexp_curr_p; + break; + } + ioexp_curr_p = ioexp_curr_p->next; + } + return result_p; +} +int +check_channel_tier_1(void) { + + if ( (!_is_channel_ready(ioexp_head_p)) && + (!_is_channel_ready(ioexp_tail_p)) ){ + return -1; + } + return 0; +} + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h new file mode 100644 index 000000000000..8c51b4f6d94f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/io_expander.h @@ -0,0 +1,136 @@ +#ifndef IO_EXPANDER_H +#define IO_EXPANDER_H + +#include + +/* IOEXP type define (QSFP series) */ +#define IOEXP_TYPE_REDWOOD_P01P08 (10202) +#define IOEXP_TYPE_REDWOOD_P09P16 (10203) + +/* IOEXP mode define */ +#define IOEXP_MODE_DIRECT (19001) + +/* IOEXP state define */ +#define STATE_IOEXP_NORMAL (0) +#define STATE_IOEXP_INIT (-1) +#define STATE_IOEXP_ABNORMAL (-2) + +/* IOEXP error code define */ +#define ERR_IOEXP_NOTSUPPORT (-100) +#define ERR_IOEXP_UNINIT (-101) +#define ERR_IOEXP_BADCONF (-102) +#define ERR_IOEXP_BADINPUT (-105) +#define ERR_IOEXP_UNEXCPT (-199) + + +#define SWPS_INFO(fmt, args...) printk( KERN_INFO "[SWPS] " fmt, ##args) +#define SWPS_WARN(fmt, args...) printk( KERN_WARNING "[SWPS] " fmt, ##args) +#define SWPS_ERR(fmt, args...) printk( KERN_ERR "[SWPS] " fmt, ##args) + +#ifdef DEBUG_SWPS +# define SWPS_DEBUG(fmt, args...) printk( KERN_DEBUG "[SWPS] " fmt, ##args) +#else +# define SWPS_DEBUG(fmt, args...) +#endif + + +struct ioexp_addr_s { + int chan_id; + int chip_addr; + int read_offset[8]; + int write_offset[8]; + int conf_offset[8]; + uint8_t data_default[8]; + uint8_t conf_default[8]; +}; + +struct ioexp_i2c_s { + int chip_id; + struct i2c_client *i2c_client_p; + struct ioexp_i2c_s *next; +}; + + +struct ioexp_bitmap_s { + int chip_id; /* IOEXP chip id */ + int ioexp_voffset; /* IOEXP virtual offset */ + int bit_shift; +}; + +struct ioexp_map_s { + int chip_amount; /* Number of chips that IOEXP object content */ + int data_width; /* Number of (Read/Write/Config) bytes */ + struct ioexp_addr_s *map_addr; /* Chip address info */ + struct ioexp_bitmap_s map_present[8]; /* IOEXP for SFP / QSFP */ + struct ioexp_bitmap_s map_reset[8]; /* IOEXP for QSFP */ + struct ioexp_bitmap_s map_lpmod[8]; /* IOEXP for QSFP */ + struct ioexp_bitmap_s map_modsel[8]; /* IOEXP for QSFP */ +}; + +struct ioexp_data_s { + uint8_t data[8]; +}; + +struct ioexp_obj_s { + + /* ============================ + * Object public property + * ============================ + */ + int ioexp_id; + int ioexp_type; + + /* ============================ + * Object private property + * ============================ + */ + struct ioexp_data_s chip_data[16]; /* Max: 8-ioexp in one virt-ioexp(ioexp_obj) */ + struct ioexp_map_s *ioexp_map_p; + struct ioexp_obj_s *next; + struct ioexp_i2c_s *i2c_head_p; + struct mutex lock; + int mode; + int state; + + /* =========================================== + * Object public functions + * =========================================== + */ + int (*get_present)(struct ioexp_obj_s *self, int virt_offset); + int (*get_reset)(struct ioexp_obj_s *self, int virt_offset); + int (*get_lpmod)(struct ioexp_obj_s *self, int virt_offset); + int (*get_modsel)(struct ioexp_obj_s *self, int virt_offset); + int (*set_reset)(struct ioexp_obj_s *self, int virt_offset, int input_val); + int (*set_lpmod)(struct ioexp_obj_s *self, int virt_offset, int input_val); + int (*set_modsel)(struct ioexp_obj_s *self, int virt_offset, int input_val); + + /* =========================================== + * Object private functions + * =========================================== + */ + int (*init)(struct ioexp_obj_s *self); + int (*update_all)(struct ioexp_obj_s *self, int show_err, char *caller_name); + int (*fsm_4_direct)(struct ioexp_obj_s* self); +}; + + +struct ioexp_obj_s* get_ioexp_obj(int ioexp_id); +int create_ioexp_obj(int ioexp_id, + int ioexp_type, + struct ioexp_addr_s *addr_map_p, + int run_mode); +int init_ioexp_objs(void); +void clean_ioexp_objs(void); + +int check_channel_tier_1(void); + +/* Macro for bit control */ +#define SWP_BIT_SET(byte_val,bit_shift) ((byte_val) |= (1<<(bit_shift))) +#define SWP_BIT_CLEAR(byte_val,bit_shift) ((byte_val) &= ~(1<<(bit_shift))) + + +#endif /* IO_EXPANDER_H */ + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c new file mode 100644 index 000000000000..36ccc45a9216 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.c @@ -0,0 +1,898 @@ +#include +#include +#include +#include +#include "io_expander.h" +#include "transceiver.h" + + +/* ========== Register EEPROM address mapping ========== + */ +struct eeprom_map_s eeprom_map_qsfp = { + .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1, + .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1, + .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1, +}; + +struct eeprom_map_s eeprom_map_qsfp28 = { + .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1, + .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1, + .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1, +}; + + +/* ========== Utility Functions ========== + */ +void +alarm_msg_2_user(struct transvr_obj_s *self, + char *emsg) { + + SWPS_ERR("%s on %s.\n", emsg, self->swp_name); +} + + +/* ========== Private functions ========== + */ +static int +_reload_transvr_obj(struct transvr_obj_s *self,int new_type); + +static int +reload_transvr_obj(struct transvr_obj_s *self,int new_type); + +static int +_transvr_init_handler(struct transvr_obj_s *self); + +static void +_transvr_clean_retry(struct transvr_obj_s *self) { + self->retry = 0; +} + + +static int +_transvr_handle_retry(struct transvr_obj_s *self, int retry) { + /* Return: 0: keep retry + * -1: stop retry + */ + if (self->retry == 0) { + self->retry = retry; + } + self->retry -= 1; + if (self->retry <= 0) { + _transvr_clean_retry(self); + return -1; + } + return 0; +} + +static int +_common_setup_page(struct transvr_obj_s *self, + int addr, + int page, + int offset, + int len, + int show_e) { + /* return: + * 0 : OK + * -1 : EEPROM settings incorrect + * -2 : I2C R/W failure + * -3 : Undefined case + */ + int retval = DEBUG_TRANSVR_INT_VAL; + char *emsg = DEBUG_TRANSVR_STR_VAL; + + /* Check */ + if ((addr < 0) || (offset < 0) || (len < 0)) { + emsg = "EEPROM settings incorrect"; + retval = -1; + goto err_common_setup_page; + } + /* Case1: continue access */ + if ((self->i2c_client_p->addr == addr) && + (self->curr_page == page)) { + return 0; + } + self->i2c_client_p->addr = addr; + /* Case2: select lower page */ + if (page == -1) { + self->curr_page = page; + return 0; + } + /* Case3: select upper page */ + if (page >= 0) { + goto upper_common_setup_page; + } + /* Unexpected case */ + show_e = 1; + emsg = "Unexpected case"; + retval = -3; + goto err_common_setup_page; + +upper_common_setup_page: + if (i2c_smbus_write_byte_data(self->i2c_client_p, + VAL_TRANSVR_PAGE_SELECT_OFFSET, + page) < 0) { + emsg = "I2C R/W failure"; + retval = -2; + goto err_common_setup_page; + } + self->curr_page = page; + mdelay(VAL_TRANSVR_PAGE_SELECT_DELAY); + return 0; + +err_common_setup_page: + if (show_e) { + SWPS_INFO("%s: %s", __func__, emsg); + SWPS_INFO("%s: :0x%02x :%d :%d :%d\n", + __func__, addr, page, offset, len); + } + return retval; +} + +/* ========== Object functions for Final State Machine ========== + */ +int +is_plugged(struct transvr_obj_s *self){ + + int limit = 63; + int present = DEBUG_TRANSVR_INT_VAL; + char emsg[64] = DEBUG_TRANSVR_STR_VAL; + struct ioexp_obj_s *ioexp_p = self->ioexp_obj_p; + + if (!ioexp_p) { + snprintf(emsg, limit, "ioexp_p is null!"); + goto err_is_plugged_1; + } + present = ioexp_p->get_present(ioexp_p, self->ioexp_virt_offset); + switch (present){ + case 0: + return 1; + case 1: + return 0; + case ERR_IOEXP_UNINIT: + snprintf(emsg, limit, "ioexp_p not ready!"); + goto err_is_plugged_1; + default: + if (ioexp_p->state == STATE_IOEXP_INIT){ + snprintf(emsg, limit, "ioexp_p not ready!"); + goto err_is_plugged_1; + } + break; + } + SWPS_INFO("%s: Exception case! :%d :%d\n", + __func__, present, ioexp_p->state); + return 0; + +err_is_plugged_1: + SWPS_DEBUG("%s: %s\n", __func__, emsg); + return 0; +} + + +static int +detect_transvr_type(struct transvr_obj_s* self){ + + int type = TRANSVR_TYPE_ERROR; + + self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; + type = i2c_smbus_read_byte_data(self->i2c_client_p, + VAL_TRANSVR_COMID_OFFSET); + + /* Case: 1. Wait transceiver I2C module. + * 2. Transceiver I2C module failure. + * Note: 1. SFF allow maximum transceiver initial time is 2 second. So, there + * are exist some case that we need to wait transceiver. + * For these case, we keeps status on "TRANSVR_TYPE_UNPLUGGED", than + * state machine will keep trace with it. + * 2. There exist some I2C failure case we need to handle. Such as user + * insert the failure transceiver, or any reason cause it abnormal. + */ + if (type < 0){ + switch (type) { + case -EIO: + SWPS_DEBUG("%s: %s smbus return:-5 (I/O error)\n", + __func__, self->swp_name); + return TRANSVR_TYPE_UNPLUGGED; + case -ENXIO: + SWPS_DEBUG("%s: %s smbus return:-6 (No such device or address)\n", + __func__, self->swp_name); + return TRANSVR_TYPE_UNPLUGGED; + default: + break; + } + SWPS_INFO("%s: %s unexpected smbus return:%d \n", + __func__, self->swp_name, type); + return TRANSVR_TYPE_ERROR; + } + /* Identify valid transceiver type */ + switch (type){ + case TRANSVR_TYPE_SFP: + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + case TRANSVR_TYPE_QSFP_28: + break; + case TRANSVR_TYPE_UNKNOW_1: + case TRANSVR_TYPE_UNKNOW_2: + type = TRANSVR_TYPE_UNKNOW_2; + break; + default: + SWPS_DEBUG("%s: unknow type:0x%02x \n", __func__, type); + type = TRANSVR_TYPE_ERROR; + break; + } + return type; +} + + +static int +detect_transvr_state(struct transvr_obj_s *self, + int result[2]){ + /* [return] [result-0] [result-1] + * 0 STATE_TRANSVR_CONNECTED TRANSVR_TYPE_FAKE + * 0 STATE_TRANSVR_DISCONNECTED TRANSVR_TYPE_UNPLUGGED + * 0 STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR + * 0 STATE_TRANSVR_INIT / + * 0 STATE_TRANSVR_SWAPPED + * 0 STATE_TRANSVR_CONNECTED + * ERR_TRNASVR_BE_ISOLATED STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR + * ERR_TRANSVR_I2C_CRASH STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_ERROR + * ERR_TRANSVR_UNEXCPT STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_UNKNOW_1/2 + */ + result[0] = STATE_TRANSVR_UNEXCEPTED; /* For return state */ + result[1] = TRANSVR_TYPE_ERROR; /* For return type */ + + /* Case1: Fake type */ + if (self->type == TRANSVR_TYPE_FAKE){ + result[0] = STATE_TRANSVR_CONNECTED; + result[1] = TRANSVR_TYPE_FAKE; + return 0; + } + /* Case2: Transceiver unplugged */ + if (!is_plugged(self)){ + result[0] = STATE_TRANSVR_DISCONNECTED; + result[1] = TRANSVR_TYPE_UNPLUGGED; + return 0; + } + /* Case3: Transceiver be isolated */ + if (self->state == STATE_TRANSVR_ISOLATED){ + result[0] = STATE_TRANSVR_ISOLATED; + result[1] = TRANSVR_TYPE_ERROR; + return ERR_TRNASVR_BE_ISOLATED; + } + /* Case4: Transceiver plugged */ + result[1] = detect_transvr_type(self); + /* Case4.1: I2C topology crash + * Note : There are some I2C issues cause by transceiver/cables. + * We need to check topology status when user insert it. + * But in this step, we can't not ensure this is the issues + * port. So, it return the ERR_TRANSVR_I2C_CRASH, then upper + * layer will diagnostic I2C topology. + */ + if (check_channel_tier_1() < 0) { + SWPS_INFO("%s: %s detect I2C crash :%d\n", + __func__, self->swp_name, self->state); + result[0] = STATE_TRANSVR_UNEXCEPTED; + result[1] = TRANSVR_TYPE_ERROR; + return ERR_TRANSVR_I2C_CRASH; + } + /* Case4.2: System initial not ready, + * Note : Sometime i2c channel or transceiver EEPROM will delay that will + * cause system in inconsistent state between EEPROM and IOEXP. + * In this case, SWP transceiver object keep state at LINK_DOWN + * to wait system ready. + * By the way, State Machine will handle these case. + */ + if (result[1] == TRANSVR_TYPE_UNPLUGGED){ + result[0] = STATE_TRANSVR_DISCONNECTED; + return 0; + } + /* Case4.3: Error transceiver type */ + if (result[1] == TRANSVR_TYPE_ERROR){ + result[0] = STATE_TRANSVR_ISOLATED; + SWPS_INFO("%s: %s detect error type\n", __func__, self->swp_name); + alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard!"); + return ERR_TRNASVR_BE_ISOLATED; + } + /* Case3.3: Unknow transceiver type */ + if ((result[1] == TRANSVR_TYPE_UNKNOW_1) || + (result[1] == TRANSVR_TYPE_UNKNOW_2) ){ + result[0] = STATE_TRANSVR_UNEXCEPTED; + return ERR_TRANSVR_UNEXCPT; + } + /* Case3.4: During initial process */ + if (self->state == STATE_TRANSVR_INIT){ + result[0] = STATE_TRANSVR_INIT; + return 0; + } + /* Case3.5: Transceiver be swapped */ + if (self->type != result[1]){ + result[0] = STATE_TRANSVR_SWAPPED; + return 0; + } + /* Case3.6: Link up state */ + result[0] = STATE_TRANSVR_CONNECTED; + return 0; +} +int +common_fsm_4_direct_mode(struct transvr_obj_s* self, + char *caller_name){ + + int err; + int detect_result[2]; + int current_state = STATE_TRANSVR_UNEXCEPTED; + int current_type = TRANSVR_TYPE_ERROR; + + if (self->state == STATE_TRANSVR_NEW) { + if (_transvr_init_handler(self) < 0){ + return ERR_TRANSVR_INIT_FAIL; + } + } + err = detect_transvr_state(self, detect_result); + if (err < 0) { + return err; + } + /* In Direct mode, driver only detect transceiver when user call driver interface + * which on sysfs. So it only need consider the state of Transceiver. + */ + current_state = detect_result[0]; + current_type = detect_result[1]; + + switch (current_state){ + + case STATE_TRANSVR_DISCONNECTED: /* Transceiver is not plugged */ + self->state = current_state; + self->type = current_type; + return ERR_TRANSVR_UNPLUGGED; + + case STATE_TRANSVR_INIT: /* Transceiver is plugged, system not ready */ + return ERR_TRANSVR_UNINIT; + + case STATE_TRANSVR_ISOLATED: /* Transceiver is plugged, but has some issues */ + return ERR_TRNASVR_BE_ISOLATED; + + case STATE_TRANSVR_CONNECTED: /* Transceiver is plugged, system is ready */ + self->state = current_state; + self->type = current_type; + return 0; + + case STATE_TRANSVR_SWAPPED: /* Transceiver is plugged, system detect user changed */ + self->type = current_type; + if (reload_transvr_obj(self, current_type) < 0){ + self->state = STATE_TRANSVR_UNEXCEPTED; + return ERR_TRANSVR_UNEXCPT; + } + self->state = current_state; + return 0; + + case STATE_TRANSVR_UNEXCEPTED: /* Transceiver type or state is unexpected case */ + self->state = STATE_TRANSVR_UNEXCEPTED; + self->type = TRANSVR_TYPE_ERROR; + return ERR_TRANSVR_UNEXCPT; + + default: + SWPS_INFO("%s: state:%d not in define.\n", __func__, current_state); + break; + } + return ERR_TRANSVR_UNEXCPT; +} + +int +fake_fsm_4_direct_mode(struct transvr_obj_s* self, + char *caller_name){ + self->state = STATE_TRANSVR_CONNECTED; + self->type = TRANSVR_TYPE_FAKE; + return 0; +} + +/* ========== Object Initial handler ========== + */ +static int +_is_transvr_valid(struct transvr_obj_s *self, + int type, + int state) { + /* [Return] + * 0 : OK, inserted + * EVENT_TRANSVR_INIT_DOWN : OK, removed + * EVENT_TRANSVR_INIT_FAIL : Outside error, type doesn't supported + * EVENT_TRANSVR_EXCEP_INIT : Internal error, state undefined + */ + switch (type) { + case TRANSVR_TYPE_SFP: + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + case TRANSVR_TYPE_QSFP_28: + case TRANSVR_TYPE_UNPLUGGED: + case TRANSVR_TYPE_FAKE: + break; + default: + SWPS_INFO("detect undefined type:0x%02x on %s\n", + type, self->swp_name); + return EVENT_TRANSVR_INIT_FAIL; + } + switch (state) { + case STATE_TRANSVR_DISCONNECTED: + return EVENT_TRANSVR_INIT_DOWN; + case STATE_TRANSVR_INIT: + case STATE_TRANSVR_CONNECTED: + case STATE_TRANSVR_SWAPPED: + break; + default: + SWPS_INFO("detect undefined state:%d on %s\n", + state, self->swp_name); + return EVENT_TRANSVR_EXCEP_INIT; + } + return 0; +} + + +static int +_is_transvr_hw_ready(struct transvr_obj_s *self, + int type){ + /* [Return] + * EVENT_TRANSVR_TASK_DONE : Ready + * EVENT_TRANSVR_TASK_WAIT : Not ready + * EVENT_TRANSVR_INIT_FAIL : Error + */ + int addr = DEBUG_TRANSVR_INT_VAL; + int page = DEBUG_TRANSVR_INT_VAL; + int offs = DEBUG_TRANSVR_INT_VAL; + int bit = DEBUG_TRANSVR_INT_VAL; + int ready = DEBUG_TRANSVR_INT_VAL; + int err = DEBUG_TRANSVR_INT_VAL; + char *emsg = DEBUG_TRANSVR_STR_VAL; + uint8_t ab_val = DEBUG_TRANSVR_HEX_VAL; + + switch (type) { + case TRANSVR_TYPE_SFP: + addr = VAL_TRANSVR_8472_READY_ADDR; + page = VAL_TRANSVR_8472_READY_PAGE; + offs = VAL_TRANSVR_8472_READY_OFFSET; + bit = VAL_TRANSVR_8472_READY_BIT; + ready = VAL_TRANSVR_8472_READY_VALUE; + ab_val = VAL_TRANSVR_8472_READY_ABNORMAL; + break; + + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + case TRANSVR_TYPE_QSFP_28: + addr = VAL_TRANSVR_8436_READY_ADDR; + page = VAL_TRANSVR_8436_READY_PAGE; + offs = VAL_TRANSVR_8436_READY_OFFSET; + bit = VAL_TRANSVR_8436_READY_BIT; + ready = VAL_TRANSVR_8436_READY_VALUE; + ab_val = VAL_TRANSVR_8436_READY_ABNORMAL; + break; + + case TRANSVR_TYPE_UNPLUGGED: + case TRANSVR_TYPE_FAKE: + return EVENT_TRANSVR_TASK_DONE; + + default: + emsg = "unexpected case"; + goto err_is_transvr_hw_ready; + } + /* Select target page */ + err = _common_setup_page(self, addr, page, offs, 1, 0); + if (err < 0) { + emsg = "setup page fail"; + goto err_is_transvr_hw_ready; + } + /* Check feature supported + * [Note] + * Some of transceiver/cables doesn't support "Status Indicators" + * (ex:DAC, RJ45 copper SFP ...etc). In these case, we bypass the + * step of checking Status Indicators, then state machine will take + * the following handle procedure. + */ + err = i2c_smbus_read_byte_data(self->i2c_client_p, + VAL_TRANSVR_COMID_OFFSET); + if (err < 0) { + emsg = "doesn't support Status Indicators"; + goto bypass_is_transvr_hw_ready; + } + /* Filter abnormal case */ + if (err == ab_val) { + emsg = "detect using unusual definition."; + goto bypass_is_transvr_hw_ready; + } + /* Get Status Indicators */ + err = i2c_smbus_read_byte_data(self->i2c_client_p, offs); + if (err < 0) { + emsg = "detect current value fail"; + goto err_is_transvr_hw_ready; + } + if ((err & (1<:%d\n", __func__, emsg, type); + return EVENT_TRANSVR_TASK_DONE; + +err_is_transvr_hw_ready: + SWPS_DEBUG("%s: %s :%d\n", __func__, emsg, type); + return EVENT_TRANSVR_INIT_FAIL; +} + +static int +_transvr_init_handler(struct transvr_obj_s *self){ + + int detect[2]; + int d_state = STATE_TRANSVR_UNEXCEPTED; + int d_type = TRANSVR_TYPE_ERROR; + int result = ERR_TRANSVR_UNINIT; + int retry = 6; /* (6+1) x 0.3 = 2.1s > spec:2.0s */ + int elimit = 63; + char emsg[64] = DEBUG_TRANSVR_STR_VAL; + + /* Clean and check callback */ + self->state = STATE_TRANSVR_INIT; + if (self->init == NULL) { + snprintf(emsg, elimit, "init() is null"); + goto initer_err_case_unexcept_0; + } + /* Detect transceiver information */ + result = detect_transvr_state(self, detect); + if (result < 0) { + snprintf(emsg, elimit, "detect_transvr_state() fail"); + switch (result) { + case ERR_TRANSVR_I2C_CRASH: + goto initer_err_case_i2c_ceash; + case ERR_TRNASVR_BE_ISOLATED: + goto initer_err_case_be_isolated; + + case ERR_TRANSVR_UNEXCPT: + default: + break; + } + goto initer_err_case_retry_1; + } + d_state = detect[0]; + d_type = detect[1]; + + /* Verify transceiver type and state */ + switch (_is_transvr_valid(self, d_type, d_state)) { + case 0: + break; + case EVENT_TRANSVR_INIT_DOWN: + goto initer_ok_case_down;; + case EVENT_TRANSVR_INIT_FAIL: + snprintf(emsg, elimit, "transceiver type doesn't support"); + goto initer_err_case_alarm_to_user; + case EVENT_TRANSVR_EXCEP_INIT: + default: + goto initer_err_case_unexcept_0; + } + + /* Handle reload case */ + if (self->type != d_type){ + /* This is the protect mechanism. Normally, This case will not happen. + * When State machine detect swap event during initial, It will trigger + * reload function to ensure type correct. */ + if (_reload_transvr_obj(self, d_type) < 0){ + snprintf(emsg, elimit, "reload object fail"); + goto initer_err_case_unexcept_0; + } + } + + /* Check transceiver HW initial ready */ + switch (_is_transvr_hw_ready(self, d_type)) { + case EVENT_TRANSVR_TASK_DONE: + break; + case EVENT_TRANSVR_TASK_WAIT: + goto initer_err_case_retry_1; + case EVENT_TRANSVR_INIT_FAIL: + default: + goto initer_err_case_unexcept_0; + } + + /* Try to update all and check */ + if (self->update_all(self, 1) < 0){ + /* For some transceiver, EEPROME has lag issues during initial stage. + * In this case, we set status back to STATE_TRANSVR_NEW, than it will + * be checked in next polling cycle. */ + goto initer_err_case_retry_1; + } + + /* Execute init() call back */ + result = self->init(self); + switch (result) { + case EVENT_TRANSVR_TASK_DONE: + break; + case EVENT_TRANSVR_TASK_WAIT: + goto initer_ok_case_wait; + + default: + snprintf(emsg, elimit, "undefined init() return:%d\n", result); + goto initer_err_case_unexcept_0; + } + goto initer_ok_case_up; + + +initer_ok_case_wait: + return EVENT_TRANSVR_TASK_WAIT; + +initer_ok_case_up: + self->state = STATE_TRANSVR_CONNECTED; + self->temp = 0; + return EVENT_TRANSVR_INIT_UP; + +initer_ok_case_down: + self->temp = 0; + self->state = STATE_TRANSVR_DISCONNECTED; + return EVENT_TRANSVR_INIT_DOWN; + +initer_err_case_i2c_ceash: + SWPS_DEBUG("%s: %s :%s :I2C crash\n", + __func__, emsg, self->swp_name); + self->state = STATE_TRANSVR_UNEXCEPTED; + return EVENT_TRANSVR_I2C_CRASH; + +initer_err_case_be_isolated: + SWPS_DEBUG("%s: %s :%s :isolated\n", + __func__, emsg, self->swp_name); + self->state = STATE_TRANSVR_ISOLATED; + return EVENT_TRANSVR_EXCEP_ISOLATED; + +initer_err_case_retry_1: + SWPS_DEBUG("%s: %s :%s :retry\n", + __func__, emsg, self->swp_name); + if (_transvr_handle_retry(self, retry) == 0) { + self->state = STATE_TRANSVR_NEW; + return EVENT_TRANSVR_INIT_REINIT; + } + goto initer_err_case_alarm_to_user; + +initer_err_case_unexcept_0: + self->state = STATE_TRANSVR_UNEXCEPTED; + return EVENT_TRANSVR_INIT_FAIL; + +initer_err_case_alarm_to_user: + SWPS_DEBUG("%s: %s :%s :alarm_to_user\n", + __func__, emsg, self->swp_name); + self->state = STATE_TRANSVR_UNEXCEPTED; + alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard"); + return EVENT_TRANSVR_INIT_FAIL; +} + +static int +setup_transvr_private_cb(struct transvr_obj_s *self, + int transvr_type){ + switch (transvr_type){ + case TRANSVR_TYPE_SFP: + self->fsm_4_direct = common_fsm_4_direct_mode; + return 0; + + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + self->fsm_4_direct = common_fsm_4_direct_mode; + return 0; + + case TRANSVR_TYPE_QSFP_28: + self->fsm_4_direct = common_fsm_4_direct_mode; + return 0; + + case TRANSVR_TYPE_FAKE: + self->fsm_4_direct = fake_fsm_4_direct_mode; + return 0; + + default: + break; + } + SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); + return ERR_TRANSVR_UNEXCPT; +} + + +static struct eeprom_map_s * +get_eeprom_map(int transvr_type){ + + switch (transvr_type){ + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + return &eeprom_map_qsfp; + case TRANSVR_TYPE_QSFP_28: + return &eeprom_map_qsfp28; + + default: + break; + } + SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); + return NULL; +} + + +static int +setup_transvr_ssize_attr(char *swp_name, + struct transvr_obj_s *self, + struct eeprom_map_s *map_p, + struct ioexp_obj_s *ioexp_obj_p, + int ioexp_virt_offset, + int transvr_type, + int chipset_type, + int chan_id, + int run_mode){ + switch (run_mode){ + case TRANSVR_MODE_DIRECT: /* Direct access device mode */ + self->mode = run_mode; + break; + default: + SWPS_ERR("%s: non-defined run_mode:%d\n", + __func__, run_mode); + self->mode = DEBUG_TRANSVR_INT_VAL; + return -1; + } + self->eeprom_map_p = map_p; + self->ioexp_obj_p = ioexp_obj_p; + self->ioexp_virt_offset = ioexp_virt_offset; + self->chan_id = chan_id; + self->layout = transvr_type; + self->type = transvr_type; + self->chipset_type = chipset_type; + self->state = STATE_TRANSVR_NEW; + self->info = STATE_TRANSVR_NEW; + self->auto_tx_disable = VAL_TRANSVR_FUNCTION_DISABLE; + strncpy(self->swp_name, swp_name, 32); + mutex_init(&self->lock); + return 0; +} + + + +static int +setup_i2c_client(struct transvr_obj_s *self){ + + struct i2c_adapter *adap = NULL; + struct i2c_client *client = NULL; + char err_msg[64] = DEBUG_TRANSVR_STR_VAL; + + adap = i2c_get_adapter(self->chan_id); + if(!adap){ + snprintf(err_msg, sizeof(err_msg), + "can not get adap:%d", self->chan_id); + goto err_setup_i2c_client; + } + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client){ + snprintf(err_msg, sizeof(err_msg), + "can not kzalloc client:%d", self->chan_id); + goto err_setup_i2c_client; + } + client->adapter = adap; + self->i2c_client_p = client; + self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; + return 0; + +err_setup_i2c_client: + SWPS_ERR("%s: %s\n", __func__, err_msg); + return ERR_TRANSVR_UNEXCPT; +} + + +struct transvr_obj_s * +create_transvr_obj(char *swp_name, + int chan_id, + struct ioexp_obj_s *ioexp_obj_p, + int ioexp_virt_offset, + int transvr_type, + int chipset_type, + int run_mode){ + + struct transvr_obj_s *result_p; + struct eeprom_map_s *map_p; + char err_msg[64] = DEBUG_TRANSVR_STR_VAL; + + /* Allocate transceiver object */ + map_p = get_eeprom_map(transvr_type); + if (!map_p){ + snprintf(err_msg, sizeof(err_msg), + "Invalid transvr_type:%d", transvr_type); + goto err_create_transvr_fail; + } + result_p = kzalloc(sizeof(*result_p), GFP_KERNEL); + if (!result_p){ + snprintf(err_msg, sizeof(err_msg), "kzalloc fail"); + goto err_create_transvr_fail; + } + /* Prepare static size attributes */ + if (setup_transvr_ssize_attr(swp_name, + result_p, + map_p, + ioexp_obj_p, + ioexp_virt_offset, + transvr_type, + chipset_type, + chan_id, + run_mode) < 0){ + goto err_create_transvr_sattr_fail; + } + + /* Prepare call back functions of object */ + if (setup_transvr_private_cb(result_p, transvr_type) < 0){ + goto err_create_transvr_sattr_fail; + } + /* Prepare i2c client object */ + if (setup_i2c_client(result_p) < 0){ + goto err_create_transvr_sattr_fail; + } + return result_p; +err_create_transvr_sattr_fail: + kfree(result_p); +err_create_transvr_fail: + SWPS_ERR("%s: %s :%d :%d :%d\n", + __func__, err_msg, chan_id, ioexp_virt_offset, transvr_type); + return NULL; +} + + +static int +_reload_transvr_obj(struct transvr_obj_s *self, + int new_type){ + + struct eeprom_map_s *new_map_p; + struct eeprom_map_s *old_map_p = self->eeprom_map_p; + struct i2c_client *old_i2c_p = self->i2c_client_p; + int old_type = self->type; + + /* Change state to STATE_TRANSVR_INIT */ + self->state = STATE_TRANSVR_INIT; + self->type = new_type; + /* Replace EEPROME map */ + new_map_p = get_eeprom_map(new_type); + if (!new_map_p){ + goto err_private_reload_func_1; + } + self->eeprom_map_p = new_map_p; + /* Reload i2c client */ + if (setup_i2c_client(self) < 0){ + goto err_private_reload_func_2; + } + if (setup_transvr_private_cb(self, new_type) < 0){ + goto err_private_reload_func_3; + } + kfree(old_i2c_p); + return 0; + +err_private_reload_func_3: + SWPS_INFO("%s: init() fail!\n", __func__); + kfree(old_i2c_p); + self->state = STATE_TRANSVR_UNEXCEPTED; + self->type = TRANSVR_TYPE_ERROR; + return -2; + +err_private_reload_func_2: + self->eeprom_map_p = old_map_p; + self->i2c_client_p = old_i2c_p; +err_private_reload_func_1: + self->state = STATE_TRANSVR_UNEXCEPTED; + self->type = old_type; + SWPS_INFO("%s fail! :0x%02x\n", __func__, new_type); + return -1; +} + + +static int +reload_transvr_obj(struct transvr_obj_s *self, + int new_type){ + + int result_val = ERR_TRANSVR_UNEXCPT; + + /* Reload phase */ + result_val = _reload_transvr_obj(self, new_type); + if (result_val < 0){ + SWPS_INFO("%s: reload phase fail! :%d\n", + __func__, result_val); + return EVENT_TRANSVR_RELOAD_FAIL; + } + /* Initial phase */ + result_val = _transvr_init_handler(self); + if (result_val < 0){ + SWPS_INFO("%s: initial phase fail! :%d\n", + __func__, result_val); + } + return result_val; +} + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h new file mode 100644 index 000000000000..487fcdd76773 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/modules/transceiver.h @@ -0,0 +1,167 @@ +#ifndef TRANSCEIVER_H +#define TRANSCEIVER_H + +#include + +/* Transceiver type define */ +#define TRANSVR_TYPE_UNKNOW_1 (0x00) +#define TRANSVR_TYPE_UNKNOW_2 (0xff) +#define TRANSVR_TYPE_SFP (0x03) /* Define for SFP, SFP+, SFP28 */ +#define TRANSVR_TYPE_QSFP (0x0c) +#define TRANSVR_TYPE_QSFP_PLUS (0x0d) +#define TRANSVR_TYPE_QSFP_28 (0x11) +#define TRANSVR_TYPE_UNPLUGGED (0xfa) /* Define for ERROR handle */ +#define TRANSVR_TYPE_FAKE (0xfc) /* Define for ERROR handle */ +#define TRANSVR_TYPE_INCONSISTENT (0xfd) /* Define for ERROR handle */ +#define TRANSVR_TYPE_ERROR (0xfe) /* Define for ERROR handle */ + +/* Transceiver mode define */ +#define TRANSVR_MODE_DIRECT (21000) + +/* Transceiver state define + * [Note] + * 1. State is used to represent the state of "Transceiver" and "Object". + * 2. State for different target has different means. The description as following: + */ +#define STATE_TRANSVR_CONNECTED (0) /* [Transvr]:Be plugged in. [Obj]:Link up, and work normally. */ +#define STATE_TRANSVR_NEW (-100) /* [Transvr]:(Not used) [Obj]:Create */ +#define STATE_TRANSVR_INIT (-101) /* [Transvr]:Be plugged in. [Obj]:Link up, and in initial process. */ +#define STATE_TRANSVR_ISOLATED (-102) /* [Transvr]:Be plugged in. [Obj]:Isolate, and not provide service. */ +#define STATE_TRANSVR_SWAPPED (-200) /* [Transvr]:Be plugged in. [Obj]:(Not used) */ +#define STATE_TRANSVR_DISCONNECTED (-300) /* [Transvr]:Un-plugged. [Obj]:Link down, and not provide service. */ +#define STATE_TRANSVR_UNEXCEPTED (-901) /* [Transvr]:Any [Obj]:Any, and not in expect case. */ + +/* Event for task handling */ +#define EVENT_TRANSVR_TASK_WAIT (2101) +#define EVENT_TRANSVR_TASK_DONE (0) +#define EVENT_TRANSVR_TASK_FAIL (-2101) +/* Event for initial handling */ +#define EVENT_TRANSVR_INIT_UP (2201) +#define EVENT_TRANSVR_INIT_DOWN (1) +#define EVENT_TRANSVR_INIT_REINIT (-2201) +#define EVENT_TRANSVR_INIT_FAIL (-2202) +/* Event for others */ +#define EVENT_TRANSVR_RELOAD_FAIL (-2301) +#define EVENT_TRANSVR_EXCEP_INIT (-2401) +#define EVENT_TRANSVR_EXCEP_UP (-2402) +#define EVENT_TRANSVR_EXCEP_DOWN (-2403) +#define EVENT_TRANSVR_EXCEP_SWAP (-2404) +#define EVENT_TRANSVR_EXCEP_EXCEP (-2405) +#define EVENT_TRANSVR_EXCEP_ISOLATED (-2406) +#define EVENT_TRANSVR_I2C_CRASH (-2501) + +/* Transceiver error code define */ +#define ERR_TRANSVR_UNINIT (-201) +#define ERR_TRANSVR_UNPLUGGED (-202) +#define ERR_TRANSVR_ABNORMAL (-203) +#define ERR_TRANSVR_NOSTATE (-204) +#define ERR_TRANSVR_NOTSUPPORT (-205) +#define ERR_TRANSVR_BADINPUT (-206) +#define ERR_TRANSVR_UPDATE_FAIL (-207) +#define ERR_TRANSVR_RELOAD_FAIL (-208) +#define ERR_TRANSVR_INIT_FAIL (-209) +#define ERR_TRANSVR_UNDEFINED (-210) +#define ERR_TRANSVR_TASK_FAIL (-211) +#define ERR_TRANSVR_TASK_BUSY (-212) +#define ERR_TRANSVR_FUNC_DISABLE (-214) +#define ERR_TRANSVR_I2C_CRASH (-297) +#define ERR_TRNASVR_BE_ISOLATED (-298) +#define ERR_TRANSVR_UNEXCPT (-299) + +/* For debug */ +#define DEBUG_TRANSVR_INT_VAL (-99) +#define DEBUG_TRANSVR_HEX_VAL (0xfe) +#define DEBUG_TRANSVR_STR_VAL "ERROR" + +/* For system internal */ +#define VAL_TRANSVR_COMID_ARREESS (0x50) +#define VAL_TRANSVR_COMID_OFFSET (0x00) +#define VAL_TRANSVR_8472_READY_ADDR (0x51) +#define VAL_TRANSVR_8472_READY_PAGE (-1) +#define VAL_TRANSVR_8472_READY_OFFSET (110) +#define VAL_TRANSVR_8472_READY_BIT (0) +#define VAL_TRANSVR_8472_READY_VALUE (0) +#define VAL_TRANSVR_8472_READY_ABNORMAL (0xff) +#define VAL_TRANSVR_8436_READY_ADDR (0x50) +#define VAL_TRANSVR_8436_READY_PAGE (-1) +#define VAL_TRANSVR_8436_READY_OFFSET (2) +#define VAL_TRANSVR_8436_READY_BIT (0) +#define VAL_TRANSVR_8436_READY_VALUE (0) +#define VAL_TRANSVR_8436_READY_ABNORMAL (0xff) +#define VAL_TRANSVR_8436_PWD_ADDR (0x50) +#define VAL_TRANSVR_8436_PWD_PAGE (-1) +#define VAL_TRANSVR_8436_PWD_OFFSET (123) +#define VAL_TRANSVR_PAGE_FREE (-99) +#define VAL_TRANSVR_PAGE_SELECT_OFFSET (127) +#define VAL_TRANSVR_PAGE_SELECT_DELAY (5) +#define VAL_TRANSVR_TASK_RETRY_FOREVER (-999) +#define VAL_TRANSVR_FUNCTION_DISABLE (-1) +#define STR_TRANSVR_QSFP "QSFP" +#define STR_TRANSVR_QSFP_PLUS "QSFP+" +#define STR_TRANSVR_QSFP28 "QSFP28" + +/* BCM chip type define */ +#define BCM_CHIP_TYPE_TOMAHAWK (31002) /* Redwood, Cypress */ + +/* Info from transceiver EEPROM */ +struct eeprom_map_s { + int addr_rx_los; int page_rx_los; int offset_rx_los; int length_rx_los; + int addr_tx_disable; int page_tx_disable; int offset_tx_disable; int length_tx_disable; + int addr_tx_fault; int page_tx_fault; int offset_tx_fault; int length_tx_fault; +}; + +/* Class of transceiver object */ +struct transvr_obj_s { + /* ========== Object private property ========== + */ + struct device *transvr_dev_p; + struct eeprom_map_s *eeprom_map_p; + struct i2c_client *i2c_client_p; + struct ioexp_obj_s *ioexp_obj_p; + struct mutex lock; + char swp_name[32]; + int auto_tx_disable; + int chan_id; + int chipset_type; + int curr_page; + int info; + int ioexp_virt_offset; + int lane_id[8]; + int layout; + int mode; + int retry; + int state; + int temp; + int type; + + /* ========== Object private functions ========== + */ + int (*init)(struct transvr_obj_s *self); + int (*update_all)(struct transvr_obj_s *self, int show_err); + int (*fsm_4_direct)(struct transvr_obj_s* self, char *caller_name); +}; + + +/* For AVL Mapping */ +struct transvr_avl_s { + char vendor_name[32]; + char vendor_pn[32]; + int (*init)(struct transvr_obj_s *self); +}; + +struct transvr_obj_s * +create_transvr_obj(char *swp_name, + int chan_id, + struct ioexp_obj_s *ioexp_obj_p, + int ioexp_virt_offset, + int transvr_type, + int chipset_type, + int run_mode); + +void alarm_msg_2_user(struct transvr_obj_s *self, char *emsg); + +#endif /* TRANSCEIVER_H */ + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py new file mode 100755 index 000000000000..f6f5e46c5536 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/inventec_d7032_util.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Inventec, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +from collections import namedtuple + +DEBUG = False +args = [] +FORCE = 0 +i2c_prefix = '/sys/bus/i2c/devices/' + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + install() + elif arg == 'clean': + uninstall() + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_log(txt): + if DEBUG == True: + print "[D7032]"+txt + return + +def exec_cmd(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + show_log (cmd +"with result:" + str(status)) + show_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +instantiate =[ +#'echo pca9545 0x70> /sys/bus/i2c/devices/i2c-0/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-1/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-2/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-3/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-4/new_device', +#'echo inv_psoc 0x66> /sys/bus/i2c/devices/i2c-5/new_device', +#'echo inv_cpld 0x55> /sys/bus/i2c/devices/i2c-5/new_device', +'echo inv_eeprom 0x53> /sys/bus/i2c/devices/i2c-0/new_device'] + +drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-mux', +'i2c-mux-pca954x', +'i2c-dev', +'inv_eeprom', +'inv_platform', +'inv_psoc', +'inv_cpld', +'swps'] + + + +def system_install(): + global FORCE + + #remove default drivers to avoid modprobe order conflicts + status, output = exec_cmd("rmmod i2c_ismt ", 1) + status, output = exec_cmd("rmmod i2c-i801 ", 1) + #install drivers + for i in range(0,len(drivers)): + status, output = exec_cmd("modprobe "+drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + + #instantiate devices + for i in range(0,len(instantiate)): + time.sleep(1) + status, output = exec_cmd(instantiate[i], 1) + if status: + print output + if FORCE == 0: + return status + + for i in range(22,30): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-4/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(30,38): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-5/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(6,14): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-2/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(14,22): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-3/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + return + + +def system_ready(): + if not device_found(): + return False + return True + +def install(): + if not device_found(): + print "No device, installing...." + status = system_install() + if status: + if FORCE == 0: + return status + else: + print " D7032 devices detected...." + return + +def uninstall(): + global FORCE + #uninstall drivers + for i in range(len(drivers)-1,-1,-1): + status, output = exec_cmd("rmmod "+drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + return + +def device_found(): + ret1, log = exec_cmd("ls "+i2c_prefix+"*0072", 0) + ret2, log = exec_cmd("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/onie-syseeprom b/platform/broadcom/sonic-platform-modules-inventec/d7032q28b/utils/onie-syseeprom deleted file mode 100755 index b8e3ba26a5d24bc70f970c24364a61cbfa0abf10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 921685 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

UCM}yocoz1wzq-Y3g~I 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

3ldnE1ZCNQfUc~ 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%0DnGRQI4{ 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 diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile new file mode 100755 index 000000000000..aeffa4376588 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/Makefile @@ -0,0 +1,6 @@ +obj-m += inv_cpld.o inv_psoc.o +obj-m += inv_platform.o +obj-m += inv_eeprom.o +obj-m += swps.o +swps-objs := inv_swps.o io_expander.o transceiver.o + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c new file mode 100644 index 000000000000..683ffa0ff3ce --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_cpld.c @@ -0,0 +1,415 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "I2CHostCommunication.h" + +#define USE_SMBUS 1 + +/* definition */ +#define CPLD_INFO_OFFSET 0x00 +#define CPLD_PSU_OFFSET 0x08 +#define CPLD_LED_OFFSET 0x0E +#define CPLD_LED_STATU_OFFSET 0x0D +#define CPLD_CTL_OFFSET 0x0C + + + +/* Each client has this additional data */ +struct cpld_data { + struct device *hwmon_dev; + struct mutex update_lock; +}; + +/*-----------------------------------------------------------------------*/ + +static ssize_t cpld_i2c_read(struct i2c_client *client, u8 *buf, u8 offset, size_t count) +{ +#if USE_SMBUS + int i; + + for(i=0; iaddr; + msg[0].buf = msgbuf; + msg[0].len = 1; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + status = i2c_transfer(client->adapter, msg, 2); + + if(status == 2) + status = count; + + return status; +#endif +} + +static ssize_t cpld_i2c_write(struct i2c_client *client, char *buf, unsigned offset, size_t count) +{ +#if USE_SMBUS + int i; + + for(i=0; iaddr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = writebuf; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + + return status; +#endif +} + +/*-----------------------------------------------------------------------*/ + +/* sysfs attributes for hwmon */ + +static ssize_t show_info(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 status; + //struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 b[4]; + + memset(b, 0, 4); + + mutex_lock(&data->update_lock); + status = cpld_i2c_read(client, b, CPLD_INFO_OFFSET, 4); + mutex_unlock(&data->update_lock); + + if(status != 4) return sprintf(buf, "read cpld info fail\n"); + + status = sprintf (buf, "The CPLD release date is %02d/%02d/%d.\n", b[2] & 0xf, (b[3] & 0x1f), 2014+(b[2] >> 4)); /* mm/dd/yyyy*/ + status = sprintf (buf, "%sThe PCB version is %X%X\n", buf, b[0]>>4, b[0]&0xf); + status = sprintf (buf, "%sThe CPLD version is %d.%d\n", buf, b[1]>>4, b[1]&0xf); + + return strlen(buf); +} + + +static ssize_t show_ctl(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 status; + //struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 b[1]; + + mutex_lock(&data->update_lock); + + status = cpld_i2c_read(client, b, CPLD_CTL_OFFSET, 1); + + mutex_unlock(&data->update_lock); + + if(status != 1) return sprintf(buf, "read cpld ctl fail\n"); + + + status = sprintf (buf, "0x%X\n", b[0]); + + return strlen(buf); +} + +static ssize_t set_ctl(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + //struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 byte; + + u8 temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + cpld_i2c_read(client, &byte, CPLD_CTL_OFFSET, 1); + if(temp) byte |= (1<<0); + else byte &= ~(1<<0); + cpld_i2c_write(client, &byte, CPLD_CTL_OFFSET, 1); + mutex_unlock(&data->update_lock); + + return count; +} + + +static char* led_str[] = { + "OFF", //000 + "0.5 Hz", //001 + "1 Hz", //010 + "2 Hz", //011 + "NA", //100 + "NA", //101 + "NA", //110 + "ON", //111 +}; + +static ssize_t show_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 byte; + int shift = (attr->index == 0)?3:0; + + mutex_lock(&data->update_lock); + status = cpld_i2c_read(client, &byte, CPLD_LED_OFFSET, 1); + mutex_unlock(&data->update_lock); + + if(status != 1) return sprintf(buf, "read cpld offset 0x%x\n", CPLD_LED_OFFSET); + + byte = (byte >> shift) & 0x7; + + /* + 0: off + 1: 0.5hz + 2: 1 hz + 3: 2 hz + 4~6: not define + 7: on + */ + + status = sprintf (buf, "%d: %s\n", byte, led_str[byte]); + + return strlen(buf); +} + +static ssize_t set_led(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + + u8 temp = simple_strtol(buf, NULL, 16); + u8 byte; + int shift = (attr->index == 0)?3:0; + + temp &= 0x7; + //validate temp value: 0,1,2,3,7, TBD + + mutex_lock(&data->update_lock); + cpld_i2c_read(client, &byte, CPLD_LED_OFFSET, 1); + byte &= ~(0x7<update_lock); + + return count; +} + +/* +CPLD report the PSU0 status +000 = PSU normal operation +100 = PSU fault +010 = PSU unpowered +111 = PSU not installed + +7 6 | 5 4 3 | 2 1 0 +---------------------- + | psu0 | psu1 +*/ +static char* psu_str[] = { + "normal", //000 + "NA", //001 + "unpowered", //010 + "NA", //011 + "fault", //100 + "NA", //101 + "NA", //110 + "not installed", //111 +}; + +static ssize_t show_psu(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 byte; + int shift = (attr->index == 1)?0:3; + + mutex_lock(&data->update_lock); + status = cpld_i2c_read(client, &byte, CPLD_PSU_OFFSET, 1); + mutex_unlock(&data->update_lock); + + byte = (byte >> shift) & 0x7; + + status = sprintf (buf, "%d : %s\n", byte, psu_str[byte]); + + return strlen(buf); +} + + +static SENSOR_DEVICE_ATTR(info, S_IRUGO, show_info, 0, 0); +static SENSOR_DEVICE_ATTR(ctl, S_IWUSR|S_IRUGO, show_ctl, set_ctl, 0); + +static SENSOR_DEVICE_ATTR(grn_led, S_IWUSR|S_IRUGO, show_led, set_led, 0); +static SENSOR_DEVICE_ATTR(red_led, S_IWUSR|S_IRUGO, show_led, set_led, 1); + +static SENSOR_DEVICE_ATTR(psu0, S_IRUGO, show_psu, 0, 0); +static SENSOR_DEVICE_ATTR(psu1, S_IRUGO, show_psu, 0, 1); + +static struct attribute *cpld_attributes[] = { + //info + &sensor_dev_attr_info.dev_attr.attr, + &sensor_dev_attr_ctl.dev_attr.attr, + + &sensor_dev_attr_grn_led.dev_attr.attr, + &sensor_dev_attr_red_led.dev_attr.attr, + + &sensor_dev_attr_psu0.dev_attr.attr, + &sensor_dev_attr_psu1.dev_attr.attr, + + NULL +}; + +static const struct attribute_group cpld_group = { + .attrs = cpld_attributes, +}; + +/*-----------------------------------------------------------------------*/ + +/* device probe and removal */ + +static int +cpld_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct cpld_data *data; + int status; + + printk("+%s\n", __func__); + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &cpld_group); + if (status) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: sensor '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &cpld_group); +exit_free: + i2c_set_clientdata(client, NULL); + kfree(data); + return status; +} + +static int cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &cpld_group); + i2c_set_clientdata(client, NULL); + kfree(data); + return 0; +} + +static const struct i2c_device_id cpld_ids[] = { + { "inv_cpld", 0, }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, cpld_ids); + +static struct i2c_driver cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "inv_cpld", + }, + .probe = cpld_probe, + .remove = cpld_remove, + .id_table = cpld_ids, +}; + +/*-----------------------------------------------------------------------*/ + +/* module glue */ + +static int __init inv_cpld_init(void) +{ + return i2c_add_driver(&cpld_driver); +} + +static void __exit inv_cpld_exit(void) +{ + i2c_del_driver(&cpld_driver); +} + +MODULE_AUTHOR("eddie.lan "); +MODULE_DESCRIPTION("inv cpld driver"); +MODULE_LICENSE("GPL"); + +module_init(inv_cpld_init); +module_exit(inv_cpld_exit); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c new file mode 100644 index 000000000000..3d13f3b04719 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_eeprom.c @@ -0,0 +1,181 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* Size of EEPROM in bytes */ +#define EEPROM_SIZE 256 + +#define SLICE_BITS (6) +#define SLICE_SIZE (1 << SLICE_BITS) +#define SLICE_NUM (EEPROM_SIZE/SLICE_SIZE) + +/* Each client has this additional data */ +struct eeprom_data { + struct mutex update_lock; + u8 valid; /* bitfield, bit!=0 if slice is valid */ + unsigned long last_updated[SLICE_NUM]; /* In jiffies, 8 slices */ + u8 data[EEPROM_SIZE]; /* Register values */ +}; + + +static void inv_eeprom_update_client(struct i2c_client *client, u8 slice) +{ + struct eeprom_data *data = i2c_get_clientdata(client); + int i, j; + int ret; + int addr; + + + mutex_lock(&data->update_lock); + + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { + dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); + + addr = slice << SLICE_BITS; + + ret = i2c_smbus_write_byte_data(client, ((u8)addr >> 8) & 0xFF, (u8)addr & 0xFF); + /* select the eeprom address */ + if (ret < 0) { + dev_err(&client->dev, "address set failed\n"); + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) { + goto exit; + } + + for (i = slice << SLICE_BITS; i < (slice + 1) << SLICE_BITS; i+= SLICE_SIZE) { + for (j = i; j < (i+SLICE_SIZE); j++) { + int res; + + res = i2c_smbus_read_byte(client); + if (res < 0) { + goto exit; + } + + data->data[j] = res & 0xFF; + } + } + + data->last_updated[slice] = jiffies; + data->valid |= (1 << slice); + } + +exit: + mutex_unlock(&data->update_lock); +} + +static ssize_t inv_eeprom_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct eeprom_data *data = i2c_get_clientdata(client); + u8 slice; + + + if (off > EEPROM_SIZE) { + return 0; + } + if (off + count > EEPROM_SIZE) { + count = EEPROM_SIZE - off; + } + if (count == 0) { + return 0; + } + + /* Only refresh slices which contain requested bytes */ + for (slice = off >> SLICE_BITS; slice <= (off + count - 1) >> SLICE_BITS; slice++) { + inv_eeprom_update_client(client, slice); + } + + memcpy(buf, &data->data[off], count); + + return count; +} + +static struct bin_attribute inv_eeprom_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + }, + .size = EEPROM_SIZE, + .read = inv_eeprom_read, +}; + +static int inv_eeprom_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct eeprom_data *data; + int err; + + if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data->data, 0xff, EEPROM_SIZE); + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* create the sysfs eeprom file */ + err = sysfs_create_bin_file(&client->dev.kobj, &inv_eeprom_attr); + if (err) { + goto exit_kfree; + } + + return 0; + +exit_kfree: + kfree(data); +exit: + return err; +} + +static int inv_eeprom_remove(struct i2c_client *client) +{ + sysfs_remove_bin_file(&client->dev.kobj, &inv_eeprom_attr); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id inv_eeprom_id[] = { + { "inv_eeprom", 0 }, + { } +}; + +static struct i2c_driver inv_eeprom_driver = { + .driver = { + .name = "inv_eeprom", + }, + .probe = inv_eeprom_probe, + .remove = inv_eeprom_remove, + .id_table = inv_eeprom_id, +}; + +module_i2c_driver(inv_eeprom_driver); + +MODULE_AUTHOR("Inventec"); +MODULE_DESCRIPTION("Inventec D7054 Mother Board EEPROM driver"); +MODULE_LICENSE("GPL"); + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c new file mode 100644 index 000000000000..ea26970075b0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_platform.c @@ -0,0 +1,219 @@ +#include +//#include +#include +#include +#include +#include +#include + +#include +//#include +//#include + +//#include +//#define IO_EXPAND_BASE 64 +//#define IO_EXPAND_NGPIO 16 + +struct inv_i2c_board_info { + int ch; + int size; + struct i2c_board_info *board_info; +}; + +#define bus_id(id) (id) +static struct pca954x_platform_mode mux_modes_0[] = { + {.adap_id = bus_id(2),}, {.adap_id = bus_id(3),}, + {.adap_id = bus_id(4),}, {.adap_id = bus_id(5),}, + {.adap_id = bus_id(6),}, {.adap_id = bus_id(7),}, + {.adap_id = bus_id(8),}, {.adap_id = bus_id(9),}, +}; +static struct pca954x_platform_mode mux_modes_0_0[] = { + {.adap_id = bus_id(10),}, {.adap_id = bus_id(11),}, + {.adap_id = bus_id(12),}, {.adap_id = bus_id(13),}, + {.adap_id = bus_id(14),}, {.adap_id = bus_id(15),}, + {.adap_id = bus_id(16),}, {.adap_id = bus_id(17),}, +}; + +static struct pca954x_platform_mode mux_modes_0_1[] = { + {.adap_id = bus_id(18),}, {.adap_id = bus_id(19),}, + {.adap_id = bus_id(20),}, {.adap_id = bus_id(21),}, + {.adap_id = bus_id(22),}, {.adap_id = bus_id(23),}, + {.adap_id = bus_id(24),}, {.adap_id = bus_id(25),}, +}; + +static struct pca954x_platform_mode mux_modes_0_2[] = { + {.adap_id = bus_id(26),}, {.adap_id = bus_id(27),}, + {.adap_id = bus_id(28),}, {.adap_id = bus_id(29),}, + {.adap_id = bus_id(30),}, {.adap_id = bus_id(31),}, + {.adap_id = bus_id(32),}, {.adap_id = bus_id(33),}, +}; + +static struct pca954x_platform_mode mux_modes_0_3[] = { + {.adap_id = bus_id(34),}, {.adap_id = bus_id(35),}, + {.adap_id = bus_id(36),}, {.adap_id = bus_id(37),}, + {.adap_id = bus_id(38),}, {.adap_id = bus_id(39),}, + {.adap_id = bus_id(40),}, {.adap_id = bus_id(41),}, +}; + +static struct pca954x_platform_mode mux_modes_0_4[] = { + {.adap_id = bus_id(42),}, {.adap_id = bus_id(43),}, + {.adap_id = bus_id(44),}, {.adap_id = bus_id(45),}, + {.adap_id = bus_id(46),}, {.adap_id = bus_id(47),}, + {.adap_id = bus_id(48),}, {.adap_id = bus_id(49),}, +}; + +static struct pca954x_platform_mode mux_modes_0_5[] = { + {.adap_id = bus_id(50),}, {.adap_id = bus_id(51),}, + {.adap_id = bus_id(52),}, {.adap_id = bus_id(53),}, + {.adap_id = bus_id(54),}, {.adap_id = bus_id(55),}, + {.adap_id = bus_id(56),}, {.adap_id = bus_id(57),}, +}; + +static struct pca954x_platform_mode mux_modes_0_6[] = { + {.adap_id = bus_id(58),}, {.adap_id = bus_id(59),}, + {.adap_id = bus_id(60),}, {.adap_id = bus_id(61),}, + {.adap_id = bus_id(62),}, {.adap_id = bus_id(63),}, + {.adap_id = bus_id(64),}, {.adap_id = bus_id(65),}, +}; + +//no i2c device driver attach to mux 7 + + +static struct pca954x_platform_data mux_data_0 = { + .modes = mux_modes_0, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_0 = { + .modes = mux_modes_0_0, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_1 = { + .modes = mux_modes_0_1, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_2 = { + .modes = mux_modes_0_2, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_3 = { + .modes = mux_modes_0_3, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_4 = { + .modes = mux_modes_0_4, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_5 = { + .modes = mux_modes_0_5, + .num_modes = 8, +}; +static struct pca954x_platform_data mux_data_0_6 = { + .modes = mux_modes_0_6, + .num_modes = 8, +}; + +static struct i2c_board_info i2c_device_info0[] __initdata = { + {"inv_psoc", 0, 0x66, 0, 0, 0},//psoc + {"inv_cpld", 0, 0x55, 0, 0, 0},//cpld + {"pca9548", 0, 0x71, &mux_data_0, 0, 0}, +}; + +static struct i2c_board_info i2c_device_info2[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_0, 0, 0}, +}; +static struct i2c_board_info i2c_device_info3[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_1, 0, 0}, +}; +static struct i2c_board_info i2c_device_info4[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_2, 0, 0}, +}; +static struct i2c_board_info i2c_device_info5[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_3, 0, 0}, +}; +static struct i2c_board_info i2c_device_info6[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_4, 0, 0}, +}; +static struct i2c_board_info i2c_device_info7[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_5, 0, 0}, +}; +static struct i2c_board_info i2c_device_info8[] __initdata = { + {"pca9548", 0, 0x72, &mux_data_0_6, 0, 0}, +}; + + +static struct inv_i2c_board_info i2cdev_list[] = { + {0, ARRAY_SIZE(i2c_device_info0), i2c_device_info0 }, //smbus 0 + + {bus_id(2), ARRAY_SIZE(i2c_device_info2), i2c_device_info2 }, //mux 0 + {bus_id(3), ARRAY_SIZE(i2c_device_info3), i2c_device_info3 }, //mux 1 + {bus_id(4), ARRAY_SIZE(i2c_device_info4), i2c_device_info4 }, //mux 2 + {bus_id(5), ARRAY_SIZE(i2c_device_info5), i2c_device_info5 }, //mux 3 + {bus_id(6), ARRAY_SIZE(i2c_device_info6), i2c_device_info6 }, //mux 4 + {bus_id(7), ARRAY_SIZE(i2c_device_info7), i2c_device_info7 }, //mux 5 + {bus_id(8), ARRAY_SIZE(i2c_device_info8), i2c_device_info8 }, //mux 6 + +}; + +///////////////////////////////////////////////////////////////////////////////////////// +#if 0 +static struct i2c_gpio_platform_data i2c_gpio_platdata0 = { + .scl_pin = 58, + .sda_pin = 75, + + .udelay = 5, //5:100kHz + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, + .scl_is_output_only = 0 +}; + +static struct platform_device device_i2c_gpio0 = { + .name = "i2c-gpio", + .id = 0, // adapter number + .dev.platform_data = &i2c_gpio_platdata0, +}; +#endif +static int __init inv_platform_init(void) +{ + struct i2c_adapter *adap = NULL; + struct i2c_client *e = NULL; + int ret = 0; + int i,j; + + printk("%s \n", __func__); + +#if 0 + //use i2c-gpio + //register i2c gpio + //config gpio58,75 to gpio function 58=32+3*8+2 75=32*2+8*1+3 + outl( inl(0x533) | (1<<2), 0x533); + outl( inl(0x541) | (1<<3), 0x541); + + ret = platform_device_register(&device_i2c_gpio0); + if (ret) { + printk(KERN_ERR "i2c-gpio: device_i2c_gpio0 register fail %d\n", ret); + } + #endif + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "I2CHostCommunication.h" + +#define IMPLEMENT_IPMI_CODE 1 +int USE_IPMI=0; +//================================= +#if IMPLEMENT_IPMI_CODE +#include +#include +#include +#include + +#define IPMI_MAX_INTF (4) +#define NETFN_OEM 0x30 +#define CMD_GETDATA 0x31 +#define CMD_SETDATA 0x32 + +struct mutex ipmi_mutex; + +static void msg_handler(struct ipmi_recv_msg *msg,void* handler_data); +static ipmi_user_t ipmi_mh_user = NULL; +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = msg_handler,}; + +static atomic_t dummy_count = ATOMIC_INIT(0); +static void dummy_smi_free(struct ipmi_smi_msg *msg) +{ + atomic_dec(&dummy_count); +} +static void dummy_recv_free(struct ipmi_recv_msg *msg) +{ + atomic_dec(&dummy_count); +} +static struct ipmi_smi_msg halt_smi_msg = { + .done = dummy_smi_free +}; +static struct ipmi_recv_msg halt_recv_msg = { + .done = dummy_recv_free +}; +#endif +//================================= + +#define USE_SMBUS 1 + +#define FAN_NUM 4 +#define PSU_NUM 2 + +struct __attribute__ ((__packed__)) psoc_psu_layout { + u16 psu1_iin; + u16 psu2_iin; + u16 psu1_iout; + u16 psu2_iout; + + u16 psu1_pin; + u16 psu2_pin; + u16 psu1_pout; + u16 psu2_pout; + + u16 psu1_vin; + u16 psu2_vin; + u16 psu1_vout; + u16 psu2_vout; +}; + +struct __attribute__ ((__packed__)) psoc_layout { + u8 ctl; //offset: 0 + u16 switch_temp; //offset: 1 + u8 reserve0; //offset: 3 + + u8 fw_upgrade; //offset: 4 + + //i2c bridge + u8 i2c_st; //offset: 5 + u8 i2c_ctl; //offset: 6 + u8 i2c_addr; //offset: 7 + u8 i2c_data[0x20]; //offset: 8 + + //gpo + u8 led_ctl; //offset: 28 + + u8 gpio; //offset: 29 + + //pwm duty + u8 pwm[FAN_NUM]; //offset: 2a + u8 pwm_psu[PSU_NUM]; //offset: 2e + + //fan rpm + u16 fan[FAN_NUM*2]; //offset: 30 + + u8 reserve1[4]; //offset: 40 + + //gpi + u8 gpi_fan; //offset: 44 + + //psu state + u8 psu_state; //offset: 45 + + //temperature + u16 temp[5]; //offset: 46 + u16 temp_psu[PSU_NUM]; //offset: 50 + + //version + u8 version[2]; //offset: 54 + + u8 reserve2[4]; //offset: 56 + struct psoc_psu_layout psu_info; //offset: 5a +}; + +/* definition */ +/* definition */ +#define PSOC_OFF(m) offsetof(struct psoc_layout, m) +#define PSOC_PSU_OFF(m) offsetof(struct psoc_psu_layout, m) + +#define SWITCH_TMP_OFFSET PSOC_OFF(switch_temp) +#define PWM_OFFSET PSOC_OFF(pwm) +#define THERMAL_OFFSET PSOC_OFF(temp) +#define RPM_OFFSET PSOC_OFF(fan) +#define DIAG_FLAG_OFFSET PSOC_OFF(ctl) +#define FAN_LED_OFFSET PSOC_OFF(led_ctl) +#define FAN_GPI_OFFSET PSOC_OFF(gpi_fan) +#define PSOC_PSU_OFFSET PSOC_OFF(psu_state) +#define VERSION_OFFSET PSOC_OFF(version) +#define PSU_INFO_OFFSET PSOC_OFF(psu_info) + +/* Each client has this additional data */ +struct psoc_data { + struct device *hwmon_dev; + struct mutex update_lock; + u32 diag; +}; + +/*-----------------------------------------------------------------------*/ +#if IMPLEMENT_IPMI_CODE +static void msg_handler(struct ipmi_recv_msg *recv_msg,void* handler_data) +{ + struct completion *comp = recv_msg->user_msg_data; + if (comp) + complete(comp); + else + ipmi_free_recv_msg(recv_msg); + return; +} + +int ipmi_command(char NetFn, char cmd,char *data,int data_length, char* result, int* result_length) +{ + int rv=0,i; + struct ipmi_system_interface_addr addr; + uint8_t _data[data_length]; + struct kernel_ipmi_msg msg; + struct completion comp; + + if(!mutex_trylock(&ipmi_mutex)) return 0; + +// for (i=0,rv=1; iaddr; + msg[0].buf = msgbuf; + msg[0].len = 1; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + status = i2c_transfer(client->adapter, msg, 2); + + if(status == 2) + status = count; + + return status; +#endif +} + +static ssize_t psoc_i2c_write(struct i2c_client *client, char *buf, unsigned offset, size_t count) +{ +#if USE_SMBUS +if(USE_IPMI==0) +{ + int i; + + for(i=0; iaddr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = writebuf; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + + return status; +#endif +} + +#if 0 +static u32 psoc_read32(struct i2c_client *client, u8 offset) +{ + u32 value = 0; + u8 buf[4]; + + if( psoc_i2c_read(client, buf, offset, 4) == 4) + value = (buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]); + + return value; +} +#endif + +static u16 psoc_read16(struct i2c_client *client, u8 offset) +{ + u16 value = 0; + u8 buf[2]; + + if(psoc_i2c_read(client, buf, offset, 2) == 2) + value = (buf[0]<<8 | buf[1]<<0); + + return value; +} + +static u8 psoc_read8(struct i2c_client *client, u8 offset) +{ + u8 value = 0; + u8 buf = 0; + + if(psoc_i2c_read(client, &buf, offset, 1) == 1) + value = buf; + + return value; +} + +//PSOC i2c bridge regsters +#define PSOC_I2C_STATUS 0x05 +#define PSOC_I2C_CNTRL 0x06 +#define PSOC_I2C_ADDR 0x07 +#define PSOC_I2C_DATA 0x08 + +//status bit definition +#define PSOC_I2C_START (1 << 0) +#define PSOC_PMB_SEL (1 << 7) + +//addr bits definition +#define PSOC_I2C_READ (1 << 0) + +//PMBUS registers definition +#define PMBUS_READ_VIN (0x88) +#define PMBUS_READ_IIN (0x89) +#define PMBUS_READ_VOUT (0x8B) +#define PMBUS_READ_IOUT (0x8C) +#define PMBUS_READ_POUT (0x96) +#define PMBUS_READ_PIN (0x97) + +/* +CPLD report the PSU0 status +000 = PSU normal operation +100 = PSU fault +010 = PSU unpowered +111 = PSU not installed + +7 6 | 5 4 3 | 2 1 0 +---------------------- + | psu1 | psu0 +*/ +static char* psu_str[] = { + "normal", //000 + "NA", //001 + "unpowered", //010 + "NA", //011 + "fault", //100 + "NA", //101 + "NA", //110 + "not installed", //111 +}; + +static ssize_t show_psu_st(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 byte; + int shift = (attr->index == 0)?3:0; + + mutex_lock(&data->update_lock); + status = psoc_i2c_read(client, &byte, PSOC_PSU_OFFSET, 1); + mutex_unlock(&data->update_lock); + + byte = (byte >> shift) & 0x7; + + status = sprintf (buf, "%d : %s\n", byte, psu_str[byte]); + + return strlen(buf); +} + +/*-----------------------------------------------------------------------*/ + +/* sysfs attributes for hwmon */ +#define PSU1 0x5800 +#define PSU2 0x5900 +#define BMC_I2cBus 3 //BMC's I2C-1 +#define PMBus_Vender 0x99 +#define PMBus_Serial 0x9E +#define PMBus_Temp2 0x8E +#define PMBus_Version 0x9B +#define MaxLeng_Result 0x20 +#define MaxLog +static long pmbus_reg2data_linear(int data, int linear16); + + +static ssize_t show_ipmi_i2c(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + uint8_t data[4],result[MaxLeng_Result]; + int result_len; + + data[0] = BMC_I2cBus; + data[1] = (attr->index & 0xFF00 ) >>7; + data[3] = attr->index & 0xff; + if(data[3]==PMBus_Temp2) + data[2]=2; + else + data[2]=MaxLeng_Result; + + if(ipmi_command(0x06, 0x52,data,4, result, &result_len)==0) + { + if(data[3]==PMBus_Temp2) + { + return sprintf(buf, "%ld \n", pmbus_reg2data_linear(result[0] | (result[1]<<8), 0 )); + } + result[result[0]+1]='\0'; + + return sprintf(buf, "%s\n",&result[1] ); + } + else + return 0; +} + +static ssize_t show_ipmi_sollog(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + uint8_t data[5],result[256]; + int result_len; + uint32_t i; + + for(i=0;i<0xffffff;i+=255) + { + data[0] = attr->index; + data[1] = (i & 0x0000ff); + data[2] = (i & 0x00ff00)>>8; + data[3] = (i & 0xff0000)>>16; + data[4] = 0; + + result_len=0; + + if(ipmi_command(0x32, 0xFE, data, 5, result, &result_len)==0) + { + if(result_len==0) break; + result[result_len+1]='\0'; + printk("%s",result); + } + else break; + + if(result_len==0) break; + } + + return 0; +} + +static ssize_t show_thermal(struct device *dev, struct device_attribute *da, + char *buf) +{ + u16 status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 offset = attr->index * 2 + THERMAL_OFFSET; + + mutex_lock(&data->update_lock); + + status = psoc_read16(client, offset); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", + (s8)(status>>8) * 1000 ); +} + + + +static ssize_t show_pwm(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 offset = attr->index + PWM_OFFSET; + + mutex_lock(&data->update_lock); + + status = psoc_read8(client, offset); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", + status); +} + +static ssize_t set_pwm(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 offset = attr->index + PWM_OFFSET; + + u8 pwm = simple_strtol(buf, NULL, 10); + if(pwm > 255) pwm = 255; + + if(data->diag) { + mutex_lock(&data->update_lock); + psoc_i2c_write(client, &pwm, offset, 1); + mutex_unlock(&data->update_lock); + } + + return count; +} + + +static ssize_t show_rpm(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 offset = attr->index*2 + RPM_OFFSET; + + mutex_lock(&data->update_lock); + + status = psoc_read16(client, offset); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", + status); +} + +static ssize_t show_switch_tmp(struct device *dev, struct device_attribute *da, + char *buf) +{ + u16 status; + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u16 temp = 0; + + mutex_lock(&data->update_lock); + status = psoc_i2c_read(client, (u8*)&temp, SWITCH_TMP_OFFSET, 2); + mutex_unlock(&data->update_lock); + + status = sprintf (buf, "%d\n", (s8)(temp>>8) * 1000 ); + + return strlen(buf); +} + +static ssize_t set_switch_tmp(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + //struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + + long temp = simple_strtol(buf, NULL, 10); + u16 temp2 = ( (temp/1000) <<8 ) & 0xFF00 ; + + //printk("set_switch_tmp temp=%d, temp2=0x%x (%x,%x)\n", temp, temp2, ( ( (temp/1000) <<8 ) & 0xFF00 ), (( (temp%1000) / 10 ) & 0xFF)); + + mutex_lock(&data->update_lock); + psoc_i2c_write(client, (u8*)&temp2, SWITCH_TMP_OFFSET, 2); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_diag(struct device *dev, struct device_attribute *da, + char *buf) +{ + u16 status; + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 diag_flag = 0; + + mutex_lock(&data->update_lock); + status = psoc_i2c_read(client, (u8*)&diag_flag, DIAG_FLAG_OFFSET, 1); + mutex_unlock(&data->update_lock); + + data->diag = (diag_flag & 0x80)?1:0; + status = sprintf (buf, "%d\n", data->diag); + + return strlen(buf); +} + +static ssize_t set_diag(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + //struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 value = 0; + u8 diag = simple_strtol(buf, NULL, 10); + + diag = diag?1:0; + data->diag = diag; + + mutex_lock(&data->update_lock); + psoc_i2c_read(client, (u8*)&value, DIAG_FLAG_OFFSET, 1); + if(diag) value |= (1<<7); + else value &= ~(1<<7); + psoc_i2c_write(client, (u8*)&value, DIAG_FLAG_OFFSET, 1); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + u16 status; + //struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + status = psoc_read16(client, VERSION_OFFSET); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "ver: %x.%x\n", (status & 0xFF00)>>8, (status & 0xFF) ); +} + + +static ssize_t show_fan_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 bit = attr->index; + + mutex_lock(&data->update_lock); + + status = psoc_read8(client, FAN_LED_OFFSET); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", + (status & (1<index; + u8 led_state = 0; + + u8 v = simple_strtol(buf, NULL, 10); + + if(data->diag) { + mutex_lock(&data->update_lock); + led_state = psoc_read8(client, FAN_LED_OFFSET); + if(v) led_state |= (1<update_lock); + } + + return count; +} + +static ssize_t show_value8(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 offset = attr->index; + + mutex_lock(&data->update_lock); + + status = psoc_read8(client, offset); + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "0x%02X\n", status ); +} + +static long pmbus_reg2data_linear(int data, int linear16) +{ + s16 exponent; + s32 mantissa; + long val; + + if (linear16) { /* LINEAR16 */ + exponent = -9; + mantissa = (u16) data; + } else { /* LINEAR11 */ + exponent = ((s16)data) >> 11; + exponent = ((s16)( data & 0xF800) ) >> 11; + mantissa = ((s32)((data & 0x7ff) << 5)) >> 5; + } + + //printk("data=%d, m=%d, e=%d\n", data, exponent, mantissa); + val = mantissa; + + /* scale result to micro-units for power sensors */ + val = val * 1000L; + + if (exponent >= 0) + val <<= exponent; + else + val >>= -exponent; + + return val; +} + +static ssize_t show_psu_psoc(struct device *dev, struct device_attribute *da, + char *buf) +{ + u16 status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct psoc_data *data = i2c_get_clientdata(client); + u8 offset = attr->index + PSU_INFO_OFFSET; + + mutex_lock(&data->update_lock); + status = psoc_read16(client, offset); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%ld \n", pmbus_reg2data_linear(status, strstr(attr->dev_attr.attr.name, "vout")? 1:0 )); +} + + + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_thermal, 0, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_thermal, 0, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_thermal, 0, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_thermal, 0, 3); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_thermal, 0, 4); +static SENSOR_DEVICE_ATTR(thermal_psu1, S_IRUGO, show_thermal, 0, 5); +static SENSOR_DEVICE_ATTR(thermal_psu2, S_IRUGO, show_thermal, 0, 6); + +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 3); +static SENSOR_DEVICE_ATTR(pwm_psu1, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 4); +static SENSOR_DEVICE_ATTR(pwm_psu2, S_IWUSR|S_IRUGO, show_pwm, set_pwm, 5); + +static SENSOR_DEVICE_ATTR(psu0, S_IRUGO, show_psu_st, 0, 0); +static SENSOR_DEVICE_ATTR(psu1, S_IRUGO, show_psu_st, 0, 1); + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, 0, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_rpm, 0, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_rpm, 0, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_rpm, 0, 3); +static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_rpm, 0, 4); +static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_rpm, 0, 5); +static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_rpm, 0, 6); +static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_rpm, 0, 7); +static SENSOR_DEVICE_ATTR(rpm_psu1, S_IRUGO, show_rpm, 0, 8); +static SENSOR_DEVICE_ATTR(rpm_psu2, S_IRUGO, show_rpm, 0, 9); + +static SENSOR_DEVICE_ATTR(switch_tmp, S_IWUSR|S_IRUGO, show_switch_tmp, set_switch_tmp, 0); + +static SENSOR_DEVICE_ATTR(diag, S_IWUSR|S_IRUGO, show_diag, set_diag, 0); +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, 0, 0); + +static SENSOR_DEVICE_ATTR(fan_led_grn1, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 0); +static SENSOR_DEVICE_ATTR(fan_led_grn2, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 1); +static SENSOR_DEVICE_ATTR(fan_led_grn3, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 2); +static SENSOR_DEVICE_ATTR(fan_led_grn4, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 3); +static SENSOR_DEVICE_ATTR(fan_led_red1, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 4); +static SENSOR_DEVICE_ATTR(fan_led_red2, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 5); +static SENSOR_DEVICE_ATTR(fan_led_red3, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 6); +static SENSOR_DEVICE_ATTR(fan_led_red4, S_IWUSR|S_IRUGO, show_fan_led, set_fan_led, 7); + +static SENSOR_DEVICE_ATTR(fan_gpi, S_IRUGO, show_value8, 0, FAN_GPI_OFFSET); +static SENSOR_DEVICE_ATTR(psoc_psu1_vin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_vin)); +static SENSOR_DEVICE_ATTR(psoc_psu1_vout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_vout)); +static SENSOR_DEVICE_ATTR(psoc_psu1_iin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_iin)); +static SENSOR_DEVICE_ATTR(psoc_psu1_iout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_iout)); +static SENSOR_DEVICE_ATTR(psoc_psu1_pin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_pin)); +static SENSOR_DEVICE_ATTR(psoc_psu1_pout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu1_pout)); + + +static SENSOR_DEVICE_ATTR(psoc_psu2_vin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_vin)); +static SENSOR_DEVICE_ATTR(psoc_psu2_vout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_vout)); +static SENSOR_DEVICE_ATTR(psoc_psu2_iin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_iin)); +static SENSOR_DEVICE_ATTR(psoc_psu2_iout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_iout)); +static SENSOR_DEVICE_ATTR(psoc_psu2_pin, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_pin)); +static SENSOR_DEVICE_ATTR(psoc_psu2_pout, S_IRUGO, show_psu_psoc, 0, PSOC_PSU_OFF(psu2_pout)); + +//IPMI +static SENSOR_DEVICE_ATTR(thermal2_psu1, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Temp2); +static SENSOR_DEVICE_ATTR(psoc_psu1_vender, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Vender); +static SENSOR_DEVICE_ATTR(psoc_psu1_serial, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Serial); +static SENSOR_DEVICE_ATTR(psoc_psu1_version, S_IRUGO, show_ipmi_i2c, 0, PSU1 | PMBus_Version); + +static SENSOR_DEVICE_ATTR(thermal2_psu2, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Temp2); +static SENSOR_DEVICE_ATTR(psoc_psu2_vender, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Vender); +static SENSOR_DEVICE_ATTR(psoc_psu2_serial, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Serial); +static SENSOR_DEVICE_ATTR(psoc_psu2_version, S_IRUGO, show_ipmi_i2c, 0, PSU2 | PMBus_Version); + +static SENSOR_DEVICE_ATTR(sollog1, S_IRUGO, show_ipmi_sollog, 0, 1); +static SENSOR_DEVICE_ATTR(sollog2, S_IRUGO, show_ipmi_sollog, 0, 2); + +static struct attribute *psoc_attributes[] = { + //thermal + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + + &sensor_dev_attr_thermal_psu1.dev_attr.attr, + &sensor_dev_attr_thermal_psu2.dev_attr.attr, + + + //pwm + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm4.dev_attr.attr, + &sensor_dev_attr_pwm_psu1.dev_attr.attr, + &sensor_dev_attr_pwm_psu2.dev_attr.attr, + + //rpm + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_fan8_input.dev_attr.attr, + + &sensor_dev_attr_rpm_psu1.dev_attr.attr, + &sensor_dev_attr_rpm_psu2.dev_attr.attr, + + //switch temperature + &sensor_dev_attr_switch_tmp.dev_attr.attr, + + //diag flag + &sensor_dev_attr_diag.dev_attr.attr, + + //version + &sensor_dev_attr_version.dev_attr.attr, + + //fan led + &sensor_dev_attr_fan_led_grn1.dev_attr.attr, + &sensor_dev_attr_fan_led_grn2.dev_attr.attr, + &sensor_dev_attr_fan_led_grn3.dev_attr.attr, + &sensor_dev_attr_fan_led_grn4.dev_attr.attr, + &sensor_dev_attr_fan_led_red1.dev_attr.attr, + &sensor_dev_attr_fan_led_red2.dev_attr.attr, + &sensor_dev_attr_fan_led_red3.dev_attr.attr, + &sensor_dev_attr_fan_led_red4.dev_attr.attr, + + //fan GPI + &sensor_dev_attr_fan_gpi.dev_attr.attr, + &sensor_dev_attr_psu0.dev_attr.attr, + &sensor_dev_attr_psu1.dev_attr.attr, + + + //psu_psoc, new added on psoc 1.9 + &sensor_dev_attr_psoc_psu1_vin.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_vout.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_iin.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_iout.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_pin.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_pout.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_vin.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_vout.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_iin.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_iout.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_pin.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_pout.dev_attr.attr, + + //ipmi_command + &sensor_dev_attr_thermal2_psu1.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_vender.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_serial.dev_attr.attr, + &sensor_dev_attr_psoc_psu1_version.dev_attr.attr, + + &sensor_dev_attr_thermal2_psu2.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_vender.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_serial.dev_attr.attr, + &sensor_dev_attr_psoc_psu2_version.dev_attr.attr, + + &sensor_dev_attr_sollog1.dev_attr.attr, + &sensor_dev_attr_sollog2.dev_attr.attr, + + NULL +}; + +static const struct attribute_group psoc_group = { + .attrs = psoc_attributes, +}; + +/*-----------------------------------------------------------------------*/ + +/* device probe and removal */ + +static int +psoc_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct psoc_data *data; + int status,i,rv; + + printk("+%s\n", __func__); + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + data = kzalloc(sizeof(struct psoc_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->diag = 0; + +#if IMPLEMENT_IPMI_CODE + for (i=0,rv=1; idev.kobj, &psoc_group); + if (status) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: sensor '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &psoc_group); +exit_free: + i2c_set_clientdata(client, NULL); + kfree(data); + return status; +} + +static int psoc_remove(struct i2c_client *client) +{ + struct psoc_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &psoc_group); + i2c_set_clientdata(client, NULL); + kfree(data); + return 0; +} + +static const struct i2c_device_id psoc_ids[] = { + { "inv_psoc", 0, }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, psoc_ids); + +static struct i2c_driver psoc_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "inv_psoc", + }, + .probe = psoc_probe, + .remove = psoc_remove, + .id_table = psoc_ids, +}; + +/*-----------------------------------------------------------------------*/ + +/* module glue */ + +static int __init inv_psoc_init(void) +{ + return i2c_add_driver(&psoc_driver); +} + +static void __exit inv_psoc_exit(void) +{ + i2c_del_driver(&psoc_driver); +} + +MODULE_AUTHOR("eddie.lan "); +MODULE_DESCRIPTION("inv psoc driver"); +MODULE_LICENSE("GPL"); + +module_init(inv_psoc_init); +module_exit(inv_psoc_exit); diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c new file mode 100644 index 000000000000..08bd490e63b6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.c @@ -0,0 +1,730 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_swps.h" + +static int port_major; +static int ioexp_total; +static int port_total; +static struct class *swp_class_p = NULL; +static struct inv_platform_s *platform_p = NULL; +static struct inv_ioexp_layout_s *ioexp_layout = NULL; +static struct inv_port_layout_s *port_layout = NULL; + +static int +__swp_match(struct device *dev, +#ifdef SWPS_KERN_VER_AF_3_10 + + const void *data){ +#else + void *data){ +#endif + + char *name = (char *)data; + if (strcmp(dev_name(dev), name) == 0) + return 1; + return 0; +} + + +struct device * +get_swpdev_by_name(char *name){ + struct device *dev = class_find_device(swp_class_p, + NULL, + name, + (const void *)__swp_match); + return dev; +} + + +static int +sscanf_2_int(const char *buf) { + + int result = -EBFONT; + char *hex_tag = "0x"; + + if (strcspn(buf, hex_tag) == 0) { + if (sscanf(buf,"%x",&result)) { + return result; + } + } else { + if (sscanf(buf,"%d",&result)) { + return result; + } + if(sscanf(buf,"-%d",&result)) { + return -result; + } + if (sscanf(buf,"%x",&result)) { + return result; + } + } + return -EBFONT; +} + + +static int +sscanf_2_binary(const char *buf) { + + int result = sscanf_2_int(buf); + + if (result < 0){ + return -EBFONT; + } + switch (result) { + case 0: + case 1: + return result; + default: + break; + } + return -EBFONT; +} + +/* ========== Show functions: For I/O Expander attribute ========== + */ +static ssize_t +_show_ioexp_binary_attr(struct transvr_obj_s *tobj_p, + int (*get_func)(struct ioexp_obj_s *ioexp_p, int voffset), + char *buf_p) { + size_t len; + struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p; + + if (!ioexp_p) { + SWPS_ERR(" %s: data corruption! :%s\n", __func__, tobj_p->swp_name); + return -ENODATA; + } + mutex_lock(&ioexp_p->lock); + len = snprintf(buf_p, 8, "%d\n", get_func(ioexp_p, tobj_p->ioexp_virt_offset)); + mutex_unlock(&ioexp_p->lock); + return len; +} + + +static ssize_t +show_attr_present(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_present, + buf_p); +} + +static ssize_t +show_attr_tx_fault(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_tx_fault, + buf_p); +} + +static ssize_t +show_attr_rxlos(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_rxlos, + buf_p); +} + +static ssize_t +show_attr_tx_disable(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_tx_disable, + buf_p); +} + +static ssize_t +show_attr_reset(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_reset, + buf_p); +} + +static ssize_t +show_attr_lpmod(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_lpmod, + buf_p); +} + + +static ssize_t +show_attr_modsel(struct device *dev_p, + struct device_attribute *attr_p, + char *buf_p){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p){ + return -ENODEV; + } + return _show_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->get_modsel, + buf_p); +} + +/* ========== Store functions: For I/O Expander (R/W) attribute ========== + */ +static ssize_t +_store_ioexp_binary_attr(struct transvr_obj_s *tobj_p, + int (*set_func)(struct ioexp_obj_s *ioexp_p, + int virt_offset, int input_val), + const char *buf_p, + size_t count) { + + int input, err; + struct ioexp_obj_s *ioexp_p = tobj_p->ioexp_obj_p; + + if (!ioexp_p) { + SWPS_ERR("%s: data corruption! :%s\n", + __func__, tobj_p->swp_name); + return -ENODATA; + } + input = sscanf_2_binary(buf_p); + if (input < 0) { + return -EBFONT; + } + mutex_lock(&ioexp_p->lock); + err = set_func(ioexp_p, tobj_p->ioexp_virt_offset, input); + mutex_unlock(&ioexp_p->lock); + if (err < 0){ + return err; + } + return count; +} + +static ssize_t +store_attr_tx_disable(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_tx_disable, + buf_p, + count); +} + +static ssize_t +store_attr_reset(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_reset, + buf_p, + count); +} + + +static ssize_t +store_attr_lpmod(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_lpmod, + buf_p, + count); +} + + +static ssize_t +store_attr_modsel(struct device *dev_p, + struct device_attribute *attr_p, + const char *buf_p, + size_t count){ + + struct transvr_obj_s *tobj_p = dev_get_drvdata(dev_p); + if (!tobj_p) { + return -ENODEV; + } + return _store_ioexp_binary_attr(tobj_p, + tobj_p->ioexp_obj_p->set_modsel, + buf_p, + count); +} + +/* ========== IO Expander attribute: from expander ========== + */ +static DEVICE_ATTR(present, S_IRUGO, show_attr_present, NULL); +static DEVICE_ATTR(tx_fault, S_IRUGO, show_attr_tx_fault, NULL); +static DEVICE_ATTR(rxlos, S_IRUGO, show_attr_rxlos, NULL); +static DEVICE_ATTR(tx_disable, S_IRUGO|S_IWUSR, show_attr_tx_disable, store_attr_tx_disable); +static DEVICE_ATTR(reset, S_IRUGO|S_IWUSR, show_attr_reset, store_attr_reset); +static DEVICE_ATTR(lpmod, S_IRUGO|S_IWUSR, show_attr_lpmod, store_attr_lpmod); +static DEVICE_ATTR(modsel, S_IRUGO|S_IWUSR, show_attr_modsel, store_attr_modsel); + +/* ========== Functions for module handling ========== + */ +static void +clean_port_obj(void){ + + dev_t dev_num; + char dev_name[32]; + struct device *device_p; + struct transvr_obj_s *transvr_obj_p; + int minor_curr, port_id; + + for (minor_curr=0; minor_curri2c_client_p); + kfree(transvr_obj_p); + } + dev_num = MKDEV(port_major, minor_curr); + device_unregister(device_p); + device_destroy(swp_class_p, dev_num); + } + SWPS_DEBUG("%s: done.\n", __func__); +} + + +static int +get_platform_type(void){ + + char log_msg[64] = "ERROR"; + + platform_p = kzalloc(sizeof(struct inv_platform_s), GFP_KERNEL); + if (!platform_p){ + snprintf(log_msg, sizeof(log_msg), "kzalloc fail"); + goto err_get_platform_type_1; + } + platform_p->id = PLATFORM_SETTINGS; + memset(platform_p->name, 0, sizeof(platform_p->name)); + snprintf(platform_p->name, (sizeof(platform_p->name) - 1), + "%s", platform_map.name); + snprintf(log_msg, sizeof(log_msg), + "User setup platform: %d (%s)", + platform_p->id, platform_p->name); + SWPS_DEBUG("%s: %s, :%d\n", __func__, log_msg, PLATFORM_SETTINGS); + return 0; + +err_get_platform_type_1: + SWPS_ERR("%s: %s :%d\n", __func__, log_msg, PLATFORM_SETTINGS); + return -1; +} + + +static int +get_layout_info(void){ + ioexp_layout = cypress_ga2_ioexp_layout; + port_layout = cypress_ga2_port_layout; + ioexp_total = ARRAY_SIZE(cypress_ga2_ioexp_layout); + port_total = ARRAY_SIZE(cypress_ga2_port_layout); + + SWPS_INFO("Start to initial platform: %d (%s)\n", + platform_p->id, platform_p->name); + return 0; +} + +/* ========== Functions for register something ========== + */ + +static int +register_ioexp_attr_sfp_1(struct device *device_p){ + /* Support machine type: + * - SFP : Magnolia + */ + char *err_attr = NULL; + + if (device_create_file(device_p, &dev_attr_present) < 0) { + err_attr = "dev_attr_present"; + goto err_ioexp_sfp1_attr; + } + if (device_create_file(device_p, &dev_attr_tx_fault) < 0) { + err_attr = "dev_attr_tx_fault"; + goto err_ioexp_sfp1_attr; + } + if (device_create_file(device_p, &dev_attr_rxlos) < 0) { + err_attr = "dev_attr_rxlos"; + goto err_ioexp_sfp1_attr; + } + if (device_create_file(device_p, &dev_attr_tx_disable) < 0) { + err_attr = "dev_attr_tx_disable"; + goto err_ioexp_sfp1_attr; + } + return 0; + +err_ioexp_sfp1_attr: + SWPS_ERR("Add device attribute:%s failure! \n",err_attr); + return -1; +} + +static int +register_ioexp_attr_sfp_2(struct device *device_p){ + /* Support machine type: + * - SFP28 : Cypress + */ + char *err_attr = NULL; + + if (register_ioexp_attr_sfp_1(device_p) < 0){ + goto err_ioexp_sfp2_attr; + } + return 0; + +err_ioexp_sfp2_attr: + SWPS_ERR("Add device attribute:%s failure! \n",err_attr); + return -1; +} + +static int +register_ioexp_attr_qsfp_1(struct device *device_p){ + /* Support machine type: + * - QSFP : Magnolia, Redwood, Hudson32i + * - QSFP+ : Magnolia, Redwood, Hudson32i + * - QSFP28: Redwood + */ + char *err_attr = NULL; + + if (device_create_file(device_p, &dev_attr_present) < 0) { + err_attr = "dev_attr_present"; + goto err_ioexp_qsfp1_attr; + } + if (device_create_file(device_p, &dev_attr_reset) < 0) { + err_attr = "dev_attr_reset"; + goto err_ioexp_qsfp1_attr; + } + if (device_create_file(device_p, &dev_attr_lpmod) < 0) { + err_attr = "dev_attr_lpmod"; + goto err_ioexp_qsfp1_attr; + } + if (device_create_file(device_p, &dev_attr_modsel) < 0) { + err_attr = "dev_attr_modsel"; + goto err_ioexp_qsfp1_attr; + } + return 0; + +err_ioexp_qsfp1_attr: + SWPS_ERR("Add device attribute:%s failure! \n",err_attr); + return -1; +} + +static int +register_ioexp_attr(struct device *device_p, + struct transvr_obj_s *transvr_obj){ + + char *err_msg = "ERR"; + + switch (transvr_obj->ioexp_obj_p->ioexp_type){ + case IOEXP_TYPE_CYPRESS_NABC: + if (register_ioexp_attr_sfp_2(device_p) < 0){ + err_msg = "register_ioexp_attr_sfp_2 fail"; + goto err_reg_ioexp_attr; + } + break; + case IOEXP_TYPE_CYPRESS_7ABC: + if (register_ioexp_attr_qsfp_1(device_p) < 0){ + err_msg = "register_ioexp_attr_qsfp_1 fail"; + goto err_reg_ioexp_attr; + } + break; + + default: + err_msg = "Unknow type"; + goto err_reg_ioexp_attr; + } + return 0; + +err_reg_ioexp_attr: + SWPS_ERR("%s: %s :%d \n", + __func__, err_msg, transvr_obj->ioexp_obj_p->ioexp_type); + return -1; +} + + +static int +register_port_device(char *dev_name, + dev_t dev_num, + struct transvr_obj_s *transvr_obj){ + + struct device *device_p = NULL; + device_p = device_create(swp_class_p, /* struct class *cls */ + NULL, /* struct device *parent */ + dev_num, /* dev_t devt */ + transvr_obj, /* void *private_data */ + dev_name); /* const char *fmt */ + if (IS_ERR(device_p)){ + goto err_regswp_create_dev; + } + if (register_ioexp_attr(device_p, transvr_obj) < 0){ + goto err_regswp_reg_attr; + } + return 0; + +err_regswp_reg_attr: + device_unregister(device_p); + device_destroy(swp_class_p, dev_num); +err_regswp_create_dev: + SWPS_ERR("%s fail! :%s\n", __func__, dev_name); + return -1; +} + + +static int +register_swp_module(void){ + + dev_t port_devt = 0; + int dev_total = port_total + 1; /* char_dev for module control */ + + if (alloc_chrdev_region(&port_devt, 0, dev_total, SWP_CLS_NAME) < 0){ + SWPS_WARN("Allocate PORT MAJOR failure! \n"); + goto err_register_swp_module_3; + } + port_major = MAJOR(port_devt); + + /* Create class object */ + swp_class_p = class_create(THIS_MODULE, SWP_CLS_NAME); + if (IS_ERR(swp_class_p)) { + SWPS_ERR("Create class failure! \n"); + goto err_register_swp_module_3; + } + return 0; + +err_register_swp_module_3: + unregister_chrdev_region(MKDEV(port_major, 0), port_total); + return -1; +} + + +/* ========== Module initial relate ========== + */ +static int +create_ioexp_objs(void) { + + int i, run_mod; + + /* Clean IOEXP object */ + clean_ioexp_objs(); + /* Get running mode */ + run_mod = IOEXP_MODE_DIRECT; + /* Create IOEXP object */ + for(i=0; i devlen_max) { + snprintf(err_msg, sizeof(err_msg), + "SWP_DEV_PORT too long!"); + goto err_initport_create_tranobj; + } + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, devlen_max, "%s%d", SWP_DEV_PORT, port_id); + /* Create transceiver object */ + ioexp_obj_p = get_ioexp_obj(ioexp_id); + if (!ioexp_obj_p){ + snprintf(err_msg, sizeof(err_msg), + "IOEXP object:%d not exist", ioexp_id); + goto err_initport_create_tranobj; + } + transvr_obj_p = create_transvr_obj(dev_name, chan_id, ioexp_obj_p, + ioexp_virt_offset, transvr_type, + chipset_type, run_mod); + if (!transvr_obj_p){ + snprintf(err_msg, sizeof(err_msg), + "Create transceiver object fail :%s", dev_name); + goto err_initport_create_tranobj; + } + /* Setup Lane_ID mapping */ + i = ARRAY_SIZE(port_layout[minor_curr].lane_id); + j = ARRAY_SIZE(transvr_obj_p->lane_id); + if (i != j) { + snprintf(err_msg, sizeof(err_msg), + "Lane_id size inconsistent %d/%d", i, j); + goto err_initport_reg_device; + } + memcpy(transvr_obj_p->lane_id, port_layout[minor_curr].lane_id, i*sizeof(int)); + /* Create and register device object */ + if (register_port_device(dev_name, MKDEV(port_major, minor_curr), transvr_obj_p) < 0){ + snprintf(err_msg, sizeof(err_msg), + "register_port_device fail"); + goto err_initport_reg_device; + } + /* Setup device_ptr of transvr_obj */ + dev_p = get_swpdev_by_name(dev_name); + if (!dev_p){ + snprintf(err_msg, sizeof(err_msg), + "get_swpdev_by_name fail"); + goto err_initport_reg_device; + } + transvr_obj_p->transvr_dev_p = dev_p; + /* Success */ + ok_count++; + } + SWPS_INFO("%s: initialed %d port-dev",__func__, ok_count); + return 0; + +err_initport_reg_device: + kfree(transvr_obj_p); +err_initport_create_tranobj: + clean_port_obj(); + SWPS_ERR("%s: %s", __func__, err_msg); + SWPS_ERR("Dump: :%d :%d :%d :%d :%d :%d\n", + port_id, chan_id, ioexp_id, ioexp_virt_offset, transvr_type, run_mod); + return -1; +} + +static int __init +swp_module_init(void){ + + if (get_platform_type() < 0){ + goto err_init_out; + } + if (get_layout_info() < 0){ + goto err_init_out; + } + if (register_swp_module() < 0){ + goto err_init_out; + } + if (create_ioexp_objs() < 0){ + goto err_init_ioexp; + } + if (create_port_objs() < 0){ + goto err_init_portobj; + } + if (init_ioexp_objs() < 0){ + goto err_init_portobj; + } + SWPS_INFO("Inventec switch-port module V.%s initial success.\n", SWP_VERSION); + return 0; + + +err_init_portobj: + clean_ioexp_objs(); +err_init_ioexp: + class_unregister(swp_class_p); + class_destroy(swp_class_p); + unregister_chrdev_region(MKDEV(port_major, 0), port_total); +err_init_out: + SWPS_ERR("Inventec switch-port module V.%s initial failure.\n", SWP_VERSION); + return -1; +} + + +static void __exit +swp_module_exit(void){ + clean_port_obj(); + clean_ioexp_objs(); + class_unregister(swp_class_p); + class_destroy(swp_class_p); + unregister_chrdev_region(MKDEV(port_major, 0), port_total); + SWPS_INFO("Remove Inventec switch-port module success.\n"); +} + + +/* Module information */ +MODULE_AUTHOR(SWP_AUTHOR); +MODULE_DESCRIPTION(SWP_DESC); +MODULE_VERSION(SWP_VERSION); +MODULE_LICENSE(SWP_LICENSE); + +module_init(swp_module_init); +module_exit(swp_module_exit); + + + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h new file mode 100644 index 000000000000..f37fd387e4a5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/inv_swps.h @@ -0,0 +1,170 @@ +#ifndef INV_SWPS_H +#define INV_SWPS_H + +#include "transceiver.h" +#include "io_expander.h" + +/* Module settings */ +#define SWP_CLS_NAME "swps" +#define SWP_DEV_PORT "port" +#define SWP_AUTOCONFIG_ENABLE (1) + +/* Module information */ +#define SWP_AUTHOR "Neil " +#define SWP_DESC "Inventec port and transceiver driver" +#define SWP_VERSION "4.2.3" +#define SWP_LICENSE "GPL" + +/* Module status define */ +#define SWP_STATE_NORMAL (0) +#define SWP_STATE_I2C_DIE (-91) + +/* [Note]: + * Functions and mechanism for auto-detect platform type is ready, + * But HW and BIOS not ready! We need to wait them. + * So, please do not use PLATFORM_TYPE_AUTO until they are ready. + * (2016.06.13) + */ +#define PLATFORM_TYPE_CYPRESS_GA2 (152) /* Down -> Up */ +#define PLATFORM_TYPE_CYPRESS_BAI (153) /* Down -> Up */ + +/* Current running platfrom */ +#define PLATFORM_SETTINGS PLATFORM_TYPE_CYPRESS_GA2 + +/* Define platform flag and kernel version */ +#if (PLATFORM_SETTINGS == PLATFORM_TYPE_CYPRESS_GA2) + #define SWPS_KERN_VER_BF_3_8 (1) +#elif (PLATFORM_SETTINGS == PLATFORM_TYPE_CYPRESS_BAI) + #define SWPS_KERN_VER_AF_3_10 (1) +#endif + + +struct inv_platform_s { + int id; + char name[64]; +}; + +struct inv_ioexp_layout_s { + int ioexp_id; + int ioexp_type; + struct ioexp_addr_s addr[4]; +}; + +struct inv_port_layout_s { + int port_id; + int chan_id; + int ioexp_id; + int ioexp_offset; + int transvr_type; + int chipset_type; + int lane_id[8]; +}; + +/* ========================================== + * Inventec Platform Settings + * ========================================== + */ +struct inv_platform_s platform_map = {PLATFORM_TYPE_CYPRESS_GA2, "D7054Q28B" }; + +/* ========================================== + * Cypress Layout configuration (Inventec version [Down->Up]) + * ========================================== + */ +struct inv_ioexp_layout_s cypress_ga2_ioexp_layout[] = { + /* IOEXP_ID / IOEXP_TYPE / { Chan_ID, Chip_addr, Read_offset, Write_offset, config_offset, data_default, conf_default } */ + {0, IOEXP_TYPE_CYPRESS_NABC, { {2, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {2, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {2, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {1, IOEXP_TYPE_CYPRESS_NABC, { {3, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {3, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {3, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {2, IOEXP_TYPE_CYPRESS_NABC, { {4, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {4, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {4, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {3, IOEXP_TYPE_CYPRESS_NABC, { {5, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {5, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {5, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {4, IOEXP_TYPE_CYPRESS_NABC, { {6, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {6, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {6, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {5, IOEXP_TYPE_CYPRESS_NABC, { {7, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[0] = I/O Expander N A */ + {7, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xf0}, {0xff, 0xf0}, }, /* addr[1] = I/O Expander N B */ + {7, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0x00, 0x00}, }, }, /* addr[2] = I/O Expander N C */ + }, + {6, IOEXP_TYPE_CYPRESS_7ABC, { {8, 0x20, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xc0, 0xc0}, }, /* addr[0] = I/O Expander 7 A */ + {8, 0x21, {0, 1}, {2, 3}, {6, 7}, {0xc0, 0xc0}, {0xff, 0xc0}, }, /* addr[1] = I/O Expander 7 B */ + {8, 0x22, {0, 1}, {2, 3}, {6, 7}, {0xff, 0xff}, {0xff, 0xff}, }, }, /* addr[2] = I/O Expander 7 C */ + }, +}; + +struct inv_port_layout_s cypress_ga2_port_layout[] = { + /* Port_ID / Chan_ID / IOEXP_ID / IOEXP_VIRT_OFFSET / TRANSCEIVER_TYPE / BCM_CHIP_TYPE / LANE_ID */ + { 0, 11, 0, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 2} }, + { 1, 10, 0, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 1} }, + { 2, 13, 0, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 4} }, + { 3, 12, 0, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 3} }, + { 4, 15, 0, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 6} }, + { 5, 14, 0, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 5} }, + { 6, 17, 0, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 8} }, + { 7, 16, 0, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 7} }, + { 8, 19, 1, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 10} }, + { 9, 18, 1, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 9} }, + {10, 21, 1, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 12} }, + {11, 20, 1, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 11} }, + {12, 23, 1, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 22} }, + {13, 22, 1, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 21} }, + {14, 25, 1, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 24} }, + {15, 24, 1, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 23} }, + {16, 27, 2, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 34} }, + {17, 26, 2, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 33} }, + {18, 29, 2, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 36} }, + {19, 28, 2, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 35} }, + {20, 31, 2, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 38} }, + {21, 30, 2, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 37} }, + {22, 33, 2, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 40} }, + {23, 32, 2, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 39} }, + {24, 35, 3, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 42} }, + {25, 34, 3, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 41} }, + {26, 37, 3, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 44} }, + {27, 36, 3, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 43} }, + {28, 39, 3, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 50} }, + {29, 38, 3, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 49} }, + {30, 41, 3, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 52} }, + {31, 40, 3, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 51} }, + {32, 43, 4, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 54} }, + {33, 42, 4, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 53} }, + {34, 45, 4, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 56} }, + {35, 44, 4, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 55} }, + {36, 47, 4, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 66} }, + {37, 46, 4, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 65} }, + {38, 49, 4, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 68} }, + {39, 48, 4, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 67} }, + {40, 51, 5, 1, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 70} }, + {41, 50, 5, 0, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 69} }, + {42, 53, 5, 3, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 72} }, + {43, 52, 5, 2, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 71} }, + {44, 55, 5, 5, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 82} }, + {45, 54, 5, 4, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 81} }, + {46, 57, 5, 7, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 84} }, + {47, 56, 5, 6, TRANSVR_TYPE_SFP, BCM_CHIP_TYPE_TOMAHAWK, { 83} }, + {48, 59, 6, 1, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 85, 86, 87, 88} }, + {49, 58, 6, 0, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, { 97, 98, 99,100} }, + {50, 61, 6, 3, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {105,106,107,108} }, + {51, 60, 6, 2, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {101,102,103,104} }, + {52, 63, 6, 5, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {117,118,119,120} }, + {53, 62, 6, 4, TRANSVR_TYPE_QSFP_28, BCM_CHIP_TYPE_TOMAHAWK, {109,110,111,112} }, +}; + + +#endif /* SFP_DRIVER_H */ + + + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c new file mode 100644 index 000000000000..057995e4551a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.c @@ -0,0 +1,944 @@ +#include +#include +#include "io_expander.h" + +static struct ioexp_obj_s *ioexp_head_p = NULL; +static struct ioexp_obj_s *ioexp_tail_p = NULL; + +struct ioexp_map_s ioexp_map_cypress_nabc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */ + {0, 0, 5}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {0, 0, 6}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {0, 0, 7}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {1, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {1, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + {1, 0, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */ + {1, 0, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */ + }, + .map_tx_disable = { {0, 1, 0}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ + {0, 1, 1}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ + {0, 1, 2}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ + {0, 1, 3}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ + {1, 1, 0}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ + {1, 1, 1}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ + {1, 1, 2}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ + {1, 1, 3}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ + }, + .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ + {0, 0, 1}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ + {0, 0, 2}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ + {0, 0, 3}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ + {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ + {1, 0, 1}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ + {1, 0, 2}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ + {1, 0, 3}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ + }, + .map_rxlos = { {0, 1, 4}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ + {0, 1, 5}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ + {0, 1, 6}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ + {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ + {1, 1, 4}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ + {1, 1, 5}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ + {1, 1, 6}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ + {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ + }, +}; + +struct ioexp_map_s ioexp_map_cypress_7abc = { + + .chip_amount = 3, + .data_width = 2, + + .map_present = { {2, 0, 0}, /* map_present[0] = MOD_ABS_PORT(X) */ + {2, 0, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ + {2, 0, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ + {2, 0, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */ + {2, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ + {2, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ + }, + .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP_N_P(X) */ + {0, 0, 1}, /* map_reset[1] = QRESET_QSFP_N_P(X+1) */ + {0, 0, 2}, /* map_reset[2] = QRESET_QSFP_N_P(X+2) */ + {0, 0, 3}, /* map_reset[3] = QRESET_QSFP_N_P(X+3) */ + {0, 0, 4}, /* map_reset[4] = QRESET_QSFP_N_P(X+4) */ + {0, 0, 5}, /* map_reset[5] = QRESET_QSFP_N_P(X+5) */ + }, + .map_lpmod = { {0, 1, 0}, /* map_lpmod[0] = LPMODE_QSFP_P(X) */ + {0, 1, 1}, /* map_lpmod[1] = LPMODE_QSFP_P(X+1) */ + {0, 1, 2}, /* map_lpmod[2] = LPMODE_QSFP_P(X+2) */ + {0, 1, 3}, /* map_lpmod[3] = LPMODE_QSFP_P(X+3) */ + {0, 1, 4}, /* map_lpmod[4] = LPMODE_QSFP_P(X+4) */ + {0, 1, 5}, /* map_lpmod[5] = LPMODE_QSFP_P(X+5) */ + }, + .map_modsel = { {1, 1, 0}, /* map_modsel[0] = MODSEL_QSFP_N_P(X) */ + {1, 1, 1}, /* map_modsel[1] = MODSEL_QSFP_N_P(X+1) */ + {1, 1, 2}, /* map_modsel[2] = MODSEL_QSFP_N_P(X+2) */ + {1, 1, 3}, /* map_modsel[3] = MODSEL_QSFP_N_P(X+3) */ + {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP_N_P(X+4) */ + {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP_N_P(X+5) */ + }, +}; + + + +/* ========== Private functions ========== + */ +int check_channel_tier_1(void); + +struct i2c_client * +_get_i2c_client(struct ioexp_obj_s *self, + int chip_id){ + + struct ioexp_i2c_s *i2c_curr_p = self->i2c_head_p; + + if (!(i2c_curr_p)){ + SWPS_ERR("%s: i2c_curr_p is NULL\n", __func__); + return NULL; + } + while (i2c_curr_p){ + if ((i2c_curr_p->chip_id) == chip_id){ + return i2c_curr_p->i2c_client_p; + } + i2c_curr_p = i2c_curr_p->next; + } + SWPS_ERR("%s: not exist! :%d\n", __func__, chip_id); + return NULL; +} + + +static int +_common_ioexp_update_one(struct ioexp_obj_s *self, + struct ioexp_addr_s *ioexp_addr, + int chip_id, + int data_width, + int show_err, + char *caller_name) { + int buf = 0; + int err = 0; + int data_id = 0; + int r_offset = 0; + + for(data_id=0; data_idread_offset[data_id]; + buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), r_offset); + /* Check error */ + if (buf < 0) { + err = 1; + if (show_err) { + SWPS_INFO("IOEXP-%d read fail! :%d \n", self->ioexp_id, buf); + SWPS_INFO("Dump: :%d :0x%02x :%d, :%s\n", + ioexp_addr->chan_id, ioexp_addr->chip_addr, + ioexp_addr->read_offset[data_id], caller_name); + } + continue; + } + /* Update IOEXP object */ + self->chip_data[chip_id].data[data_id] = (uint8_t)buf; + } + if (err) { + return ERR_IOEXP_UNEXCPT; + } + return 0; +} + + +static int +common_ioexp_update_all(struct ioexp_obj_s *self, + int show_err, + char *caller_name){ + + int err = 0; + int chip_id = 0; + int chip_amount = self->ioexp_map_p->chip_amount; + + for (chip_id=0; chip_idioexp_map_p->map_addr[chip_id]), + chip_id, + self->ioexp_map_p->data_width, + show_err, + caller_name) < 0) { + err = 1; + } + } + if (err) { + return ERR_IOEXP_UNEXCPT; + } + return 0; +} + +static int +_common_get_bit(struct ioexp_obj_s *self, + struct ioexp_bitmap_s *bitmap_obj_p, + char *func_mane){ + uint8_t buf; + int err_code; + + /* Get address */ + err_code = self->fsm_4_direct(self); + if (err_code < 0){ + return err_code; + } + + if (!bitmap_obj_p){ + SWPS_ERR("Layout config incorrect! :%d :%s\n", + self->ioexp_id, func_mane); + return ERR_IOEXP_BADCONF; + } + /* Get data form cache */ + buf = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset]; + return (int)(buf >> bitmap_obj_p->bit_shift & 0x01); +} + + +static int +_common_set_bit(struct ioexp_obj_s *self, + struct ioexp_bitmap_s *bitmap_obj_p, + int input_val, + char *func_mane){ + int err_code, target_offset; + uint8_t origin_byte; + uint8_t modify_byte; + + /* Get address */ + err_code = self->fsm_4_direct(self); + if (err_code < 0){ + return err_code; + } + if (!bitmap_obj_p){ + SWPS_ERR("Layout config incorrect! :%d :%s\n", + self->ioexp_id, func_mane); + return ERR_IOEXP_BADCONF; + } + /* Prepare write date */ + origin_byte = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset]; + switch (input_val) { + case 0: + modify_byte = origin_byte; + SWP_BIT_CLEAR(modify_byte, bitmap_obj_p->bit_shift); + break; + case 1: + modify_byte = origin_byte; + SWP_BIT_SET(modify_byte, bitmap_obj_p->bit_shift); + break; + default: + SWPS_ERR("Input value incorrect! :%d :%d :%s\n", + input_val, self->ioexp_id, func_mane); + return ERR_IOEXP_BADINPUT; + } + /* Setup i2c client */ + target_offset = self->ioexp_map_p->map_addr[bitmap_obj_p->chip_id].write_offset[bitmap_obj_p->ioexp_voffset]; + /* Write byte to chip via I2C */ + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, bitmap_obj_p->chip_id), + target_offset, + modify_byte); + /* Update or bollback object */ + if (err_code < 0){ + self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = origin_byte; + SWPS_ERR("I2C write fail! :%d :%d :%s :%d\n", + input_val, self->ioexp_id, func_mane, err_code); + return err_code; + } + self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = modify_byte; + return 0; +} + + +/* ========== Object public functions ========== + */ +int +common_get_present(struct ioexp_obj_s *self, + int virt_offset){ + + int UNPLUG = 1; + int retval = ERR_IOEXP_UNEXCPT; + + retval = _common_get_bit(self, + &(self->ioexp_map_p->map_present[virt_offset]), + "common_get_present"); + if (retval < 0) { + /* [Note] + * => Transceiver object does not need to handle IOEXP layer issues. + */ + return UNPLUG; + } + return retval; +} + +int +common_get_tx_fault(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_tx_fault[virt_offset]), + "common_get_tx_fault"); +} + +int +common_get_rxlos(struct ioexp_obj_s *self, + int virt_offset){ + /* [Receiver Loss of Signal (Rx_LOS)] + * The post-amplification IC also includes transition detection circuitry + * which monitors the ac level of incoming optical signals and provides a + * TTL/CMOS compatible status signal to the host (pin 8). An adequate optical + * input results in a low Rx_LOS output while a high Rx_LOS output indicates + * an unusable optical input. The Rx_LOS thresholds are factory set so that + * a high output indicates a definite optical fault has occurred. Rx_LOS can + * also be monitored via the two-wire serial interface + * (address A2h, byte 110, bit 1). + * + * 0: Normal + * 1: Abnormal + */ + return _common_get_bit(self, + &(self->ioexp_map_p->map_rxlos[virt_offset]), + "common_get_rxlos"); +} + + +int +common_get_tx_disable(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_tx_disable[virt_offset]), + "common_get_tx_disable"); +} + +int +common_get_reset(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_reset[virt_offset]), + "common_get_reset"); +} + + +int +common_get_lpmod(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_lpmod[virt_offset]), + "common_get_lpmod"); +} + + +int +common_get_modsel(struct ioexp_obj_s *self, + int virt_offset){ + + return _common_get_bit(self, + &(self->ioexp_map_p->map_modsel[virt_offset]), + "common_get_modsel"); +} + +int +common_set_tx_disable(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_tx_disable[virt_offset]), + input_val, + "common_set_tx_disable"); +} + +int +common_set_reset(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_reset[virt_offset]), + input_val, + "common_set_reset"); +} + + +int +common_set_lpmod(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_lpmod[virt_offset]), + input_val, + "common_set_lpmod"); +} + + +int +common_set_modsel(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + + return _common_set_bit(self, + &(self->ioexp_map_p->map_modsel[virt_offset]), + input_val, + "common_set_modsel"); +} + +int +ioexp_get_not_support(struct ioexp_obj_s *self, + int virt_offset){ + return ERR_IOEXP_NOTSUPPORT; +} + + +int +ioexp_set_not_support(struct ioexp_obj_s *self, + int virt_offset, + int input_val){ + return ERR_IOEXP_NOTSUPPORT; +} + +/* ========== Initial functions for IO Expander ========== + */ +int +common_ioexp_init(struct ioexp_obj_s *self) { + + int chip_id, offset, err_code; + struct ioexp_addr_s *addr_p; + + if (self->mode == IOEXP_MODE_DIRECT) { ///important + goto update_common_ioexp_init; + } + /* Setup default value to each physical IO Expander */ + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + /* Get address mapping */ + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + if (!addr_p){ + SWPS_ERR("%s: IOEXP config incorrect! :%d \n", + __func__, chip_id); + return -1; + } + /* Setup default value */ + for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), + addr_p->write_offset[offset], + addr_p->data_default[offset]); + if (err_code < 0){ + SWPS_ERR("%s: set default fail! :%d \n", + __func__, err_code); + return ERR_IOEXP_UNEXCPT; + } + } + } + +update_common_ioexp_init: + /* Check and update info to object */ + err_code = self->update_all(self, 1, "common_ioexp_init"); + if (err_code < 0) { + SWPS_ERR("%s: update_all() fail! :%d \n", + __func__, err_code); + return ERR_IOEXP_UNEXCPT; + } + return 0; +} + + +/* ========== Object functions for Final State Machine ========== + */ +int +_is_channel_ready(struct ioexp_obj_s *self){ + + int buf = 0; + int chip_id = 0; /* Use first chip which be registered */ + int data_id = 0; /* Use first byte which be registered */ + struct ioexp_addr_s *ioexp_addr = NULL; + + ioexp_addr = &(self->ioexp_map_p->map_addr[chip_id]); + if (!ioexp_addr){ + SWPS_ERR("%s: config incorrect!\n", __func__); + return ERR_IOEXP_UNEXCPT; + } + buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), + ioexp_addr->read_offset[data_id]); + if (buf >= 0){ + return 1; + } + return 0; +} + +int +_ioexp_init_handler(struct ioexp_obj_s *self){ + + int return_val; + + switch (self->mode) { + case IOEXP_MODE_DIRECT: + return_val = self->init(self); + if (return_val < 0){ + self->state = STATE_IOEXP_ABNORMAL; + } else { + self->state = STATE_IOEXP_NORMAL; + } + return return_val; + default: + break; + } + SWPS_ERR("%s: exception occur :%d\n", __func__, self->mode); + return ERR_IOEXP_UNEXCPT; +} + + +int +common_ioexp_fsm_4_direct(struct ioexp_obj_s *self){ + + int result_val; + int show_err = 1; + char *func_mane = "common_ioexp_fsm_4_direct"; + + switch (self->state){ + case STATE_IOEXP_INIT: + result_val = _ioexp_init_handler(self); + /* Exception case: terminate initial procedure */ + if(result_val < 0){ + /* Initial fail */ + return result_val; + } + if(self->state == STATE_IOEXP_INIT){ + /* Keep in INIT state, and return error */ + return ERR_IOEXP_UNINIT; + } + /* Case: Initial done */ + return 0; + + case STATE_IOEXP_NORMAL: + result_val = self->update_all(self, show_err, func_mane); + if (result_val < 0){ + SWPS_INFO("%s: NORMAL -> ABNORMAL :%d\n", + __func__, result_val); + self->state = STATE_IOEXP_ABNORMAL; + return result_val; + } + self->state = STATE_IOEXP_NORMAL; + return 0; + + case STATE_IOEXP_ABNORMAL: + result_val = self->update_all(self, show_err, func_mane); + if (result_val < 0){ + self->state = STATE_IOEXP_ABNORMAL; + return result_val; + } + SWPS_DEBUG("%s: ABNORMAL -> NORMAL :%d\n", + __func__, result_val); + self->state = STATE_IOEXP_NORMAL; + return 0; + + default: + break; + } + SWPS_ERR("%s: Exception occurs :%d\n", + __func__, self->state); + return ERR_IOEXP_UNEXCPT; +} + +/* ========== Functions for Factory pattern ========== + */ +static struct ioexp_map_s * +get_ioexp_map(int ioexp_type){ + switch (ioexp_type){ + case IOEXP_TYPE_CYPRESS_NABC: + return &ioexp_map_cypress_nabc; + case IOEXP_TYPE_CYPRESS_7ABC: + return &ioexp_map_cypress_7abc; + default: + return NULL; + } +} + + +int +setup_ioexp_ssize_attr(struct ioexp_obj_s *self, + struct ioexp_map_s *ioexp_map_p, + int ioexp_id, + int ioexp_type, + int run_mode){ + switch (run_mode){ + case IOEXP_MODE_DIRECT: /* Direct access device mode */ + self->mode = run_mode; + break; + default: + SWPS_ERR("%s: non-defined run_mode:%d\n", + __func__, run_mode); + self->mode = ERR_IOEXP_UNEXCPT; + return ERR_IOEXP_UNEXCPT; + } + self->ioexp_id = ioexp_id; + self->ioexp_type = ioexp_type; + self->ioexp_map_p = ioexp_map_p; + self->state = STATE_IOEXP_INIT; + mutex_init(&self->lock); + return 0; +} + + +static int +setup_addr_mapping(struct ioexp_obj_s *self, + struct ioexp_addr_s *addr_map_p){ + if (!addr_map_p){ + SWPS_ERR("%s: map is null\n", __func__); + return -1; + } + self->ioexp_map_p->map_addr = addr_map_p; + return 0; +} + + +static int +setup_ioexp_public_cb(struct ioexp_obj_s *self, + int ioexp_type){ + switch (ioexp_type){ + case IOEXP_TYPE_CYPRESS_NABC: + self->get_present = common_get_present; + self->get_tx_fault = common_get_tx_fault; + self->get_rxlos = common_get_rxlos; + self->get_tx_disable = common_get_tx_disable; + self->get_reset = ioexp_get_not_support; + self->get_lpmod = ioexp_get_not_support; + self->get_modsel = ioexp_get_not_support; + self->set_tx_disable = common_set_tx_disable; + self->set_reset = ioexp_set_not_support; + self->set_lpmod = ioexp_set_not_support; + self->set_modsel = ioexp_set_not_support; + return 0; + case IOEXP_TYPE_CYPRESS_7ABC: + self->get_present = common_get_present; + self->get_tx_fault = ioexp_get_not_support; + self->get_rxlos = ioexp_get_not_support; + self->get_tx_disable = ioexp_get_not_support; + self->get_reset = common_get_reset; + self->get_lpmod = common_get_lpmod; + self->get_modsel = common_get_modsel; + self->set_tx_disable = ioexp_set_not_support; + self->set_reset = common_set_reset; + self->set_lpmod = common_set_lpmod; + self->set_modsel = common_set_modsel; + return 0; + + default: + SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type); + break; + } + return ERR_IOEXP_UNEXCPT; +} + + +static int +setup_ioexp_private_cb(struct ioexp_obj_s *self, + int ioexp_type){ + + switch (ioexp_type){ + case IOEXP_TYPE_CYPRESS_NABC: + case IOEXP_TYPE_CYPRESS_7ABC: + self->init = common_ioexp_init; + self->update_all = common_ioexp_update_all; + self->fsm_4_direct = common_ioexp_fsm_4_direct; + return 0; + + default: + SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type); + break; + } + return ERR_IOEXP_UNEXCPT; +} + + +static int +setup_i2c_client_one(struct ioexp_obj_s *self, + int chip_id){ + + char *err_msg = "ERROR"; + struct i2c_adapter *adap = NULL; + struct i2c_client *client = NULL; + struct ioexp_i2c_s *i2c_obj_p = NULL; + struct ioexp_i2c_s *i2c_curr_p = NULL; + + int chan_id = self->ioexp_map_p->map_addr[chip_id].chan_id; + adap = i2c_get_adapter(chan_id); + if(!adap){ + err_msg = "Can not get adap!"; + goto err_ioexp_setup_i2c_1; + } + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client){ + err_msg = "Can not kzalloc client!"; + goto err_ioexp_setup_i2c_1; + } + i2c_obj_p = kzalloc(sizeof(*i2c_obj_p), GFP_KERNEL); + if (!i2c_obj_p){ + err_msg = "Can not kzalloc i2c_obj_p!"; + goto err_ioexp_setup_i2c_2; + } + client->adapter = adap; + client->addr = self->ioexp_map_p->map_addr[chip_id].chip_addr; + i2c_obj_p->i2c_client_p = client; + i2c_obj_p->chip_id = chip_id; + i2c_obj_p->next = NULL; + if (!self->i2c_head_p){ + self->i2c_head_p = i2c_obj_p; + } else { + i2c_curr_p = self->i2c_head_p; + while (i2c_curr_p->next){ + i2c_curr_p = i2c_curr_p->next; + } + i2c_curr_p->next = i2c_obj_p; + } + return 0; + +err_ioexp_setup_i2c_2: + kfree(client); +err_ioexp_setup_i2c_1: + SWPS_ERR("%s: %s :%d\n", __func__, err_msg, chan_id); + return -1; +} + + +static int +setup_i2c_client(struct ioexp_obj_s* self){ + + int result; + int chip_id = 0; + + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + result = setup_i2c_client_one(self, chip_id); + if (result < 0){ + SWPS_ERR("%s fail! :%d\n", __func__, chip_id); + return -1; + } + } + return 0; +} + +static int +setup_ioexp_config(struct ioexp_obj_s *self) { + + int chip_id, offset, err_code; + struct ioexp_addr_s *addr_p; + + for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ + addr_p = &(self->ioexp_map_p->map_addr[chip_id]); + if (!addr_p){ + SWPS_ERR("IOEXP config incorrect! :%d \n",chip_id); + return -1; + } + for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ + + err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), + addr_p->conf_offset[offset], + addr_p->conf_default[offset]); + + if (err_code < 0){ + SWPS_INFO("%s: set conf fail! :%d \n", __func__, err_code); + return -2; + } + } + } + return 0; +} + +struct ioexp_obj_s * +_create_ioexp_obj(int ioexp_id, + int ioexp_type, + struct ioexp_addr_s *addr_map_p, + int run_mode){ + + struct ioexp_map_s* ioexp_map_p; + struct ioexp_obj_s* result_p; + struct ioexp_i2c_s *i2c_curr_p; + struct ioexp_i2c_s *i2c_next_p; + + /* Get layout */ + ioexp_map_p = get_ioexp_map(ioexp_type); + if (!ioexp_map_p){ + SWPS_ERR("%s: Invalid ioexp_type\n", __func__); + goto err_create_ioexp_fail; + } + /* Prepare IOEXP object */ + result_p = kzalloc(sizeof(*result_p), GFP_KERNEL); + if (!result_p){ + SWPS_ERR("%s: kzalloc failure!\n", __func__); + goto err_create_ioexp_fail; + } + /* Prepare static size attributes */ + if (setup_ioexp_ssize_attr(result_p, + ioexp_map_p, + ioexp_id, + ioexp_type, + run_mode) < 0){ + goto err_create_ioexp_setup_attr_fail; + } + /* Prepare address mapping */ + if (setup_addr_mapping(result_p, addr_map_p) < 0){ + goto err_create_ioexp_setup_attr_fail; + } + if (setup_i2c_client(result_p) < 0){ + goto err_create_ioexp_setup_i2c_fail; + } + /* Prepare call back functions of object */ + if (setup_ioexp_public_cb(result_p, ioexp_type) < 0){ + goto err_create_ioexp_setup_i2c_fail; + } + if (setup_ioexp_private_cb(result_p, ioexp_type) < 0){ + goto err_create_ioexp_setup_i2c_fail; + } + return result_p; + +err_create_ioexp_setup_i2c_fail: + i2c_curr_p = result_p->i2c_head_p; + i2c_next_p = result_p->i2c_head_p; + while (i2c_curr_p){ + i2c_next_p = i2c_curr_p->next; + kfree(i2c_curr_p->i2c_client_p); + kfree(i2c_curr_p); + i2c_curr_p = i2c_next_p; + } +err_create_ioexp_setup_attr_fail: + kfree(result_p); +err_create_ioexp_fail: + SWPS_ERR("%s: fail! :%d :%d \n", + __func__, ioexp_id, ioexp_type); + return NULL; +} + + +int +create_ioexp_obj(int ioexp_id, + int ioexp_type, + struct ioexp_addr_s *addr_map_p, + int run_mode){ + + struct ioexp_obj_s *ioexp_p = NULL; + + ioexp_p = _create_ioexp_obj(ioexp_id, ioexp_type, + addr_map_p, run_mode); + if (!ioexp_p){ + return -1; + } + if (ioexp_head_p == NULL){ + ioexp_head_p = ioexp_p; + ioexp_tail_p = ioexp_p; + return 0; + } + ioexp_tail_p->next = ioexp_p; + ioexp_tail_p = ioexp_p; + return 0; +} + +static int +_init_ioexp_obj(struct ioexp_obj_s* self) { + + char *err_msg = "ERR"; + char *func_name = "_init_ioexp_obj"; + + /* Setup IOEXP configure byte */ + if (setup_ioexp_config(self) < 0){ + err_msg = "setup_ioexp_config fail"; + goto err_init_ioexp_obj; + } + /* Setup default data */ + if (_ioexp_init_handler(self) < 0){ + err_msg = "_ioexp_init_handler fail"; + goto err_init_ioexp_obj; + } + /* Update all */ + if (self->state == STATE_IOEXP_NORMAL){ + if (self->update_all(self, 1, func_name) < 0){ + err_msg = "update_all() fail"; + goto err_init_ioexp_obj; + } + } + return 0; + +err_init_ioexp_obj: + SWPS_DEBUG("%s: %s\n", __func__, err_msg); + return -1; +} + +int +init_ioexp_objs(void){ + /* Return value: + * 0: Success + * -1: Detect topology error + * -2: SWPS internal error + */ + + struct ioexp_obj_s *curr_p = ioexp_head_p; + + if (!curr_p) { + SWPS_ERR("%s: ioexp_head_p is NULL\n", __func__); + return -2; + } + while (curr_p) { + if (_init_ioexp_obj(curr_p) < 0) { + SWPS_DEBUG("%s: _init_ioexp_obj() fail\n", __func__); + return -1; + } + curr_p = curr_p->next; + } + SWPS_DEBUG("%s: done.\n", __func__); + return 0; +} + +void +clean_ioexp_objs(void){ + + struct ioexp_i2c_s *i2c_curr_p = NULL; + struct ioexp_i2c_s *i2c_next_p = NULL; + struct ioexp_obj_s *ioexp_next_p = NULL; + struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p; + + if (ioexp_head_p == NULL){ + ioexp_tail_p = NULL; + return; + } + while(ioexp_curr_p){ + ioexp_next_p = ioexp_curr_p->next; + i2c_curr_p = ioexp_curr_p->i2c_head_p; + while (i2c_curr_p) { + i2c_next_p = i2c_curr_p->next; + kfree(i2c_curr_p->i2c_client_p); + kfree(i2c_curr_p); + i2c_curr_p = i2c_next_p; + } + kfree(ioexp_curr_p); + ioexp_curr_p = ioexp_next_p; + } + ioexp_tail_p = NULL; + SWPS_DEBUG("%s: done.\n", __func__); +} + +struct ioexp_obj_s * +get_ioexp_obj(int ioexp_id){ + + struct ioexp_obj_s *result_p = NULL; + struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p; + + while(ioexp_curr_p){ + if (ioexp_curr_p->ioexp_id == ioexp_id){ + result_p = ioexp_curr_p; + break; + } + ioexp_curr_p = ioexp_curr_p->next; + } + return result_p; +} +int +check_channel_tier_1(void) { + + if ( (!_is_channel_ready(ioexp_head_p)) && + (!_is_channel_ready(ioexp_tail_p)) ){ + return -1; + } + return 0; +} + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h new file mode 100644 index 000000000000..a5541617dd05 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/io_expander.h @@ -0,0 +1,143 @@ +#ifndef IO_EXPANDER_H +#define IO_EXPANDER_H + +#include + +/* IOEXP type define (QSFP series) */ +#define IOEXP_TYPE_CYPRESS_NABC (10102) +#define IOEXP_TYPE_CYPRESS_7ABC (10207) + +/* IOEXP mode define */ +#define IOEXP_MODE_DIRECT (19001) + +/* IOEXP state define */ +#define STATE_IOEXP_NORMAL (0) +#define STATE_IOEXP_INIT (-1) +#define STATE_IOEXP_ABNORMAL (-2) + +/* IOEXP error code define */ +#define ERR_IOEXP_NOTSUPPORT (-100) +#define ERR_IOEXP_UNINIT (-101) +#define ERR_IOEXP_BADCONF (-102) +#define ERR_IOEXP_BADINPUT (-105) +#define ERR_IOEXP_UNEXCPT (-199) + + +#define SWPS_INFO(fmt, args...) printk( KERN_INFO "[SWPS] " fmt, ##args) +#define SWPS_WARN(fmt, args...) printk( KERN_WARNING "[SWPS] " fmt, ##args) +#define SWPS_ERR(fmt, args...) printk( KERN_ERR "[SWPS] " fmt, ##args) + +#ifdef DEBUG_SWPS +# define SWPS_DEBUG(fmt, args...) printk( KERN_DEBUG "[SWPS] " fmt, ##args) +#else +# define SWPS_DEBUG(fmt, args...) +#endif + + +struct ioexp_addr_s { + int chan_id; + int chip_addr; + int read_offset[8]; + int write_offset[8]; + int conf_offset[8]; + uint8_t data_default[8]; + uint8_t conf_default[8]; +}; + +struct ioexp_i2c_s { + int chip_id; + struct i2c_client *i2c_client_p; + struct ioexp_i2c_s *next; +}; + + +struct ioexp_bitmap_s { + int chip_id; /* IOEXP chip id */ + int ioexp_voffset; /* IOEXP virtual offset */ + int bit_shift; +}; + +struct ioexp_map_s { + int chip_amount; /* Number of chips that IOEXP object content */ + int data_width; /* Number of (Read/Write/Config) bytes */ + struct ioexp_addr_s *map_addr; /* Chip address info */ + struct ioexp_bitmap_s map_present[8]; /* IOEXP for SFP / QSFP */ + struct ioexp_bitmap_s map_tx_disable[8]; /* IOEXP for SFP */ + struct ioexp_bitmap_s map_tx_fault[8]; /* IOEXP for SFP */ + struct ioexp_bitmap_s map_rxlos[8]; /* IOEXP for SFP */ + struct ioexp_bitmap_s map_reset[8]; /* IOEXP for QSFP */ + struct ioexp_bitmap_s map_lpmod[8]; /* IOEXP for QSFP */ + struct ioexp_bitmap_s map_modsel[8]; /* IOEXP for QSFP */ +}; + +struct ioexp_data_s { + uint8_t data[8]; +}; + +struct ioexp_obj_s { + + /* ============================ + * Object public property + * ============================ + */ + int ioexp_id; + int ioexp_type; + + /* ============================ + * Object private property + * ============================ + */ + struct ioexp_data_s chip_data[16]; /* Max: 8-ioexp in one virt-ioexp(ioexp_obj) */ + struct ioexp_map_s *ioexp_map_p; + struct ioexp_obj_s *next; + struct ioexp_i2c_s *i2c_head_p; + struct mutex lock; + int mode; + int state; + + /* =========================================== + * Object public functions + * =========================================== + */ + int (*get_present)(struct ioexp_obj_s *self, int virt_offset); + int (*get_tx_fault)(struct ioexp_obj_s *self, int virt_offset); + int (*get_rxlos)(struct ioexp_obj_s *self, int virt_offset); + int (*get_tx_disable)(struct ioexp_obj_s *self, int virt_offset); + int (*get_reset)(struct ioexp_obj_s *self, int virt_offset); + int (*get_lpmod)(struct ioexp_obj_s *self, int virt_offset); + int (*get_modsel)(struct ioexp_obj_s *self, int virt_offset); + int (*set_tx_disable)(struct ioexp_obj_s *self, int virt_offset, int input_val); + int (*set_reset)(struct ioexp_obj_s *self, int virt_offset, int input_val); + int (*set_lpmod)(struct ioexp_obj_s *self, int virt_offset, int input_val); + int (*set_modsel)(struct ioexp_obj_s *self, int virt_offset, int input_val); + + /* =========================================== + * Object private functions + * =========================================== + */ + int (*init)(struct ioexp_obj_s *self); + int (*update_all)(struct ioexp_obj_s *self, int show_err, char *caller_name); + int (*fsm_4_direct)(struct ioexp_obj_s* self); +}; + + +struct ioexp_obj_s* get_ioexp_obj(int ioexp_id); +int create_ioexp_obj(int ioexp_id, + int ioexp_type, + struct ioexp_addr_s *addr_map_p, + int run_mode); +int init_ioexp_objs(void); +void clean_ioexp_objs(void); + +int check_channel_tier_1(void); + +/* Macro for bit control */ +#define SWP_BIT_SET(byte_val,bit_shift) ((byte_val) |= (1<<(bit_shift))) +#define SWP_BIT_CLEAR(byte_val,bit_shift) ((byte_val) &= ~(1<<(bit_shift))) + + +#endif /* IO_EXPANDER_H */ + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c new file mode 100644 index 000000000000..368e412b19e2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.c @@ -0,0 +1,906 @@ +#include +#include +#include +#include +#include "io_expander.h" +#include "transceiver.h" + + +/* ========== Register EEPROM address mapping ========== + */ +struct eeprom_map_s eeprom_map_sfp = { + .addr_rx_los =-1, .page_rx_los =-1, .offset_rx_los =-1, .length_rx_los =-1, + .addr_tx_disable =-1, .page_tx_disable =-1, .offset_tx_disable =-1, .length_tx_disable =-1, + .addr_tx_fault =-1, .page_tx_fault =-1, .offset_tx_fault =-1, .length_tx_fault =-1, +}; + +struct eeprom_map_s eeprom_map_qsfp = { + .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1, + .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1, + .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1, +}; + +struct eeprom_map_s eeprom_map_qsfp28 = { + .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1, + .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1, + .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1, +}; + + +/* ========== Utility Functions ========== + */ +void +alarm_msg_2_user(struct transvr_obj_s *self, + char *emsg) { + + SWPS_ERR("%s on %s.\n", emsg, self->swp_name); +} + + +/* ========== Private functions ========== + */ +static int +_reload_transvr_obj(struct transvr_obj_s *self,int new_type); + +static int +reload_transvr_obj(struct transvr_obj_s *self,int new_type); + +static int +_transvr_init_handler(struct transvr_obj_s *self); + +static void +_transvr_clean_retry(struct transvr_obj_s *self) { + self->retry = 0; +} + + +static int +_transvr_handle_retry(struct transvr_obj_s *self, int retry) { + /* Return: 0: keep retry + * -1: stop retry + */ + if (self->retry == 0) { + self->retry = retry; + } + self->retry -= 1; + if (self->retry <= 0) { + _transvr_clean_retry(self); + return -1; + } + return 0; +} + +static int +_common_setup_page(struct transvr_obj_s *self, + int addr, + int page, + int offset, + int len, + int show_e) { + /* return: + * 0 : OK + * -1 : EEPROM settings incorrect + * -2 : I2C R/W failure + * -3 : Undefined case + */ + int retval = DEBUG_TRANSVR_INT_VAL; + char *emsg = DEBUG_TRANSVR_STR_VAL; + + /* Check */ + if ((addr < 0) || (offset < 0) || (len < 0)) { + emsg = "EEPROM settings incorrect"; + retval = -1; + goto err_common_setup_page; + } + /* Case1: continue access */ + if ((self->i2c_client_p->addr == addr) && + (self->curr_page == page)) { + return 0; + } + self->i2c_client_p->addr = addr; + /* Case2: select lower page */ + if (page == -1) { + self->curr_page = page; + return 0; + } + /* Case3: select upper page */ + if (page >= 0) { + goto upper_common_setup_page; + } + /* Unexpected case */ + show_e = 1; + emsg = "Unexpected case"; + retval = -3; + goto err_common_setup_page; + +upper_common_setup_page: + if (i2c_smbus_write_byte_data(self->i2c_client_p, + VAL_TRANSVR_PAGE_SELECT_OFFSET, + page) < 0) { + emsg = "I2C R/W failure"; + retval = -2; + goto err_common_setup_page; + } + self->curr_page = page; + mdelay(VAL_TRANSVR_PAGE_SELECT_DELAY); + return 0; + +err_common_setup_page: + if (show_e) { + SWPS_INFO("%s: %s", __func__, emsg); + SWPS_INFO("%s: :0x%02x :%d :%d :%d\n", + __func__, addr, page, offset, len); + } + return retval; +} + +/* ========== Object functions for Final State Machine ========== + */ +int +is_plugged(struct transvr_obj_s *self){ + + int limit = 63; + int present = DEBUG_TRANSVR_INT_VAL; + char emsg[64] = DEBUG_TRANSVR_STR_VAL; + struct ioexp_obj_s *ioexp_p = self->ioexp_obj_p; + + if (!ioexp_p) { + snprintf(emsg, limit, "ioexp_p is null!"); + goto err_is_plugged_1; + } + present = ioexp_p->get_present(ioexp_p, self->ioexp_virt_offset); + switch (present){ + case 0: + return 1; + case 1: + return 0; + case ERR_IOEXP_UNINIT: + snprintf(emsg, limit, "ioexp_p not ready!"); + goto err_is_plugged_1; + default: + if (ioexp_p->state == STATE_IOEXP_INIT){ + snprintf(emsg, limit, "ioexp_p not ready!"); + goto err_is_plugged_1; + } + break; + } + SWPS_INFO("%s: Exception case! :%d :%d\n", + __func__, present, ioexp_p->state); + return 0; + +err_is_plugged_1: + SWPS_DEBUG("%s: %s\n", __func__, emsg); + return 0; +} + + +static int +detect_transvr_type(struct transvr_obj_s* self){ + + int type = TRANSVR_TYPE_ERROR; + + self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; + type = i2c_smbus_read_byte_data(self->i2c_client_p, + VAL_TRANSVR_COMID_OFFSET); + + /* Case: 1. Wait transceiver I2C module. + * 2. Transceiver I2C module failure. + * Note: 1. SFF allow maximum transceiver initial time is 2 second. So, there + * are exist some case that we need to wait transceiver. + * For these case, we keeps status on "TRANSVR_TYPE_UNPLUGGED", than + * state machine will keep trace with it. + * 2. There exist some I2C failure case we need to handle. Such as user + * insert the failure transceiver, or any reason cause it abnormal. + */ + if (type < 0){ + switch (type) { + case -EIO: + SWPS_DEBUG("%s: %s smbus return:-5 (I/O error)\n", + __func__, self->swp_name); + return TRANSVR_TYPE_UNPLUGGED; + case -ENXIO: + SWPS_DEBUG("%s: %s smbus return:-6 (No such device or address)\n", + __func__, self->swp_name); + return TRANSVR_TYPE_UNPLUGGED; + default: + break; + } + SWPS_INFO("%s: %s unexpected smbus return:%d \n", + __func__, self->swp_name, type); + return TRANSVR_TYPE_ERROR; + } + /* Identify valid transceiver type */ + switch (type){ + case TRANSVR_TYPE_SFP: + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + case TRANSVR_TYPE_QSFP_28: + break; + case TRANSVR_TYPE_UNKNOW_1: + case TRANSVR_TYPE_UNKNOW_2: + type = TRANSVR_TYPE_UNKNOW_2; + break; + default: + SWPS_DEBUG("%s: unknow type:0x%02x \n", __func__, type); + type = TRANSVR_TYPE_ERROR; + break; + } + return type; +} + + +static int +detect_transvr_state(struct transvr_obj_s *self, + int result[2]){ + /* [return] [result-0] [result-1] + * 0 STATE_TRANSVR_CONNECTED TRANSVR_TYPE_FAKE + * 0 STATE_TRANSVR_DISCONNECTED TRANSVR_TYPE_UNPLUGGED + * 0 STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR + * 0 STATE_TRANSVR_INIT / + * 0 STATE_TRANSVR_SWAPPED + * 0 STATE_TRANSVR_CONNECTED + * ERR_TRNASVR_BE_ISOLATED STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR + * ERR_TRANSVR_I2C_CRASH STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_ERROR + * ERR_TRANSVR_UNEXCPT STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_UNKNOW_1/2 + */ + result[0] = STATE_TRANSVR_UNEXCEPTED; /* For return state */ + result[1] = TRANSVR_TYPE_ERROR; /* For return type */ + + /* Case1: Fake type */ + if (self->type == TRANSVR_TYPE_FAKE){ + result[0] = STATE_TRANSVR_CONNECTED; + result[1] = TRANSVR_TYPE_FAKE; + return 0; + } + /* Case2: Transceiver unplugged */ + if (!is_plugged(self)){ + result[0] = STATE_TRANSVR_DISCONNECTED; + result[1] = TRANSVR_TYPE_UNPLUGGED; + return 0; + } + /* Case3: Transceiver be isolated */ + if (self->state == STATE_TRANSVR_ISOLATED){ + result[0] = STATE_TRANSVR_ISOLATED; + result[1] = TRANSVR_TYPE_ERROR; + return ERR_TRNASVR_BE_ISOLATED; + } + /* Case4: Transceiver plugged */ + result[1] = detect_transvr_type(self); + /* Case4.1: I2C topology crash + * Note : There are some I2C issues cause by transceiver/cables. + * We need to check topology status when user insert it. + * But in this step, we can't not ensure this is the issues + * port. So, it return the ERR_TRANSVR_I2C_CRASH, then upper + * layer will diagnostic I2C topology. + */ + if (check_channel_tier_1() < 0) { + SWPS_INFO("%s: %s detect I2C crash :%d\n", + __func__, self->swp_name, self->state); + result[0] = STATE_TRANSVR_UNEXCEPTED; + result[1] = TRANSVR_TYPE_ERROR; + return ERR_TRANSVR_I2C_CRASH; + } + /* Case4.2: System initial not ready, + * Note : Sometime i2c channel or transceiver EEPROM will delay that will + * cause system in inconsistent state between EEPROM and IOEXP. + * In this case, SWP transceiver object keep state at LINK_DOWN + * to wait system ready. + * By the way, State Machine will handle these case. + */ + if (result[1] == TRANSVR_TYPE_UNPLUGGED){ + result[0] = STATE_TRANSVR_DISCONNECTED; + return 0; + } + /* Case4.3: Error transceiver type */ + if (result[1] == TRANSVR_TYPE_ERROR){ + result[0] = STATE_TRANSVR_ISOLATED; + SWPS_INFO("%s: %s detect error type\n", __func__, self->swp_name); + alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard!"); + return ERR_TRNASVR_BE_ISOLATED; + } + /* Case3.3: Unknow transceiver type */ + if ((result[1] == TRANSVR_TYPE_UNKNOW_1) || + (result[1] == TRANSVR_TYPE_UNKNOW_2) ){ + result[0] = STATE_TRANSVR_UNEXCEPTED; + return ERR_TRANSVR_UNEXCPT; + } + /* Case3.4: During initial process */ + if (self->state == STATE_TRANSVR_INIT){ + result[0] = STATE_TRANSVR_INIT; + return 0; + } + /* Case3.5: Transceiver be swapped */ + if (self->type != result[1]){ + result[0] = STATE_TRANSVR_SWAPPED; + return 0; + } + /* Case3.6: Link up state */ + result[0] = STATE_TRANSVR_CONNECTED; + return 0; +} +int +common_fsm_4_direct_mode(struct transvr_obj_s* self, + char *caller_name){ + + int err; + int detect_result[2]; + int current_state = STATE_TRANSVR_UNEXCEPTED; + int current_type = TRANSVR_TYPE_ERROR; + + if (self->state == STATE_TRANSVR_NEW) { + if (_transvr_init_handler(self) < 0){ + return ERR_TRANSVR_INIT_FAIL; + } + } + err = detect_transvr_state(self, detect_result); + if (err < 0) { + return err; + } + /* In Direct mode, driver only detect transceiver when user call driver interface + * which on sysfs. So it only need consider the state of Transceiver. + */ + current_state = detect_result[0]; + current_type = detect_result[1]; + + switch (current_state){ + + case STATE_TRANSVR_DISCONNECTED: /* Transceiver is not plugged */ + self->state = current_state; + self->type = current_type; + return ERR_TRANSVR_UNPLUGGED; + + case STATE_TRANSVR_INIT: /* Transceiver is plugged, system not ready */ + return ERR_TRANSVR_UNINIT; + + case STATE_TRANSVR_ISOLATED: /* Transceiver is plugged, but has some issues */ + return ERR_TRNASVR_BE_ISOLATED; + + case STATE_TRANSVR_CONNECTED: /* Transceiver is plugged, system is ready */ + self->state = current_state; + self->type = current_type; + return 0; + + case STATE_TRANSVR_SWAPPED: /* Transceiver is plugged, system detect user changed */ + self->type = current_type; + if (reload_transvr_obj(self, current_type) < 0){ + self->state = STATE_TRANSVR_UNEXCEPTED; + return ERR_TRANSVR_UNEXCPT; + } + self->state = current_state; + return 0; + + case STATE_TRANSVR_UNEXCEPTED: /* Transceiver type or state is unexpected case */ + self->state = STATE_TRANSVR_UNEXCEPTED; + self->type = TRANSVR_TYPE_ERROR; + return ERR_TRANSVR_UNEXCPT; + + default: + SWPS_INFO("%s: state:%d not in define.\n", __func__, current_state); + break; + } + return ERR_TRANSVR_UNEXCPT; +} + +int +fake_fsm_4_direct_mode(struct transvr_obj_s* self, + char *caller_name){ + self->state = STATE_TRANSVR_CONNECTED; + self->type = TRANSVR_TYPE_FAKE; + return 0; +} + +/* ========== Object Initial handler ========== + */ +static int +_is_transvr_valid(struct transvr_obj_s *self, + int type, + int state) { + /* [Return] + * 0 : OK, inserted + * EVENT_TRANSVR_INIT_DOWN : OK, removed + * EVENT_TRANSVR_INIT_FAIL : Outside error, type doesn't supported + * EVENT_TRANSVR_EXCEP_INIT : Internal error, state undefined + */ + switch (type) { + case TRANSVR_TYPE_SFP: + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + case TRANSVR_TYPE_QSFP_28: + case TRANSVR_TYPE_UNPLUGGED: + case TRANSVR_TYPE_FAKE: + break; + default: + SWPS_INFO("detect undefined type:0x%02x on %s\n", + type, self->swp_name); + return EVENT_TRANSVR_INIT_FAIL; + } + switch (state) { + case STATE_TRANSVR_DISCONNECTED: + return EVENT_TRANSVR_INIT_DOWN; + case STATE_TRANSVR_INIT: + case STATE_TRANSVR_CONNECTED: + case STATE_TRANSVR_SWAPPED: + break; + default: + SWPS_INFO("detect undefined state:%d on %s\n", + state, self->swp_name); + return EVENT_TRANSVR_EXCEP_INIT; + } + return 0; +} + + +static int +_is_transvr_hw_ready(struct transvr_obj_s *self, + int type){ + /* [Return] + * EVENT_TRANSVR_TASK_DONE : Ready + * EVENT_TRANSVR_TASK_WAIT : Not ready + * EVENT_TRANSVR_INIT_FAIL : Error + */ + int addr = DEBUG_TRANSVR_INT_VAL; + int page = DEBUG_TRANSVR_INT_VAL; + int offs = DEBUG_TRANSVR_INT_VAL; + int bit = DEBUG_TRANSVR_INT_VAL; + int ready = DEBUG_TRANSVR_INT_VAL; + int err = DEBUG_TRANSVR_INT_VAL; + char *emsg = DEBUG_TRANSVR_STR_VAL; + uint8_t ab_val = DEBUG_TRANSVR_HEX_VAL; + + switch (type) { + case TRANSVR_TYPE_SFP: + addr = VAL_TRANSVR_8472_READY_ADDR; + page = VAL_TRANSVR_8472_READY_PAGE; + offs = VAL_TRANSVR_8472_READY_OFFSET; + bit = VAL_TRANSVR_8472_READY_BIT; + ready = VAL_TRANSVR_8472_READY_VALUE; + ab_val = VAL_TRANSVR_8472_READY_ABNORMAL; + break; + + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + case TRANSVR_TYPE_QSFP_28: + addr = VAL_TRANSVR_8436_READY_ADDR; + page = VAL_TRANSVR_8436_READY_PAGE; + offs = VAL_TRANSVR_8436_READY_OFFSET; + bit = VAL_TRANSVR_8436_READY_BIT; + ready = VAL_TRANSVR_8436_READY_VALUE; + ab_val = VAL_TRANSVR_8436_READY_ABNORMAL; + break; + + case TRANSVR_TYPE_UNPLUGGED: + case TRANSVR_TYPE_FAKE: + return EVENT_TRANSVR_TASK_DONE; + + default: + emsg = "unexpected case"; + goto err_is_transvr_hw_ready; + } + /* Select target page */ + err = _common_setup_page(self, addr, page, offs, 1, 0); + if (err < 0) { + emsg = "setup page fail"; + goto err_is_transvr_hw_ready; + } + /* Check feature supported + * [Note] + * Some of transceiver/cables doesn't support "Status Indicators" + * (ex:DAC, RJ45 copper SFP ...etc). In these case, we bypass the + * step of checking Status Indicators, then state machine will take + * the following handle procedure. + */ + err = i2c_smbus_read_byte_data(self->i2c_client_p, + VAL_TRANSVR_COMID_OFFSET); + if (err < 0) { + emsg = "doesn't support Status Indicators"; + goto bypass_is_transvr_hw_ready; + } + /* Filter abnormal case */ + if (err == ab_val) { + emsg = "detect using unusual definition."; + goto bypass_is_transvr_hw_ready; + } + /* Get Status Indicators */ + err = i2c_smbus_read_byte_data(self->i2c_client_p, offs); + if (err < 0) { + emsg = "detect current value fail"; + goto err_is_transvr_hw_ready; + } + if ((err & (1<:%d\n", __func__, emsg, type); + return EVENT_TRANSVR_TASK_DONE; + +err_is_transvr_hw_ready: + SWPS_DEBUG("%s: %s :%d\n", __func__, emsg, type); + return EVENT_TRANSVR_INIT_FAIL; +} + +static int +_transvr_init_handler(struct transvr_obj_s *self){ + + int detect[2]; + int d_state = STATE_TRANSVR_UNEXCEPTED; + int d_type = TRANSVR_TYPE_ERROR; + int result = ERR_TRANSVR_UNINIT; + int retry = 6; /* (6+1) x 0.3 = 2.1s > spec:2.0s */ + int elimit = 63; + char emsg[64] = DEBUG_TRANSVR_STR_VAL; + + /* Clean and check callback */ + self->state = STATE_TRANSVR_INIT; + if (self->init == NULL) { + snprintf(emsg, elimit, "init() is null"); + goto initer_err_case_unexcept_0; + } + /* Detect transceiver information */ + result = detect_transvr_state(self, detect); + if (result < 0) { + snprintf(emsg, elimit, "detect_transvr_state() fail"); + switch (result) { + case ERR_TRANSVR_I2C_CRASH: + goto initer_err_case_i2c_ceash; + case ERR_TRNASVR_BE_ISOLATED: + goto initer_err_case_be_isolated; + + case ERR_TRANSVR_UNEXCPT: + default: + break; + } + goto initer_err_case_retry_1; + } + d_state = detect[0]; + d_type = detect[1]; + + /* Verify transceiver type and state */ + switch (_is_transvr_valid(self, d_type, d_state)) { + case 0: + break; + case EVENT_TRANSVR_INIT_DOWN: + goto initer_ok_case_down;; + case EVENT_TRANSVR_INIT_FAIL: + snprintf(emsg, elimit, "transceiver type doesn't support"); + goto initer_err_case_alarm_to_user; + case EVENT_TRANSVR_EXCEP_INIT: + default: + goto initer_err_case_unexcept_0; + } + + /* Handle reload case */ + if (self->type != d_type){ + /* This is the protect mechanism. Normally, This case will not happen. + * When State machine detect swap event during initial, It will trigger + * reload function to ensure type correct. */ + if (_reload_transvr_obj(self, d_type) < 0){ + snprintf(emsg, elimit, "reload object fail"); + goto initer_err_case_unexcept_0; + } + } + + /* Check transceiver HW initial ready */ + switch (_is_transvr_hw_ready(self, d_type)) { + case EVENT_TRANSVR_TASK_DONE: + break; + case EVENT_TRANSVR_TASK_WAIT: + goto initer_err_case_retry_1; + case EVENT_TRANSVR_INIT_FAIL: + default: + goto initer_err_case_unexcept_0; + } + + /* Try to update all and check */ + if (self->update_all(self, 1) < 0){ + /* For some transceiver, EEPROME has lag issues during initial stage. + * In this case, we set status back to STATE_TRANSVR_NEW, than it will + * be checked in next polling cycle. */ + goto initer_err_case_retry_1; + } + + /* Execute init() call back */ + result = self->init(self); + switch (result) { + case EVENT_TRANSVR_TASK_DONE: + break; + case EVENT_TRANSVR_TASK_WAIT: + goto initer_ok_case_wait; + + default: + snprintf(emsg, elimit, "undefined init() return:%d\n", result); + goto initer_err_case_unexcept_0; + } + goto initer_ok_case_up; + + +initer_ok_case_wait: + return EVENT_TRANSVR_TASK_WAIT; + +initer_ok_case_up: + self->state = STATE_TRANSVR_CONNECTED; + self->temp = 0; + return EVENT_TRANSVR_INIT_UP; + +initer_ok_case_down: + self->temp = 0; + self->state = STATE_TRANSVR_DISCONNECTED; + return EVENT_TRANSVR_INIT_DOWN; + +initer_err_case_i2c_ceash: + SWPS_DEBUG("%s: %s :%s :I2C crash\n", + __func__, emsg, self->swp_name); + self->state = STATE_TRANSVR_UNEXCEPTED; + return EVENT_TRANSVR_I2C_CRASH; + +initer_err_case_be_isolated: + SWPS_DEBUG("%s: %s :%s :isolated\n", + __func__, emsg, self->swp_name); + self->state = STATE_TRANSVR_ISOLATED; + return EVENT_TRANSVR_EXCEP_ISOLATED; + +initer_err_case_retry_1: + SWPS_DEBUG("%s: %s :%s :retry\n", + __func__, emsg, self->swp_name); + if (_transvr_handle_retry(self, retry) == 0) { + self->state = STATE_TRANSVR_NEW; + return EVENT_TRANSVR_INIT_REINIT; + } + goto initer_err_case_alarm_to_user; + +initer_err_case_unexcept_0: + self->state = STATE_TRANSVR_UNEXCEPTED; + return EVENT_TRANSVR_INIT_FAIL; + +initer_err_case_alarm_to_user: + SWPS_DEBUG("%s: %s :%s :alarm_to_user\n", + __func__, emsg, self->swp_name); + self->state = STATE_TRANSVR_UNEXCEPTED; + alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard"); + return EVENT_TRANSVR_INIT_FAIL; +} + +static int +setup_transvr_private_cb(struct transvr_obj_s *self, + int transvr_type){ + switch (transvr_type){ + case TRANSVR_TYPE_SFP: + self->fsm_4_direct = common_fsm_4_direct_mode; + return 0; + + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + self->fsm_4_direct = common_fsm_4_direct_mode; + return 0; + + case TRANSVR_TYPE_QSFP_28: + self->fsm_4_direct = common_fsm_4_direct_mode; + return 0; + + case TRANSVR_TYPE_FAKE: + self->fsm_4_direct = fake_fsm_4_direct_mode; + return 0; + + default: + break; + } + SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); + return ERR_TRANSVR_UNEXCPT; +} + + +static struct eeprom_map_s * +get_eeprom_map(int transvr_type){ + + switch (transvr_type){ + case TRANSVR_TYPE_SFP: + return &eeprom_map_sfp; + case TRANSVR_TYPE_QSFP: + case TRANSVR_TYPE_QSFP_PLUS: + return &eeprom_map_qsfp; + case TRANSVR_TYPE_QSFP_28: + return &eeprom_map_qsfp28; + + default: + break; + } + SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); + return NULL; +} + + +static int +setup_transvr_ssize_attr(char *swp_name, + struct transvr_obj_s *self, + struct eeprom_map_s *map_p, + struct ioexp_obj_s *ioexp_obj_p, + int ioexp_virt_offset, + int transvr_type, + int chipset_type, + int chan_id, + int run_mode){ + switch (run_mode){ + case TRANSVR_MODE_DIRECT: /* Direct access device mode */ + self->mode = run_mode; + break; + default: + SWPS_ERR("%s: non-defined run_mode:%d\n", + __func__, run_mode); + self->mode = DEBUG_TRANSVR_INT_VAL; + return -1; + } + self->eeprom_map_p = map_p; + self->ioexp_obj_p = ioexp_obj_p; + self->ioexp_virt_offset = ioexp_virt_offset; + self->chan_id = chan_id; + self->layout = transvr_type; + self->type = transvr_type; + self->chipset_type = chipset_type; + self->state = STATE_TRANSVR_NEW; + self->info = STATE_TRANSVR_NEW; + self->auto_tx_disable = VAL_TRANSVR_FUNCTION_DISABLE; + strncpy(self->swp_name, swp_name, 32); + mutex_init(&self->lock); + return 0; +} + + + +static int +setup_i2c_client(struct transvr_obj_s *self){ + + struct i2c_adapter *adap = NULL; + struct i2c_client *client = NULL; + char err_msg[64] = DEBUG_TRANSVR_STR_VAL; + + adap = i2c_get_adapter(self->chan_id); + if(!adap){ + snprintf(err_msg, sizeof(err_msg), + "can not get adap:%d", self->chan_id); + goto err_setup_i2c_client; + } + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client){ + snprintf(err_msg, sizeof(err_msg), + "can not kzalloc client:%d", self->chan_id); + goto err_setup_i2c_client; + } + client->adapter = adap; + self->i2c_client_p = client; + self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; + return 0; + +err_setup_i2c_client: + SWPS_ERR("%s: %s\n", __func__, err_msg); + return ERR_TRANSVR_UNEXCPT; +} + + +struct transvr_obj_s * +create_transvr_obj(char *swp_name, + int chan_id, + struct ioexp_obj_s *ioexp_obj_p, + int ioexp_virt_offset, + int transvr_type, + int chipset_type, + int run_mode){ + + struct transvr_obj_s *result_p; + struct eeprom_map_s *map_p; + char err_msg[64] = DEBUG_TRANSVR_STR_VAL; + + /* Allocate transceiver object */ + map_p = get_eeprom_map(transvr_type); + if (!map_p){ + snprintf(err_msg, sizeof(err_msg), + "Invalid transvr_type:%d", transvr_type); + goto err_create_transvr_fail; + } + result_p = kzalloc(sizeof(*result_p), GFP_KERNEL); + if (!result_p){ + snprintf(err_msg, sizeof(err_msg), "kzalloc fail"); + goto err_create_transvr_fail; + } + /* Prepare static size attributes */ + if (setup_transvr_ssize_attr(swp_name, + result_p, + map_p, + ioexp_obj_p, + ioexp_virt_offset, + transvr_type, + chipset_type, + chan_id, + run_mode) < 0){ + goto err_create_transvr_sattr_fail; + } + + /* Prepare call back functions of object */ + if (setup_transvr_private_cb(result_p, transvr_type) < 0){ + goto err_create_transvr_sattr_fail; + } + /* Prepare i2c client object */ + if (setup_i2c_client(result_p) < 0){ + goto err_create_transvr_sattr_fail; + } + return result_p; +err_create_transvr_sattr_fail: + kfree(result_p); +err_create_transvr_fail: + SWPS_ERR("%s: %s :%d :%d :%d\n", + __func__, err_msg, chan_id, ioexp_virt_offset, transvr_type); + return NULL; +} + + +static int +_reload_transvr_obj(struct transvr_obj_s *self, + int new_type){ + + struct eeprom_map_s *new_map_p; + struct eeprom_map_s *old_map_p = self->eeprom_map_p; + struct i2c_client *old_i2c_p = self->i2c_client_p; + int old_type = self->type; + + /* Change state to STATE_TRANSVR_INIT */ + self->state = STATE_TRANSVR_INIT; + self->type = new_type; + /* Replace EEPROME map */ + new_map_p = get_eeprom_map(new_type); + if (!new_map_p){ + goto err_private_reload_func_1; + } + self->eeprom_map_p = new_map_p; + /* Reload i2c client */ + if (setup_i2c_client(self) < 0){ + goto err_private_reload_func_2; + } + if (setup_transvr_private_cb(self, new_type) < 0){ + goto err_private_reload_func_3; + } + kfree(old_i2c_p); + return 0; + +err_private_reload_func_3: + SWPS_INFO("%s: init() fail!\n", __func__); + kfree(old_i2c_p); + self->state = STATE_TRANSVR_UNEXCEPTED; + self->type = TRANSVR_TYPE_ERROR; + return -2; + +err_private_reload_func_2: + self->eeprom_map_p = old_map_p; + self->i2c_client_p = old_i2c_p; +err_private_reload_func_1: + self->state = STATE_TRANSVR_UNEXCEPTED; + self->type = old_type; + SWPS_INFO("%s fail! :0x%02x\n", __func__, new_type); + return -1; +} + + +static int +reload_transvr_obj(struct transvr_obj_s *self, + int new_type){ + + int result_val = ERR_TRANSVR_UNEXCPT; + + /* Reload phase */ + result_val = _reload_transvr_obj(self, new_type); + if (result_val < 0){ + SWPS_INFO("%s: reload phase fail! :%d\n", + __func__, result_val); + return EVENT_TRANSVR_RELOAD_FAIL; + } + /* Initial phase */ + result_val = _transvr_init_handler(self); + if (result_val < 0){ + SWPS_INFO("%s: initial phase fail! :%d\n", + __func__, result_val); + } + return result_val; +} + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.h b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.h new file mode 100644 index 000000000000..0e79f0b9027f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/modules/transceiver.h @@ -0,0 +1,168 @@ +#ifndef TRANSCEIVER_H +#define TRANSCEIVER_H + +#include + +/* Transceiver type define */ +#define TRANSVR_TYPE_UNKNOW_1 (0x00) +#define TRANSVR_TYPE_UNKNOW_2 (0xff) +#define TRANSVR_TYPE_SFP (0x03) /* Define for SFP, SFP+, SFP28 */ +#define TRANSVR_TYPE_QSFP (0x0c) +#define TRANSVR_TYPE_QSFP_PLUS (0x0d) +#define TRANSVR_TYPE_QSFP_28 (0x11) +#define TRANSVR_TYPE_UNPLUGGED (0xfa) /* Define for ERROR handle */ +#define TRANSVR_TYPE_FAKE (0xfc) /* Define for ERROR handle */ +#define TRANSVR_TYPE_INCONSISTENT (0xfd) /* Define for ERROR handle */ +#define TRANSVR_TYPE_ERROR (0xfe) /* Define for ERROR handle */ + +/* Transceiver mode define */ +#define TRANSVR_MODE_DIRECT (21000) + +/* Transceiver state define + * [Note] + * 1. State is used to represent the state of "Transceiver" and "Object". + * 2. State for different target has different means. The description as following: + */ +#define STATE_TRANSVR_CONNECTED (0) /* [Transvr]:Be plugged in. [Obj]:Link up, and work normally. */ +#define STATE_TRANSVR_NEW (-100) /* [Transvr]:(Not used) [Obj]:Create */ +#define STATE_TRANSVR_INIT (-101) /* [Transvr]:Be plugged in. [Obj]:Link up, and in initial process. */ +#define STATE_TRANSVR_ISOLATED (-102) /* [Transvr]:Be plugged in. [Obj]:Isolate, and not provide service. */ +#define STATE_TRANSVR_SWAPPED (-200) /* [Transvr]:Be plugged in. [Obj]:(Not used) */ +#define STATE_TRANSVR_DISCONNECTED (-300) /* [Transvr]:Un-plugged. [Obj]:Link down, and not provide service. */ +#define STATE_TRANSVR_UNEXCEPTED (-901) /* [Transvr]:Any [Obj]:Any, and not in expect case. */ + +/* Event for task handling */ +#define EVENT_TRANSVR_TASK_WAIT (2101) +#define EVENT_TRANSVR_TASK_DONE (0) +#define EVENT_TRANSVR_TASK_FAIL (-2101) +/* Event for initial handling */ +#define EVENT_TRANSVR_INIT_UP (2201) +#define EVENT_TRANSVR_INIT_DOWN (1) +#define EVENT_TRANSVR_INIT_REINIT (-2201) +#define EVENT_TRANSVR_INIT_FAIL (-2202) +/* Event for others */ +#define EVENT_TRANSVR_RELOAD_FAIL (-2301) +#define EVENT_TRANSVR_EXCEP_INIT (-2401) +#define EVENT_TRANSVR_EXCEP_UP (-2402) +#define EVENT_TRANSVR_EXCEP_DOWN (-2403) +#define EVENT_TRANSVR_EXCEP_SWAP (-2404) +#define EVENT_TRANSVR_EXCEP_EXCEP (-2405) +#define EVENT_TRANSVR_EXCEP_ISOLATED (-2406) +#define EVENT_TRANSVR_I2C_CRASH (-2501) + +/* Transceiver error code define */ +#define ERR_TRANSVR_UNINIT (-201) +#define ERR_TRANSVR_UNPLUGGED (-202) +#define ERR_TRANSVR_ABNORMAL (-203) +#define ERR_TRANSVR_NOSTATE (-204) +#define ERR_TRANSVR_NOTSUPPORT (-205) +#define ERR_TRANSVR_BADINPUT (-206) +#define ERR_TRANSVR_UPDATE_FAIL (-207) +#define ERR_TRANSVR_RELOAD_FAIL (-208) +#define ERR_TRANSVR_INIT_FAIL (-209) +#define ERR_TRANSVR_UNDEFINED (-210) +#define ERR_TRANSVR_TASK_FAIL (-211) +#define ERR_TRANSVR_TASK_BUSY (-212) +#define ERR_TRANSVR_FUNC_DISABLE (-214) +#define ERR_TRANSVR_I2C_CRASH (-297) +#define ERR_TRNASVR_BE_ISOLATED (-298) +#define ERR_TRANSVR_UNEXCPT (-299) + +/* For debug */ +#define DEBUG_TRANSVR_INT_VAL (-99) +#define DEBUG_TRANSVR_HEX_VAL (0xfe) +#define DEBUG_TRANSVR_STR_VAL "ERROR" + +/* For system internal */ +#define VAL_TRANSVR_COMID_ARREESS (0x50) +#define VAL_TRANSVR_COMID_OFFSET (0x00) +#define VAL_TRANSVR_8472_READY_ADDR (0x51) +#define VAL_TRANSVR_8472_READY_PAGE (-1) +#define VAL_TRANSVR_8472_READY_OFFSET (110) +#define VAL_TRANSVR_8472_READY_BIT (0) +#define VAL_TRANSVR_8472_READY_VALUE (0) +#define VAL_TRANSVR_8472_READY_ABNORMAL (0xff) +#define VAL_TRANSVR_8436_READY_ADDR (0x50) +#define VAL_TRANSVR_8436_READY_PAGE (-1) +#define VAL_TRANSVR_8436_READY_OFFSET (2) +#define VAL_TRANSVR_8436_READY_BIT (0) +#define VAL_TRANSVR_8436_READY_VALUE (0) +#define VAL_TRANSVR_8436_READY_ABNORMAL (0xff) +#define VAL_TRANSVR_8436_PWD_ADDR (0x50) +#define VAL_TRANSVR_8436_PWD_PAGE (-1) +#define VAL_TRANSVR_8436_PWD_OFFSET (123) +#define VAL_TRANSVR_PAGE_FREE (-99) +#define VAL_TRANSVR_PAGE_SELECT_OFFSET (127) +#define VAL_TRANSVR_PAGE_SELECT_DELAY (5) +#define VAL_TRANSVR_TASK_RETRY_FOREVER (-999) +#define VAL_TRANSVR_FUNCTION_DISABLE (-1) +#define STR_TRANSVR_SFP "SFP" +#define STR_TRANSVR_QSFP "QSFP" +#define STR_TRANSVR_QSFP_PLUS "QSFP+" +#define STR_TRANSVR_QSFP28 "QSFP28" + +/* BCM chip type define */ +#define BCM_CHIP_TYPE_TOMAHAWK (31002) /* Redwood, Cypress */ + +/* Info from transceiver EEPROM */ +struct eeprom_map_s { + int addr_rx_los; int page_rx_los; int offset_rx_los; int length_rx_los; + int addr_tx_disable; int page_tx_disable; int offset_tx_disable; int length_tx_disable; + int addr_tx_fault; int page_tx_fault; int offset_tx_fault; int length_tx_fault; +}; + +/* Class of transceiver object */ +struct transvr_obj_s { + /* ========== Object private property ========== + */ + struct device *transvr_dev_p; + struct eeprom_map_s *eeprom_map_p; + struct i2c_client *i2c_client_p; + struct ioexp_obj_s *ioexp_obj_p; + struct mutex lock; + char swp_name[32]; + int auto_tx_disable; + int chan_id; + int chipset_type; + int curr_page; + int info; + int ioexp_virt_offset; + int lane_id[8]; + int layout; + int mode; + int retry; + int state; + int temp; + int type; + + /* ========== Object private functions ========== + */ + int (*init)(struct transvr_obj_s *self); + int (*update_all)(struct transvr_obj_s *self, int show_err); + int (*fsm_4_direct)(struct transvr_obj_s* self, char *caller_name); +}; + + +/* For AVL Mapping */ +struct transvr_avl_s { + char vendor_name[32]; + char vendor_pn[32]; + int (*init)(struct transvr_obj_s *self); +}; + +struct transvr_obj_s * +create_transvr_obj(char *swp_name, + int chan_id, + struct ioexp_obj_s *ioexp_obj_p, + int ioexp_virt_offset, + int transvr_type, + int chipset_type, + int run_mode); + +void alarm_msg_2_user(struct transvr_obj_s *self, char *emsg); + +#endif /* TRANSCEIVER_H */ + + + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/utils/inventec_d7054_util.py b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/utils/inventec_d7054_util.py new file mode 100755 index 000000000000..7fbb707f4187 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/d7054q28b/utils/inventec_d7054_util.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Inventec, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +from collections import namedtuple + +DEBUG = False +args = [] +FORCE = 0 +i2c_prefix = '/sys/bus/i2c/devices/' + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + install() + elif arg == 'clean': + uninstall() + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_log(txt): + if DEBUG == True: + print "[D7032]"+txt + return + +def exec_cmd(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + show_log (cmd +"with result:" + str(status)) + show_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +instantiate =[ +#'echo pca9548 0x71> /sys/bus/i2c/devices/i2c-0/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-2/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-3/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-4/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-5/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-6/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-7/new_device', +#'echo pca9548 0x72> /sys/bus/i2c/devices/i2c-0/i2c-8/new_device', +'echo inv_eeprom 0x53 > /sys/bus/i2c/devices/i2c-0/new_device'] +#'echo inv_psoc 0x66> /sys/bus/i2c/devices/i2c-0/new_device', +#'echo inv_cpld 0x55> /sys/bus/i2c/devices/i2c-0/new_device'] + +drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-mux', +'i2c-mux-pca954x', +'i2c-dev', +'inv_eeprom', +'inv_platform', +'inv_psoc', +'inv_cpld', +'swps'] + + + +def system_install(): + global FORCE + + #install drivers + for i in range(0,len(drivers)): + status, output = exec_cmd("modprobe "+drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + + #instantiate devices + for i in range(0,len(instantiate)): + #time.sleep(1) + status, output = exec_cmd(instantiate[i], 1) + if status: + print output + if FORCE == 0: + return status + + for i in range(10,18): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-2/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(18,26): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-3/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(26,34): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-4/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(34,42): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-5/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(42,50): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-6/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(50,58): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-7/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + for i in range(58,64): + status, output =exec_cmd("echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-8/i2c-"+str(i)+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + return + + +def system_ready(): + if not device_found(): + return False + return True + +def install(): + if not device_found(): + print "No device, installing...." + status = system_install() + if status: + if FORCE == 0: + return status + else: + print " D7032 devices detected...." + return + +def uninstall(): + global FORCE + #uninstall drivers + for i in range(len(drivers)-1,-1,-1): + status, output = exec_cmd("rmmod "+drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + return + +def device_found(): + ret1, log = exec_cmd("ls "+i2c_prefix+"*0072", 0) + ret2, log = exec_cmd("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() + + diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/changelog b/platform/broadcom/sonic-platform-modules-inventec/debian/changelog index 3598fc1d40d1..9d33aa418ef5 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/changelog +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/changelog @@ -1,3 +1,8 @@ +sonic-inventec-platform-modules (1.1.0) unstable; urgency=low + * Add support for Inventec d7054 + + -- developer Tue, 18 Jul 2017 16:30:45 +0800 + sonic-inventec-platform-modules (1.0.0) unstable; urgency=low * Add support for Inventec d7032 diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/control b/platform/broadcom/sonic-platform-modules-inventec/debian/control index 328de48c097b..d570e777de98 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/control +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/control @@ -10,3 +10,8 @@ Architecture: amd64 Depends: linux-image-3.16.0-4-amd64 Description: kernel modules for platform devices such as fan, led +Package: platform-modules-d7054q28b +Architecture: amd64 +Depends: linux-image-3.16.0-4-amd64 +Description: kernel modules for platform devices such as fan, led + diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.init b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.init index 9b9683a4eb2a..5df1bb444123 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.init +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.init @@ -15,43 +15,14 @@ case "$1" in start) echo -n "Setting up board... " - depmod -a - modprobe inv_platform - modprobe inv_psoc - modprobe inv_cpld - - /usr/local/bin/onie-syseeprom -S /tmp/eeprom - # Attach 32 instances of EEPROM driver QSFP ports on IO module 1 - #eeprom can dump data using below command - for ((i=22;i<=29;i++)); - do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-4/i2c-$i/new_device - done - - for ((i=30;i<=37;i++)); - do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-5/i2c-$i/new_device - done - - for ((i=6;i<=13;i++)); - do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-2/i2c-$i/new_device - done - - for ((i=14;i<=21;i++)); - do - echo sff8436 0x50 > /sys/bus/i2c/devices/i2c-0/i2c-3/i2c-$i/new_device - done - + depmod -a + /usr/local/bin/inventec_d7032_util.py -f install echo "done." ;; stop) - - rmmod inv_cpld - rmmod inv_psoc - rmmod inv_platform - + + /usr/local/bin/inventec_d7032_util.py -f clean echo "done." ;; diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.install b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.install index 996d5e36b781..0864a728ea79 100644 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.install +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.install @@ -1 +1 @@ -d7032q28b/conf/d7032q28b-modules.conf etc/modules-load.d +d7032q28b/utils/inventec_d7032_util.py usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.upstart b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.upstart new file mode 100644 index 000000000000..cbb96a664f6a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7032q28b.upstart @@ -0,0 +1,5 @@ +description "SONiC platform service" + +respawn + +exec /usr/local/bin/inventec_d7032_util.py -f install diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.init b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.init new file mode 100644 index 000000000000..20341f8527e5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.init @@ -0,0 +1,40 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup Inventec d7054q28b board. +### END INIT INFO + +case "$1" in +start) + echo -n "Setting up board... " + + depmod -a + /usr/local/bin/inventec_d7054_util.py -f install + echo "done." + ;; + +stop) + + /usr/local/bin/inventec_d7054_util.py -f clean + echo "done." + + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-d7054q28b.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install new file mode 100644 index 000000000000..42bf3f23c809 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.install @@ -0,0 +1 @@ +d7054q28b/utils/inventec_d7054_util.py usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.upstart b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.upstart new file mode 100644 index 000000000000..9f185f47b623 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/platform-modules-d7054q28b.upstart @@ -0,0 +1,5 @@ +description "SONiC platform service" + +respawn + +exec /usr/local/bin/inventec_d7054_util.py -f install diff --git a/platform/broadcom/sonic-platform-modules-inventec/debian/rules b/platform/broadcom/sonic-platform-modules-inventec/debian/rules index 166a3426b2ba..6ead4c21de50 100755 --- a/platform/broadcom/sonic-platform-modules-inventec/debian/rules +++ b/platform/broadcom/sonic-platform-modules-inventec/debian/rules @@ -14,7 +14,7 @@ export INSTALL_MOD_DIR:=extra KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= d7032q28b +MODULE_DIRS:= d7032q28b d7054q28b %: dh $@ @@ -31,7 +31,8 @@ override_dh_auto_install: cp $(MOD_SRC_DIR)/$${mod}/modules/*.ko \ debian/platform-modules-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ dh_installdirs -pplatform-modules-$${mod} usr/local/bin; \ - cp -r $(MOD_SRC_DIR)/$${mod}/utils/onie-syseeprom debian/platform-modules-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/utils/* \ + debian/platform-modules-$${mod}/usr/local/bin; \ done) override_dh_usrlocal: diff --git a/platform/vs/README.md b/platform/vs/README.md new file mode 100644 index 000000000000..52f3f30eac6d --- /dev/null +++ b/platform/vs/README.md @@ -0,0 +1,75 @@ +HOWTO Use Virtual Switch + + +1. Create a docker with 32 front panel port + +``` +$ docker run -id --name sw debian bash +$ sudo ./create_vnet.sh sw +$ ip netns list +sw-srv31 (id: 37) +sw-srv30 (id: 35) +sw-srv29 (id: 34) +sw-srv28 (id: 33) +sw-srv27 (id: 32) +sw-srv26 (id: 31) +sw-srv25 (id: 30) +sw-srv24 (id: 29) +sw-srv23 (id: 28) +sw-srv22 (id: 27) +sw-srv21 (id: 26) +sw-srv20 (id: 25) +sw-srv19 (id: 24) +sw-srv18 (id: 23) +sw-srv17 (id: 22) +sw-srv16 (id: 21) +sw-srv15 (id: 20) +sw-srv14 (id: 19) +sw-srv13 (id: 18) +sw-srv12 (id: 17) +sw-srv11 (id: 16) +sw-srv10 (id: 15) +sw-srv9 (id: 14) +sw-srv8 (id: 13) +sw-srv7 (id: 12) +sw-srv6 (id: 11) +sw-srv5 (id: 10) +sw-srv4 (id: 9) +sw-srv3 (id: 8) +sw-srv2 (id: 7) +sw-srv1 (id: 6) +sw-srv0 (id: 5) +``` + +2. Start sonic virtual switch docker + +``` +$ docker run --privileged --network container:sw -d docker-sonic-vs +``` + +3. Setup IP in the virtual switch docker + +``` +$ docker exec -it vs bash +root@2e9b5c2dc2a2:/# ifconfig Ethernet0 10.0.0.0/31 up +root@2e9b5c2dc2a2:/# ifconfig Ethernet4 10.0.0.2/31 up +``` + +4. Setup IP in the server network namespace + +``` +$ sudo ip netns exec sw-srv0 ifconfig eth0 10.0.0.1/31 +$ sudo ip netns exec sw-srv0 ip route add default via 10.0.0.0 +$ sudo ip netns exec sw-srv1 ifconfig eth0 10.0.0.3/31 +$ sudo ip netns exec sw-srv1 ip route add default via 10.0.0.2 +``` + +5. Ping from sw-srv0 to sw-srv1 + +``` +$ sudo ip netns exec sw-srv0 ping 10.0.0.3 +PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data. +64 bytes from 10.0.0.3: icmp_seq=1 ttl=63 time=0.137 ms +64 bytes from 10.0.0.3: icmp_seq=2 ttl=63 time=0.148 ms +64 bytes from 10.0.0.3: icmp_seq=3 ttl=63 time=0.149 ms +``` diff --git a/platform/vs/create_vnet.sh b/platform/vs/create_vnet.sh new file mode 100755 index 000000000000..857a61b52cc5 --- /dev/null +++ b/platform/vs/create_vnet.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +SWNAME=$1 + +pid=$(docker inspect --format '{{.State.Pid}}' $SWNAME) + +echo Seting up servers + +SERVERS=31 + +for srv in `seq 0 $SERVERS`; do + + SRV="$SWNAME-srv$srv" + + NSS="ip netns exec $SRV" + + ip netns add $SRV + + $NSS ip addr add 127.0.0.1/8 dev lo + $NSS ip addr add ::1/128 dev lo + $NSS ip link set dev lo up + + # add virtual link between neighbor and the virtual switch docker + + IF="vEthernet$((srv*4))" + + ip link add ${SRV}eth0 type veth peer name $IF + ip link set ${SRV}eth0 netns $SRV + ip link set $IF netns ${pid} + + echo "Bring ${SRV}eth0 up" + $NSS ip link set dev ${SRV}eth0 name eth0 + $NSS ip link set dev eth0 up + + echo "Bring $IF up in the virtual switch docker" + nsenter -t $pid -n ip link set dev $IF up + +done diff --git a/platform/vs/docker-sonic-vs.mk b/platform/vs/docker-sonic-vs.mk new file mode 100644 index 000000000000..e9d23db493db --- /dev/null +++ b/platform/vs/docker-sonic-vs.mk @@ -0,0 +1,16 @@ +# docker image for virtual switch based sonic docker image + +DOCKER_SONIC_VS = docker-sonic-vs.gz +$(DOCKER_SONIC_VS)_PATH = $(PLATFORM_PATH)/docker-sonic-vs +$(DOCKER_SONIC_VS)_DEPENDS += $(SWSS) $(SYNCD_VS) $(REDIS_SERVER) $(REDIS_TOOLS) $(PYTHON_SWSSCOMMON) $(LIBTEAMDCT) $(LIBTEAM_UTILS) $(SONIC_DEVICE_DATA) + +ifeq ($(SONIC_ROUTING_STACK), quagga) +$(DOCKER_SONIC_VS)_DEPENDS += $(QUAGGA) +else ifeq ($(SONIC_ROUTING_STACK), frr) +$(DOCKER_SONIC_VS)_DEPENDS += $(FRR) +else +$(DOCKER_SONIC_VS)_DEPENDS += $(GOBGP) +endif + +$(DOCKER_SONIC_VS)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE) +SONIC_DOCKER_IMAGES += $(DOCKER_SONIC_VS) diff --git a/platform/vs/docker-sonic-vs/50-default.conf b/platform/vs/docker-sonic-vs/50-default.conf new file mode 100644 index 000000000000..d672d83af789 --- /dev/null +++ b/platform/vs/docker-sonic-vs/50-default.conf @@ -0,0 +1,68 @@ +# Default rules for rsyslog. +# +# For more information see rsyslog.conf(5) and /etc/rsyslog.conf + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +#daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +#lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +#user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +#mail.info -/var/log/mail.info +#mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +#*.=debug;\ +# auth,authpriv.none;\ +# news.none;mail.none -/var/log/debug +#*.=info;*.=notice;*.=warn;\ +# auth,authpriv.none;\ +# cron,daemon.none;\ +# mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg :omusrmsg:* + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole diff --git a/platform/vs/docker-sonic-vs/Dockerfile.j2 b/platform/vs/docker-sonic-vs/Dockerfile.j2 new file mode 100644 index 000000000000..32b91e8cf44a --- /dev/null +++ b/platform/vs/docker-sonic-vs/Dockerfile.j2 @@ -0,0 +1,57 @@ +FROM docker-config-engine + +## Make apt-get non-interactive +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update + +RUN apt-get install -y net-tools \ + ethtool \ + tcpdump \ + ifupdown \ + bridge-utils \ + python-ply \ + libqt5core5a \ + libqt5network5 \ + libboost-program-options1.55.0 \ + libboost-system1.55.0 \ + libboost-thread1.55.0 \ + libgmp10 \ + libjudydebian1 \ + libnanomsg0 \ + libdaemon0 \ + libjansson4 \ + libjemalloc1 \ + openssh-client \ + openssh-server \ + libc-ares2 \ + iproute \ + libpython2.7 + +COPY \ +{% for deb in docker_sonic_vs_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +RUN dpkg -i \ +{% for deb in docker_sonic_vs_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor %} + +## Clean up +RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y +RUN rm -rf /debs + +RUN sed -ri 's/^daemonize yes$/daemonize no/; \ + s/^logfile .*$/logfile ""/; \ + s/^# syslog-enabled no$/syslog-enabled no/; \ + s/^# unixsocket/unixsocket/ \ + ' /etc/redis/redis.conf + +COPY ["50-default.conf", "/etc/rsyslog.d/"] +COPY ["start.sh", "orchagent.sh", "/usr/bin/"] +COPY ["brcm.profile.ini", "/usr/share/sonic/device/vswitch/"] +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] + +ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/platform/vs/docker-sonic-vs/brcm.profile.ini b/platform/vs/docker-sonic-vs/brcm.profile.ini new file mode 100644 index 000000000000..23cd24c73a35 --- /dev/null +++ b/platform/vs/docker-sonic-vs/brcm.profile.ini @@ -0,0 +1,4 @@ +SAI_WARM_BOOT_READ_FILE=/var/cache/sai_warmboot.bin +SAI_WARM_BOOT_WRITE_FILE=/var/cache/sai_warmboot.bin +SAI_VS_SWITCH_TYPE=SAI_VS_SWITCH_TYPE_BCM56850 +SAI_VS_HOSTIF_USE_TAP_DEVICE=true diff --git a/platform/vs/docker-sonic-vs/orchagent.sh b/platform/vs/docker-sonic-vs/orchagent.sh new file mode 100755 index 000000000000..7e250dfa20e9 --- /dev/null +++ b/platform/vs/docker-sonic-vs/orchagent.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +MAC_ADDRESS=`ip link show eth0 | grep ether | awk '{print $2}'` + +# Create a folder for SsWW record files +mkdir -p /var/log/swss +ORCHAGENT_ARGS="-d /var/log/swss " + +# Set orchagent pop batch size to 8192 +ORCHAGENT_ARGS+="-b 8192 " + +# Set mac address +ORCHAGENT_ARGS+="-m $MAC_ADDRESS" + +exec /usr/bin/orchagent ${ORCHAGENT_ARGS} diff --git a/platform/vs/docker-sonic-vs/start.sh b/platform/vs/docker-sonic-vs/start.sh new file mode 100755 index 000000000000..07d0fb7a0426 --- /dev/null +++ b/platform/vs/docker-sonic-vs/start.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +mkdir -p /etc/swss/config.d/ + +# sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json +# sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/mirror.json.j2 > /etc/swss/config.d/mirror.json +# sonic-cfggen -m /etc/sonic/minigraph.xml -d -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json + +# export platform=`sonic-cfggen -v platform` + +rm -f /var/run/rsyslogd.pid + +supervisorctl start rsyslogd + +mkdir -p /var/run/redis + +supervisorctl start redis-server + +supervisorctl start syncd + +supervisorctl start orchagent + +supervisorctl start portsyncd + +supervisorctl start intfsyncd + +supervisorctl start neighsyncd + +supervisorctl start teamsyncd + +# Start arp_update when VLAN exists +# VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'` +# if [ "$VLAN" != "" ]; then +# supervisorctl start arp_update +# fi diff --git a/platform/vs/docker-sonic-vs/supervisord.conf b/platform/vs/docker-sonic-vs/supervisord.conf new file mode 100644 index 000000000000..c6fefef1415a --- /dev/null +++ b/platform/vs/docker-sonic-vs/supervisord.conf @@ -0,0 +1,76 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[program:start.sh] +command=/usr/bin/start.sh +priority=1 +autostart=true +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n +priority=2 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:redis-server] +command=/usr/bin/redis-server /etc/redis/redis.conf +priority=3 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:syncd] +command=/usr/bin/syncd -uN -p /usr/share/sonic/device/vswitch/brcm.profile.ini +priority=4 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:orchagent] +command=/usr/bin/orchagent.sh +priority=5 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:portsyncd] +command=/usr/bin/portsyncd -p /usr/share/sonic/device/x86_64-dell_s6000_s1220-r0/Force10-S6000/port_config.ini +priority=6 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:intfsyncd] +command=/usr/bin/intfsyncd +priority=7 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:neighsyncd] +command=/usr/bin/neighsyncd +priority=8 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +[program:teamsyncd] +command=/usr/bin/teamsyncd +priority=9 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog diff --git a/platform/vs/rules.mk b/platform/vs/rules.mk new file mode 100644 index 000000000000..28dba54a5a4e --- /dev/null +++ b/platform/vs/rules.mk @@ -0,0 +1,4 @@ +include $(PLATFORM_PATH)/syncd-vs.mk +include $(PLATFORM_PATH)/docker-sonic-vs.mk + +SONIC_ALL += $(DOCKER_SONIC_VS) diff --git a/platform/vs/syncd-vs.mk b/platform/vs/syncd-vs.mk new file mode 100644 index 000000000000..49035aaf958b --- /dev/null +++ b/platform/vs/syncd-vs.mk @@ -0,0 +1,13 @@ +$(LIBSAIREDIS)_DPKG_TARGET = binary-syncd-vs + +# inject libsaivs and libsaivs_dev to swss build dependency +$(SWSS)_DEPENDS += $(LIBSAIVS) $(LIBSAIVS_DEV) + +SYNCD_VS = syncd-vs_1.0.0_amd64.deb +$(SYNCD_VS)_RDEPENDS += $(LIBSAIREDIS) $(LIBSAIMETADATA) $(LIBSAIVS) +$(eval $(call add_derived_package,$(LIBSAIREDIS),$(SYNCD_VS))) + +SYNCD_VS_DBG = syncd-vs-dbg_1.0.0_amd64.deb +$(SYNCD_VS_DBG)_DEPENDS += $(SYNCD_VS) +$(SYNCD_VS_DBG)_RDEPENDS += $(SYNCD_VS) +$(eval $(call add_derived_package,$(LIBSAIREDIS),$(SYNCD_VS_DBG))) diff --git a/rules/sairedis.mk b/rules/sairedis.mk index 4a62954f4d1c..760d75c5a611 100644 --- a/rules/sairedis.mk +++ b/rules/sairedis.mk @@ -9,6 +9,13 @@ SONIC_DPKG_DEBS += $(LIBSAIREDIS) LIBSAIREDIS_DEV = libsairedis-dev_1.0.0_amd64.deb $(eval $(call add_derived_package,$(LIBSAIREDIS),$(LIBSAIREDIS_DEV))) +LIBSAIVS = libsaivs_1.0.0_amd64.deb +$(eval $(call add_derived_package,$(LIBSAIREDIS),$(LIBSAIVS))) + +LIBSAIVS_DEV = libsaivs-dev_1.0.0_amd64.deb +$(eval $(call add_derived_package,$(LIBSAIREDIS),$(LIBSAIVS_DEV))) + +ifneq ($(CONFIGURED_PLATFORM),vs) SYNCD = syncd_1.0.0_amd64.deb $(SYNCD)_RDEPENDS += $(LIBSAIREDIS) $(LIBSAIMETADATA) $(eval $(call add_derived_package,$(LIBSAIREDIS),$(SYNCD))) @@ -16,6 +23,7 @@ $(eval $(call add_derived_package,$(LIBSAIREDIS),$(SYNCD))) SYNCD_RPC = syncd-rpc_1.0.0_amd64.deb $(SYNCD_RPC)_RDEPENDS += $(LIBSAIREDIS) $(LIBSAIMETADATA) $(eval $(call add_derived_package,$(LIBSAIREDIS),$(SYNCD_RPC))) +endif LIBSAIMETADATA = libsaimetadata_1.0.0_amd64.deb $(eval $(call add_derived_package,$(LIBSAIREDIS),$(LIBSAIMETADATA))) @@ -29,6 +37,12 @@ $(LIBSAIREDIS_DBG)_DEPENDS += $(LIBSAIREDIS) $(LIBSAIREDIS_DBG)_RDEPENDS += $(LIBSAIREDIS) $(eval $(call add_derived_package,$(LIBSAIREDIS),$(LIBSAIREDIS_DBG))) +LIBSAIVS_DBG = libsaivs-dbg_1.0.0_amd64.deb +$(LIBSAIVS_DBG)_DEPENDS += $(LIBSAIVS) +$(LIBSAIVS_DBG)_RDEPENDS += $(LIBSAIVS) +$(eval $(call add_derived_package,$(LIBSAIREDIS),$(LIBSAIVS_DBG))) + +ifneq ($(CONFIGURED_PLATFORM),vs) SYNCD_DBG = syncd-dbg_1.0.0_amd64.deb $(SYNCD_DBG)_DEPENDS += $(SYNCD) $(SYNCD_DBG)_RDEPENDS += $(SYNCD) @@ -38,6 +52,7 @@ SYNCD_RPC_DBG = syncd-rpc-dbg_1.0.0_amd64.deb $(SYNCD_RPC_DBG)_DEPENDS += $(SYNCD_RPC) $(SYNCD_RPC_DBG)_RDEPENDS += $(SYNCD_RPC) $(eval $(call add_derived_package,$(LIBSAIREDIS),$(SYNCD_RPC_DBG))) +endif LIBSAIMETADATA_DBG = libsaimetadata-dbg_1.0.0_amd64.deb $(LIBSAIMETADATA_DBG)_DEPENDS += $(LIBSAIMETADATA) diff --git a/rules/sonic-utilities.mk b/rules/sonic-utilities.mk index 9349813f5c4e..7a935ba70ede 100644 --- a/rules/sonic-utilities.mk +++ b/rules/sonic-utilities.mk @@ -2,4 +2,5 @@ SONIC_UTILS = python-sonic-utilities_1.1-1_all.deb $(SONIC_UTILS)_SRC_PATH = $(SRC_PATH)/sonic-utilities +$(SONIC_UTILS)_WHEEL_DEPENDS = $(SONIC_CONFIG_ENGINE) SONIC_PYTHON_STDEB_DEBS += $(SONIC_UTILS) diff --git a/rules/swss-common.mk b/rules/swss-common.mk index a4ccdafc2376..623410d4cdab 100644 --- a/rules/swss-common.mk +++ b/rules/swss-common.mk @@ -12,6 +12,9 @@ SONIC_DPKG_DEBS += $(LIBSWSSCOMMON) LIBSWSSCOMMON_DEV = libswsscommon-dev_1.0.0_amd64.deb $(eval $(call add_derived_package,$(LIBSWSSCOMMON),$(LIBSWSSCOMMON_DEV))) +PYTHON_SWSSCOMMON = python-swsscommon_1.0.0_amd64.deb +$(eval $(call add_derived_package,$(LIBSWSSCOMMON),$(PYTHON_SWSSCOMMON))) + LIBSWSSCOMMON_DBG = libswsscommon-dbg_1.0.0_amd64.deb $(LIBSWSSCOMMON_DBG)_DEPENDS += $(LIBSWSSCOMMON) $(LIBSWSSCOMMON_DBG)_RDEPENDS += $(LIBSWSSCOMMON) diff --git a/slave.mk b/slave.mk index c26e4932f05a..6f823cf98340 100644 --- a/slave.mk +++ b/slave.mk @@ -59,10 +59,6 @@ list : ## Include other rules ############################################################################### -ifeq ($(SONIC_ENABLE_SYNCD_RPC),y) -ENABLE_SYNCD_RPC = y -endif - include $(RULES_PATH)/config include $(RULES_PATH)/functions include $(RULES_PATH)/*.mk @@ -207,7 +203,10 @@ $(addprefix $(DEBS_PATH)/, $(SONIC_DPKG_DEBS)) : $(DEBS_PATH)/% : .platform $$(a # Build project pushd $($*_SRC_PATH) $(LOG) [ ! -f ./autogen.sh ] || ./autogen.sh $(LOG) - dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) $(LOG) + $(if $($*_DPKG_TARGET), + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --as-root -T$($*_DPKG_TARGET) $(LOG), + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) $(LOG) + ) popd $(LOG) # Clean up if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && quilt pop -a -f; popd; fi @@ -223,7 +222,8 @@ SONIC_TARGET_LIST += $(addprefix $(DEBS_PATH)/, $(SONIC_DPKG_DEBS)) # $(SOME_NEW_DEB)_SRC_PATH = $(SRC_PATH)/project_name # $(SOME_NEW_DEB)_DEPENDS = $(SOME_OTHER_DEB1) $(SOME_OTHER_DEB2) ... # SONIC_PYTHON_STDEB_DEBS += $(SOME_NEW_DEB) -$(addprefix $(DEBS_PATH)/, $(SONIC_PYTHON_STDEB_DEBS)) : $(DEBS_PATH)/% : .platform $$(addsuffix -install,$$(addprefix $(DEBS_PATH)/,$$($$*_DEPENDS))) +$(addprefix $(DEBS_PATH)/, $(SONIC_PYTHON_STDEB_DEBS)) : $(DEBS_PATH)/% : .platform $$(addsuffix -install,$$(addprefix $(DEBS_PATH)/,$$($$*_DEPENDS))) \ + $$(addsuffix -install,$$(addprefix $(PYTHON_WHEELS_PATH)/,$$($$*_WHEEL_DEPENDS))) $(HEADER) # Apply series of patches if exist if [ -f $($*_SRC_PATH).patch/series ]; then pushd $($*_SRC_PATH) && QUILT_PATCHES=../$(notdir $($*_SRC_PATH)).patch quilt push -a; popd; fi diff --git a/sonic-slave/Dockerfile b/sonic-slave/Dockerfile index f194bf604caa..603c3b6cb357 100644 --- a/sonic-slave/Dockerfile +++ b/sonic-slave/Dockerfile @@ -200,7 +200,9 @@ RUN apt-get update && apt-get install -y \ procmail \ # For gtest libgtest-dev \ - cmake + cmake \ +# For python-based swsscommon + swig3.0 # For linux build RUN apt-get -y build-dep linux @@ -223,6 +225,9 @@ RUN pip install j2cli # For sonic config engine testing RUN pip install pyangbind==0.5.10 +# For sonic utilities testing +RUN pip install click-default-group click natsort tabulate + # For supervisor build RUN pip install meld3 mock diff --git a/src/isc-dhcp/Makefile b/src/isc-dhcp/Makefile index 9cacd6cfe5e7..d2304876d1cf 100644 --- a/src/isc-dhcp/Makefile +++ b/src/isc-dhcp/Makefile @@ -10,7 +10,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : rm -rf ./isc-dhcp # Clone isc-dhcp repo - git clone git://anonscm.debian.org/pkg-dhcp/isc-dhcp.git + git clone https://anonscm.debian.org/cgit/pkg-dhcp/isc-dhcp.git pushd ./isc-dhcp git checkout -f debian/4.3.1-6 popd diff --git a/src/isc-dhcp/isc-dhcp-4.3.1_dhcrelay-custom-circuit_id-remote_id-and-bridge-iface-support.patch b/src/isc-dhcp/isc-dhcp-4.3.1_dhcrelay-custom-circuit_id-remote_id-and-bridge-iface-support.patch index 8d28751da63c..4dee30238acd 100644 --- a/src/isc-dhcp/isc-dhcp-4.3.1_dhcrelay-custom-circuit_id-remote_id-and-bridge-iface-support.patch +++ b/src/isc-dhcp/isc-dhcp-4.3.1_dhcrelay-custom-circuit_id-remote_id-and-bridge-iface-support.patch @@ -1,10 +1,10 @@ This patch adds the following functionality to dhcrelay in isc-dhcp v4.3.1-6: * Add customizable Circuit ID and Remote ID fields -* Support for obtaining name of physical interface of interfaces that are part of a bridge interface +* Support for obtaining name of physical interfaces that are part of a bridge interface diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c ---- a/isc-dhcp/relay/dhcrelay.c 2014-08-06 22:35:02.000000000 +0000 -+++ b/isc-dhcp/relay/dhcrelay.c 2017-06-08 21:39:53.856192546 +0000 +--- a/isc-dhcp/relay/dhcrelay.c 2017-10-03 01:46:19.811524700 +0000 ++++ b/isc-dhcp/relay/dhcrelay.c 2017-10-03 01:45:50.699524700 +0000 @@ -73,6 +73,8 @@ did not match any known circuit ID. */ int missing_circuit_id = 0; /* Circuit ID option in matching RAI option @@ -14,7 +14,33 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c int max_hop_count = 10; /* Maximum hop count */ #ifdef DHCPv6 -@@ -140,9 +142,19 @@ +@@ -120,6 +122,14 @@ + char *dhcrelay_sub_id = NULL; + #endif + ++struct interface_name_alias_tuple { ++ char if_name[IFNAMSIZ + 1]; ++ char if_alias[IFNAMSIZ + 1]; ++}; ++ ++static struct interface_name_alias_tuple *g_interface_name_alias_map = NULL; ++static size_t g_interface_name_alias_map_size = 0; ++ + static void do_relay4(struct interface_info *, struct dhcp_packet *, + unsigned int, unsigned int, struct iaddr, + struct hardware *); +@@ -132,6 +142,10 @@ + struct interface_info **, + struct dhcp_packet *, unsigned); + ++static int load_interface_alias_map(const char *port_alias_map_file_path); ++static int get_interface_alias_by_name(const char *if_name, char *if_alias_out); ++static void free_interface_alias_map(void); ++ + static const char copyright[] = + "Copyright 2004-2014 Internet Systems Consortium."; + static const char arr[] = "All rights reserved."; +@@ -140,28 +154,42 @@ static const char url[] = "For info, please visit https://www.isc.org/software/dhcp/"; @@ -23,7 +49,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c +"\n" \ +" %%%% A single %%\n" \ +" %%h Hostname of device\n" \ -+" %%p Name of interface that generated the request\n" \ ++" %%p Alias of interface that generated the request\n" \ +" %%P Hardware address of interface that generated the request\n" \ +" %%C Client hardware address\n" \ +" %%I DHCP relay agent IP Address\n" \ @@ -35,7 +61,13 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c " [-A ] [-c ] [-p ]\n" \ " [-pf ] [--no-pid]\n"\ " [-m append|replace|forward|discard]\n" \ -@@ -154,14 +166,15 @@ ++" [--name-alias-map-file ]\n" \ + " [-i interface0 [ ... -i interfaceN]\n" \ + " server0 [ ... serverN]\n\n" \ + " dhcrelay -6 [-d] [-q] [-I] [-c ] [-p ]\n" \ + " [-pf ] [--no-pid]\n" \ ++" [--name-alias-map-file ]\n" \ + " [-s ]\n" \ " -l lower0 [ ... -l lowerN]\n" \ " -u upper0 [ ... -u upperN]\n" \ " lower (client link): [address%%]interface[#index]\n" \ @@ -49,13 +81,14 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c +" [-A ] [-c ] [-p ]\n" \ +" [-pf ] [--no-pid]\n"\ " [-m append|replace|forward|discard]\n" \ ++" [--name-alias-map-file ]\n" \ " [-i interface0 [ ... -i interfaceN]\n" \ -" server0 [ ... serverN]\n\n" +" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE #endif static void usage() { -@@ -287,6 +300,15 @@ +@@ -287,6 +315,15 @@ local_family_set = 1; local_family = AF_INET; #endif @@ -71,7 +104,59 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c add_agent_options = 1; } else if (!strcmp(argv[i], "-A")) { #ifdef DHCPv6 -@@ -937,6 +959,166 @@ +@@ -383,6 +420,13 @@ + no_dhcrelay_pid = ISC_TRUE; + } else if (!strcmp(argv[i], "--no-pid")) { + no_pid_file = ISC_TRUE; ++ } else if (!strcmp(argv[i], "--name-alias-map-file")) { ++ if (++i == argc) ++ usage(); ++ if (load_interface_alias_map(argv[i]) != 0) ++ log_fatal("Failed to load interface name-alias map."); ++ path_dhcrelay_pid = argv[i]; ++ no_dhcrelay_pid = ISC_TRUE; + } else if (!strcmp(argv[i], "--version")) { + log_info("isc-dhcrelay-%s", PACKAGE_VERSION); + exit(0); +@@ -602,6 +646,8 @@ + dispatch(); + + /* In fact dispatch() never returns. */ ++ free_interface_alias_map(); ++ + return (0); + } + +@@ -690,10 +736,9 @@ + &to, htop) < 0) { + ++server_packet_errors; + } else { +- log_debug("Forwarded BOOTREPLY for %s to %s", +- print_hw_addr(packet->htype, packet->hlen, +- packet->chaddr), +- inet_ntoa(to.sin_addr)); ++ //log_debug("Forwarded BOOTREPLY for %s to %s", ++ // print_hw_addr(packet->htype, packet->hlen, packet->chaddr), ++ // inet_ntoa(to.sin_addr)); + + ++server_packets_relayed; + } +@@ -732,10 +777,10 @@ + &sp->to, NULL) < 0) { + ++client_packet_errors; + } else { +- log_debug("Forwarded BOOTREQUEST for %s to %s", +- print_hw_addr(packet->htype, packet->hlen, +- packet->chaddr), +- inet_ntoa(sp->to.sin_addr)); ++ //log_debug("Forwarded BOOTREQUEST for %s to %s", ++ // print_hw_addr(packet->htype, packet->hlen, packet->chaddr), ++ // inet_ntoa(sp->to.sin_addr)); ++ + ++client_packets_relayed; + } + } +@@ -937,6 +982,152 @@ return (-1); } @@ -106,9 +191,8 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c + if (cmd != NULL) { + while (fgets(buf, sizeof(buf), cmd)) { + sscanf(buf, FDB_LINE_FORMAT, macAddr, interface, vlanid); -+ log_debug ("bridgefdbquery: macAddr:%s interface: %s vlanid %d", -+ macAddr, -+ interface, *vlanid); ++ //log_debug("bridgefdbquery: macAddr:%s interface: %s vlanid %d", ++ // macAddr, interface, *vlanid); + } + pclose(cmd); + return 0; @@ -149,7 +233,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c + + case 'p': /* Name of interface that we received the request from */ + /* -+ * Query FDB to identify the exact physical interface only when source MAC address ++ * Query FDB to identify the exact physical interface only when source MAC address + * is present and '20: DHCP relay agent IP address' (giaddr) is not present + */ + if (packet->htype && !packet->giaddr.s_addr) { @@ -160,42 +244,29 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c + &vlanid); + + if (ret < 0) { -+ log_debug("MAC Address: %s (interface:%s vlan:%d) not found in bridge fdb show", -+ print_hw_addr (packet->htype, packet->hlen, packet->chaddr), -+ ip->name, -+ vlanid); ++ //log_debug("MAC Address: %s (interface:%s vlan:%d) not found in bridge fdb show", ++ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr), ++ // ip->name, ++ // vlanid); ++ + strncpy(ifname, ip->name, IFNAMSIZ); + } + else if (strlen(ip->name) > 0) { -+ char cmdstr[256] = { 0 }; -+ char cmdout[256] = { 0 }; -+ -+ log_debug("Adding option 82 interface name for MAC Address: %s as %s", -+ print_hw_addr (packet->htype, packet->hlen, packet->chaddr), -+ ip->name); -+ -+ // Translate SONiC interface name to vendor alias -+ sprintf(cmdstr, "sonic-cfggen -m /etc/sonic/minigraph.xml -v \"minigraph_ports['%s'].alias\"", ip->name); -+ -+ FILE *cmd = popen(cmdstr, "r"); -+ -+ if (cmd != NULL) { -+ while (fgets(cmdout, sizeof(cmdout), cmd)) { -+ // Strip any trailing newline -+ if (cmdout[strlen(cmdout) - 1] == '\n') -+ cmdout[strlen(cmdout) - 1] = '\0'; -+ -+ log_debug ("Retrieved alias %s for interface %s", buf, ip->name); ++ // Translate SONiC interface name to vendor alias ++ if (get_interface_alias_by_name(ip->name, ifname) < 0) { ++ log_error("Failed to retrieve alias for interface name '%s'. Defaulting to interface name.", ip->name); ++ strncpy(ifname, ip->name, IFNAMSIZ); + } + -+ pclose(cmd); ++ //log_debug("Mapped interface name '%s' to alias '%s'", ip->name, ifname); ++ ++ //log_debug("Adding option 82 interface alias for MAC Address %s as '%s'", ++ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr), ++ // ifname); + } + -+ strncpy(ifname, cmdout, IFNAMSIZ); ++ str = ifname; + } -+ -+ str = ifname; -+ } + break; + + case 'P': /* Physical address of interface that we received the request from */ @@ -238,7 +309,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c /* * Examine a packet to see if it's a candidate to have a Relay * Agent Information option tacked onto its tail. If it is, tack -@@ -948,6 +1130,8 @@ +@@ -948,6 +1139,8 @@ int is_dhcp = 0, mms; unsigned optlen; u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL; @@ -247,7 +318,7 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c /* If we're not adding agent options to packets, we can skip this. */ -@@ -1077,6 +1261,38 @@ +@@ -1077,6 +1270,38 @@ op = sp; #endif @@ -262,8 +333,8 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c + ip->circuit_id = (uint8_t *)circuit_id_buf; + ip->circuit_id_len = len; + -+ log_debug("sending on %s option82:circuit_id='%s'(%d)", -+ ip->name, (char *)ip->circuit_id, ip->circuit_id_len); ++ //log_debug("Sending on %s option82:circuit_id='%s' (%d)", ++ // ip->name, (char *)ip->circuit_id, ip->circuit_id_len); + } + } + @@ -278,12 +349,94 @@ diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c + ip->remote_id = (uint8_t *)remote_id_buf; + ip->remote_id_len = len; + -+ log_debug("sending on %s option82:remote_id='%s'(%d)", -+ ip->name, (char *)ip->remote_id, ip->remote_id_len); ++ //log_debug("Sending on %s option82:remote_id='%s' (%d)", ++ // ip->name, (char *)ip->remote_id, ip->remote_id_len); + } + } + /* Sanity check. Had better not ever happen. */ if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1)) log_fatal("Circuit ID length %d out of range [1-255] on " - +@@ -1102,7 +1327,7 @@ + * If not, forward without adding the option. + */ + if (max - sp >= optlen + 3) { +- log_debug("Adding %d-byte relay agent option", optlen + 3); ++ //log_debug("Adding %d-byte relay agent option", optlen + 3); + + /* Okay, cons up *our* Relay Agent Information option. */ + *sp++ = DHO_DHCP_AGENT_OPTIONS; +@@ -1726,3 +1951,73 @@ + + exit(0); + } ++ ++#define MAX_PORT_CONFIG_LINE_LEN 1024 ++ ++// Allocates and loads global map g_interface_name_alias_map ++// Also sets global g_interface_name_alias_map_size ++static int ++load_interface_alias_map(const char *port_alias_map_file_path) { ++ int i = 0; ++ FILE *fp = NULL; ++ char line[MAX_PORT_CONFIG_LINE_LEN] = { 0 }; ++ ++ fp = fopen(port_alias_map_file_path,"r"); ++ if (fp == NULL) { ++ log_error("Unable to open %s", port_alias_map_file_path); ++ return -1; ++ } ++ ++ g_interface_name_alias_map_size = 0; ++ ++ // Count the number of interfaces listed in the file ++ while (fgets(line, sizeof(line), fp)) { ++ g_interface_name_alias_map_size++; ++ } ++ ++ // Allocate our map accordingly ++ g_interface_name_alias_map = ((struct interface_name_alias_tuple *) ++ dmalloc((sizeof(struct interface_name_alias_tuple) * g_interface_name_alias_map_size), ++ MDL)); ++ ++ // Reset file position indicator to beginning of file ++ fseek(fp, 0, SEEK_SET); ++ ++ // Every line should contain exactly one name-alias pair ++ while (fgets(line, sizeof(line), fp)) { ++ // Each line should read as "" ++ sscanf(line, "%s %s", g_interface_name_alias_map[i].if_name, g_interface_name_alias_map[i].if_alias); ++ i++; ++ } ++ ++ fclose(fp); ++ ++ log_info("Loaded %d interface name-alias mappings", i); ++ ++ return 0; ++} ++ ++// Locates alias for port named if_name, copies alias into if_alias_out, up to a ++// max of IFNAMSIZ bytes. ++// Returns 0 on success, -1 on failure ++static int ++get_interface_alias_by_name(const char *if_name, char *if_alias_out) { ++ int i = 0; ++ ++ for (i = 0; i < g_interface_name_alias_map_size; i++) { ++ if (strncmp(if_name, g_interface_name_alias_map[i].if_name, IFNAMSIZ) == 0) { ++ strncpy(if_alias_out, g_interface_name_alias_map[i].if_alias, IFNAMSIZ); ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ ++// Frees global map g_interface_name_alias_map ++// Sets g_interface_name_alias_map_size to 0 ++static void ++free_interface_alias_map(void) { ++ free(g_interface_name_alias_map); ++ g_interface_name_alias_map_size = 0; ++} diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 2034125b1dce..826997063349 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -12,38 +12,24 @@ from lxml import etree as ET from lxml.etree import QName -DOCUMENTATION = ''' ---- -module: minigraph_facts +from portconfig import get_port_config + +"""minigraph.py version_added: "1.9" author: Guohan Lu (gulv@microsoft.com) -short_description: Retrive minigraph facts for a device. -description: - - Retrieve minigraph facts for a device, the facts will be - inserted to the ansible_facts key. -options: - host: - description: - - Set to target snmp server (normally {{inventory_hostname}}) - required: true -''' - -EXAMPLES = ''' -# Gather minigraph facts -- name: Gathering minigraph facts about the device - minigraph_facts: host={{ hostname }} -''' +short_description: Parse minigraph xml file and device description xml file +""" ns = "Microsoft.Search.Autopilot.Evolution" ns1 = "http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" ns2 = "Microsoft.Search.Autopilot.NetMux" ns3 = "http://www.w3.org/2001/XMLSchema-instance" - +KEY_SEPARATOR = '|' class minigraph_encoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, ( - ipaddress.IPv4Network, ipaddress.IPv6Network, + ipaddress.IPv4Network, ipaddress.IPv6Network, ipaddress.IPv4Address, ipaddress.IPv6Address )): return str(obj) @@ -100,7 +86,7 @@ def parse_png(png, hname): if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): (lo_prefix, mgmt_prefix, name, hwsku, d_type) = parse_device(device) - device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } + device_data = {'lo_addr': lo_prefix, 'type': d_type, 'mgmt_addr': mgmt_prefix, 'hwsku': hwsku } devices[name] = device_data if child.tag == str(QName(ns, "DeviceInterfaceLinks")): @@ -143,7 +129,7 @@ def parse_dpg(dpg, hname): intfname = lointf.find(str(QName(ns, "AttachTo"))).text ipprefix = lointf.find(str(QName(ns1, "PrefixStr"))).text lo_intfs[(intfname, ipprefix)] = {} - + mgmtintfs = child.find(str(QName(ns, "ManagementIPInterfaces"))) mgmt_intf = {} for mgmtintf in mgmtintfs.findall(str(QName(ns1, "ManagementIPInterface"))): @@ -167,6 +153,7 @@ def parse_dpg(dpg, hname): vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] vlans = {} + vlan_members = {} for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): vintfname = vintf.find(str(QName(ns, "Name"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text @@ -174,14 +161,25 @@ def parse_dpg(dpg, hname): vmbr_list = vintfmbr.split(';') for i, member in enumerate(vmbr_list): vmbr_list[i] = port_alias_map.get(member, member) - vlan_attributes = {'members': vmbr_list, 'vlanid': vlanid} + sonic_vlan_member_name = "Vlan%s%s%s" % (vlanid, KEY_SEPARATOR, vmbr_list[i]) + vlan_members[sonic_vlan_member_name] = {'tagging_mode': 'untagged'} + + vlan_attributes = {'vlanid': vlanid} + + # If this VLAN requires a DHCP relay agent, it will contain a element + # containing a list of DHCP server IPs + if vintf.find(str(QName(ns, "DhcpRelays"))) is not None: + vintfdhcpservers = vintf.find(str(QName(ns, "DhcpRelays"))).text + vdhcpserver_list = vintfdhcpservers.split(';') + vlan_attributes['dhcp_servers'] = vdhcpserver_list + sonic_vlan_name = "Vlan%s" % vlanid vlans[sonic_vlan_name] = vlan_attributes aclintfs = child.find(str(QName(ns, "AclInterfaces"))) acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): - aclname = aclintf.find(str(QName(ns, "InAcl"))).text.lower().replace(" ", "_").replace("-", "_") + aclname = aclintf.find(str(QName(ns, "InAcl"))).text.upper().replace(" ", "_").replace("-", "_") aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') acl_intfs = [] is_mirror = False @@ -199,9 +197,9 @@ def parse_dpg(dpg, hname): acl_intfs = port_alias_map.values() break; if acl_intfs: - acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'mirror' if is_mirror else 'L3'} - return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls - return None, None, None, None, None, None + acls[aclname] = { 'policy_desc': aclname, 'ports': acl_intfs, 'type': 'MIRROR' if is_mirror else 'L3'} + return intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, acls + return None, None, None, None, None, None, None def parse_cpg(cpg, hname): @@ -266,7 +264,7 @@ def parse_cpg(cpg, hname): bgp_session = bgp_sessions[peer] if hostname == bgp_session['name']: bgp_session['asn'] = asn - + bgp_sessions = { key: bgp_sessions[key] for key in bgp_sessions if bgp_sessions[key].has_key('asn') and int(bgp_sessions[key]['asn']) != 0 } return bgp_sessions, myasn, bgp_peers_with_range @@ -311,40 +309,6 @@ def parse_deviceinfo(meta, hwsku): ethernet_interfaces[port_alias_map.get(alias, alias)] = speed return ethernet_interfaces -def parse_port_config(hwsku, platform=None, port_config_file=None): - port_config_candidates = [] - if port_config_file != None: - port_config_candidates.append(port_config_file) - port_config_candidates.append('/usr/share/sonic/hwsku/port_config.ini') - if platform != None: - port_config_candidates.append(os.path.join('/usr/share/sonic/device', platform, hwsku, 'port_config.ini')) - port_config_candidates.append(os.path.join('/usr/share/sonic/platform', hwsku, 'port_config.ini')) - port_config_candidates.append(os.path.join('/usr/share/sonic', hwsku, 'port_config.ini')) - port_config = None - for candidate in port_config_candidates: - if os.path.isfile(candidate): - port_config = candidate - break - if port_config == None: - return None - - ports = {} - with open(port_config) as data: - for line in data: - if line.startswith('#'): - continue - tokens = line.split() - if len(tokens) < 2: - continue - name = tokens[0].strip() - if len(tokens) == 2: - alias = name - else: - alias = tokens[2].strip() - ports[name] = {'alias': alias} - port_alias_map[alias] = name - return ports - def parse_xml(filename, platform=None, port_config_file=None): root = ET.parse(filename).getroot() mini_graph_path = filename @@ -358,6 +322,7 @@ def parse_xml(filename, platform=None, port_config_file=None): vlan_intfs = None pc_intfs = None vlans = None + vlan_members = None pcs = None mgmt_intf = None lo_intf = None @@ -381,11 +346,11 @@ def parse_xml(filename, platform=None, port_config_file=None): if child.tag == str(hostname_qn): hostname = child.text - ports = parse_port_config(hwsku, platform, port_config_file) - + (ports, alias_map) = get_port_config(hwsku, platform, port_config_file) + port_alias_map.update(alias_map) for child in root: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls) = parse_dpg(child, hostname) + (intfs, lo_intfs, mgmt_intf, vlans, vlan_members, pcs, acls) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): @@ -398,7 +363,7 @@ def parse_xml(filename, platform=None, port_config_file=None): port_speeds = parse_deviceinfo(child, hwsku) results = {} - results['DEVICE_METADATA'] = {'localhost': { + results['DEVICE_METADATA'] = {'localhost': { 'bgp_asn': bgp_asn, 'deployment_id': deployment_id, 'hostname': hostname, @@ -433,8 +398,10 @@ def parse_xml(filename, platform=None, port_config_file=None): results['PORT'] = ports results['PORTCHANNEL'] = pcs results['VLAN'] = vlans + results['VLAN_MEMBER'] = vlan_members results['DEVICE_NEIGHBOR'] = neighbors + results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key != hostname } results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) @@ -462,13 +429,13 @@ def parse_device_desc_xml(filename): (lo_prefix, mgmt_prefix, hostname, hwsku, d_type) = parse_device(root) results = {} - results['DEVICE_METADATA'] = {'localhost': { + results['DEVICE_METADATA'] = {'localhost': { 'hostname': hostname, 'hwsku': hwsku, }} results['LOOPBACK_INTERFACE'] = {('lo', lo_prefix): {}} - + mgmt_intf = {} mgmtipn = ipaddress.IPNetwork(mgmt_prefix) gwaddr = ipaddress.IPAddress(int(mgmtipn.network) + 1) diff --git a/src/sonic-config-engine/portconfig.py b/src/sonic-config-engine/portconfig.py new file mode 100644 index 000000000000..db2baa308174 --- /dev/null +++ b/src/sonic-config-engine/portconfig.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +import os +import sys + + +def get_port_config_file_name(hwsku=None, platform=None): + port_config_candidates = [] + port_config_candidates.append('/usr/share/sonic/hwsku/port_config.ini') + if hwsku: + if platform: + port_config_candidates.append(os.path.join('/usr/share/sonic/device', platform, hwsku, 'port_config.ini')) + port_config_candidates.append(os.path.join('/usr/share/sonic/platform', hwsku, 'port_config.ini')) + port_config_candidates.append(os.path.join('/usr/share/sonic', hwsku, 'port_config.ini')) + for candidate in port_config_candidates: + if os.path.isfile(candidate): + return candidate + return None + + +def get_port_config(hwsku=None, platform=None, port_config_file=None): + if not port_config_file: + port_config_file = get_port_config_file_name(hwsku, platform) + if not port_config_file: + return ({}, {}) + return parse_port_config_file(port_config_file) + + +def parse_port_config_file(port_config_file): + ports = {} + port_alias_map = {} + # Default column definition + titles = ['name', 'lanes', 'alias', 'index'] + with open(port_config_file) as data: + for line in data: + if line.startswith('#'): + if "name" in line: + titles = line.strip('#').split() + continue; + tokens = line.split() + if len(tokens) < 2: + continue + name_index = titles.index('name') + name = tokens[name_index] + data = {} + for i, item in enumerate(tokens): + if i == name_index: + continue + data[titles[i]] = item + data.setdefault('alias', name) + ports[name] = data + port_alias_map[data['alias']] = name + return (ports, port_alias_map) + + diff --git a/src/sonic-config-engine/setup.py b/src/sonic-config-engine/setup.py index ac4eb16b30e1..296b7a03a6b9 100755 --- a/src/sonic-config-engine/setup.py +++ b/src/sonic-config-engine/setup.py @@ -15,8 +15,8 @@ def get_test_suite(): author='Taoyu Li', author_email='taoyl@microsoft.com', url='https://github.com/Azure/sonic-buildimage', - py_modules=['minigraph', 'openconfig_acl', 'sonic_platform'], - scripts=['sonic-cfggen', 'translate_acl'], + py_modules=['portconfig', 'minigraph', 'openconfig_acl', 'sonic_platform'], + scripts=['sonic-cfggen'], install_requires=['lxml', 'jinja2', 'netaddr', 'ipaddr', 'pyyaml', 'pyangbind'], test_suite='setup.get_test_suite', ) diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index 5303557c4fb4..9f1323dab2eb 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -200,7 +200,7 @@ def main(): print template.render(data) if args.var_json != None: - print json.dumps(data[args.var_json], indent=4, cls=minigraph_encoder) + print json.dumps(FormatConverter.to_serialized(data[args.var_json]), indent=4, cls=minigraph_encoder) if args.write_to_db: configdb = ConfigDBConnector() diff --git a/src/sonic-config-engine/tests/pc-test-graph.xml b/src/sonic-config-engine/tests/pc-test-graph.xml index 7d7ec74a8631..2cb281b879cb 100644 --- a/src/sonic-config-engine/tests/pc-test-graph.xml +++ b/src/sonic-config-engine/tests/pc-test-graph.xml @@ -108,6 +108,7 @@ False 0.0.0.0/0 + 192.0.0.1;192.0.0.2 1000 1000 192.168.0.0/27 diff --git a/src/sonic-config-engine/tests/sample-port-config-mlnx.ini b/src/sonic-config-engine/tests/sample-port-config-mlnx.ini new file mode 100644 index 000000000000..816bb0e94a70 --- /dev/null +++ b/src/sonic-config-engine/tests/sample-port-config-mlnx.ini @@ -0,0 +1,33 @@ +# name lanes +Ethernet0 0,1,2,3 +Ethernet4 4,5,6,7 +Ethernet8 8,9,10,11 +Ethernet12 12,13,14,15 +Ethernet16 16,17,18,19 +Ethernet20 20,21,22,23 +Ethernet24 24,25,26,27 +Ethernet28 28,29,30,31 +Ethernet32 32,33,34,35 +Ethernet36 36,37,38,39 +Ethernet40 40,41,42,43 +Ethernet44 44,45,46,47 +Ethernet48 48,49,50,51 +Ethernet52 52,53,54,55 +Ethernet56 56,57,58,59 +Ethernet60 60,61,62,63 +Ethernet64 64,65,66,67 +Ethernet68 68,69,70,71 +Ethernet72 72,73,74,75 +Ethernet76 76,77,78,79 +Ethernet80 80,81,82,83 +Ethernet84 84,85,86,87 +Ethernet88 88,89,90,91 +Ethernet92 92,93,94,95 +Ethernet96 96,97,98,99 +Ethernet100 100,101,102,103 +Ethernet104 104,105,106,107 +Ethernet108 108,109,110,111 +Ethernet112 112,113,114,115 +Ethernet116 116,117,118,119 +Ethernet120 120,121,122,123 +Ethernet124 124,125,126,127 diff --git a/src/sonic-config-engine/tests/sample_output/interfaces b/src/sonic-config-engine/tests/sample_output/interfaces index ec3b6f740bc4..2d54e6dabb3d 100644 --- a/src/sonic-config-engine/tests/sample_output/interfaces +++ b/src/sonic-config-engine/tests/sample_output/interfaces @@ -39,151 +39,6 @@ iface eth0 inet6 static down ip -6 rule delete from 2603:10e2:0:2902::8/128 table default # # The switch front panel interfaces -# "|| true" is added to suppress the error when interface is already a member of VLAN -allow-hotplug fortyGigE0/4 -iface fortyGigE0/4 inet manual - pre-up ifconfig fortyGigE0/4 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/4 || true - post-down ifconfig fortyGigE0/4 down -# -allow-hotplug fortyGigE0/8 -iface fortyGigE0/8 inet manual - pre-up ifconfig fortyGigE0/8 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/8 || true - post-down ifconfig fortyGigE0/8 down -# -allow-hotplug fortyGigE0/12 -iface fortyGigE0/12 inet manual - pre-up ifconfig fortyGigE0/12 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/12 || true - post-down ifconfig fortyGigE0/12 down -# -allow-hotplug fortyGigE0/16 -iface fortyGigE0/16 inet manual - pre-up ifconfig fortyGigE0/16 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/16 || true - post-down ifconfig fortyGigE0/16 down -# -allow-hotplug fortyGigE0/20 -iface fortyGigE0/20 inet manual - pre-up ifconfig fortyGigE0/20 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/20 || true - post-down ifconfig fortyGigE0/20 down -# -allow-hotplug fortyGigE0/24 -iface fortyGigE0/24 inet manual - pre-up ifconfig fortyGigE0/24 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/24 || true - post-down ifconfig fortyGigE0/24 down -# -allow-hotplug fortyGigE0/28 -iface fortyGigE0/28 inet manual - pre-up ifconfig fortyGigE0/28 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/28 || true - post-down ifconfig fortyGigE0/28 down -# -allow-hotplug fortyGigE0/32 -iface fortyGigE0/32 inet manual - pre-up ifconfig fortyGigE0/32 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/32 || true - post-down ifconfig fortyGigE0/32 down -# -allow-hotplug fortyGigE0/36 -iface fortyGigE0/36 inet manual - pre-up ifconfig fortyGigE0/36 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/36 || true - post-down ifconfig fortyGigE0/36 down -# -allow-hotplug fortyGigE0/40 -iface fortyGigE0/40 inet manual - pre-up ifconfig fortyGigE0/40 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/40 || true - post-down ifconfig fortyGigE0/40 down -# -allow-hotplug fortyGigE0/44 -iface fortyGigE0/44 inet manual - pre-up ifconfig fortyGigE0/44 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/44 || true - post-down ifconfig fortyGigE0/44 down -# -allow-hotplug fortyGigE0/48 -iface fortyGigE0/48 inet manual - pre-up ifconfig fortyGigE0/48 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/48 || true - post-down ifconfig fortyGigE0/48 down -# -allow-hotplug fortyGigE0/52 -iface fortyGigE0/52 inet manual - pre-up ifconfig fortyGigE0/52 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/52 || true - post-down ifconfig fortyGigE0/52 down -# -allow-hotplug fortyGigE0/56 -iface fortyGigE0/56 inet manual - pre-up ifconfig fortyGigE0/56 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/56 || true - post-down ifconfig fortyGigE0/56 down -# -allow-hotplug fortyGigE0/60 -iface fortyGigE0/60 inet manual - pre-up ifconfig fortyGigE0/60 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/60 || true - post-down ifconfig fortyGigE0/60 down -# -allow-hotplug fortyGigE0/64 -iface fortyGigE0/64 inet manual - pre-up ifconfig fortyGigE0/64 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/64 || true - post-down ifconfig fortyGigE0/64 down -# -allow-hotplug fortyGigE0/68 -iface fortyGigE0/68 inet manual - pre-up ifconfig fortyGigE0/68 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/68 || true - post-down ifconfig fortyGigE0/68 down -# -allow-hotplug fortyGigE0/72 -iface fortyGigE0/72 inet manual - pre-up ifconfig fortyGigE0/72 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/72 || true - post-down ifconfig fortyGigE0/72 down -# -allow-hotplug fortyGigE0/76 -iface fortyGigE0/76 inet manual - pre-up ifconfig fortyGigE0/76 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/76 || true - post-down ifconfig fortyGigE0/76 down -# -allow-hotplug fortyGigE0/80 -iface fortyGigE0/80 inet manual - pre-up ifconfig fortyGigE0/80 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/80 || true - post-down ifconfig fortyGigE0/80 down -# -allow-hotplug fortyGigE0/84 -iface fortyGigE0/84 inet manual - pre-up ifconfig fortyGigE0/84 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/84 || true - post-down ifconfig fortyGigE0/84 down -# -allow-hotplug fortyGigE0/88 -iface fortyGigE0/88 inet manual - pre-up ifconfig fortyGigE0/88 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/88 || true - post-down ifconfig fortyGigE0/88 down -# -allow-hotplug fortyGigE0/92 -iface fortyGigE0/92 inet manual - pre-up ifconfig fortyGigE0/92 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/92 || true - post-down ifconfig fortyGigE0/92 down -# -allow-hotplug fortyGigE0/96 -iface fortyGigE0/96 inet manual - pre-up ifconfig fortyGigE0/96 up mtu 9100 - post-up brctl addif Vlan1000 fortyGigE0/96 || true - post-down ifconfig fortyGigE0/96 down -# # "|| true" is added to suppress the error when interface is already a member of LAG # "ip link show | grep -q master" is added to ensure interface is enslaved allow-hotplug fortyGigE0/112 @@ -210,13 +65,6 @@ iface fortyGigE0/124 inet manual post-up ip link show fortyGigE0/124 | grep -q master && ifconfig fortyGigE0/124 up post-down ifconfig fortyGigE0/124 down # -# Vlan interfaces -auto Vlan1000 -iface Vlan1000 inet static - bridge_ports none - address 192.168.0.1 - netmask 255.255.255.224 -# # Portchannel interfaces allow-hotplug PortChannel01 iface PortChannel01 inet static diff --git a/src/sonic-config-engine/tests/sample_output/isc-dhcp-relay b/src/sonic-config-engine/tests/sample_output/isc-dhcp-relay deleted file mode 100644 index 4a851af34eb9..000000000000 --- a/src/sonic-config-engine/tests/sample_output/isc-dhcp-relay +++ /dev/null @@ -1,7 +0,0 @@ -SERVERS="192.0.0.1 192.0.0.2 192.0.0.3 192.0.0.4 192.0.0.5 192.0.0.6 192.0.0.7 192.0.0.8 192.0.0.9 192.0.0.10 192.0.0.11 192.0.0.12 192.0.0.13 192.0.0.14 192.0.0.15 192.0.0.16 192.0.0.17 192.0.0.18 192.0.0.19 192.0.0.20 192.0.0.21 192.0.0.22 192.0.0.23 192.0.0.24 192.0.0.25 192.0.0.26 192.0.0.27 192.0.0.28 192.0.0.29 192.0.0.30 192.0.0.31 192.0.0.32 192.0.0.33 192.0.0.34 192.0.0.35 192.0.0.36 192.0.0.37 192.0.0.38 192.0.0.39 192.0.0.40 192.0.0.41 192.0.0.42 192.0.0.43 192.0.0.44 192.0.0.45 192.0.0.46 192.0.0.47 192.0.0.48" - -INTERFACES="Vlan1000 PortChannel01 PortChannel02 PortChannel03 PortChannel04" - -# '-a' option provides option 82 circuit id information -OPTIONS="-a" - diff --git a/src/sonic-config-engine/tests/sample_output/mirror.json b/src/sonic-config-engine/tests/sample_output/mirror.json deleted file mode 100644 index 225235067e23..000000000000 --- a/src/sonic-config-engine/tests/sample_output/mirror.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "MIRROR_SESSION_TABLE:everflow0": { - "src_ip": "10.1.0.32", - "dst_ip": "2.2.2.2", - "gre_type": "0x88be", - "queue": "0", - "dscp": "8", - "ttl": "255" - }, - "OP": "SET" - } -] - diff --git a/src/sonic-config-engine/tests/sample_output/msn27.32ports.json b/src/sonic-config-engine/tests/sample_output/msn27.32ports.json new file mode 100644 index 000000000000..c65ebb847d7b --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/msn27.32ports.json @@ -0,0 +1,341 @@ +[ + { + "BUFFER_POOL_TABLE:ingress_lossy_pool": { + "size": "6422528", + "type": "ingress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:egress_lossless_pool": { + "size": "7291456", + "type": "egress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:egress_lossy_pool": { + "size": "8254464", + "type": "egress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:ingress_lossless_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:ingress_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossy_pool]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:egress_lossless_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossless_pool]", + "size":"1518", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:egress_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossy_pool]", + "size":"4096", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:pg_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:q_lossless_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossless_pool]", + "size":"0", + "dynamic_th":"7" + }, + "OP": "SET" + }, + { + "BUFFER_PROFILE_TABLE:q_lossy_profile": { + "pool":"[BUFFER_POOL_TABLE:egress_lossy_pool]", + "size":"0", + "dynamic_th":"1" + }, + "OP": "SET" + }, + { + "BUFFER_PORT_INGRESS_PROFILE_LIST:Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet68,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet64,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet88,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet28,Ethernet60,Ethernet20,Ethernet24": { + "profile_list" : "[BUFFER_PROFILE_TABLE:ingress_lossless_profile],[BUFFER_PROFILE_TABLE:ingress_lossy_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PORT_EGRESS_PROFILE_LIST:Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet68,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet64,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet88,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet28,Ethernet60,Ethernet20,Ethernet24": { + "profile_list" : "[BUFFER_PROFILE_TABLE:egress_lossless_profile],[BUFFER_PROFILE_TABLE:egress_lossy_profile]" + }, + "OP": "SET" + }, + + + + { + "BUFFER_PG_TABLE:Ethernet8:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet0:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet4:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet108:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet100:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet104:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet68:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet96:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet124:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet92:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet120:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet52:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet56:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet76:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet72:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet64:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet32:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet16:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet36:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet12:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet88:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet116:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet80:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet112:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet84:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet48:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet44:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet40:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet28:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet60:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet20:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet24:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile]" + }, + "OP": "SET" + }, + + { + "BUFFER_PROFILE_TABLE:pg_lossless_40G_300m_profile": { + "pool":"[BUFFER_POOL_TABLE:ingress_lossless_pool]", + "xon":"18432", + "xoff":"75776", + "size":"94208", + "dynamic_th":"1" + }, + "OP": "SET" + }, + { + "BUFFER_POOL_TABLE:ingress_lossless_pool": { + "size": "3881382", + "type": "ingress", + "mode": "dynamic" + }, + "OP": "SET" + }, + { + "BUFFER_PG_TABLE:Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet68,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet64,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet88,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet28,Ethernet60,Ethernet20,Ethernet24:0-1": { + "profile" : "[BUFFER_PROFILE_TABLE:pg_lossy_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet68,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet64,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet88,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet28,Ethernet60,Ethernet20,Ethernet24:3-4": { + "profile" : "[BUFFER_PROFILE_TABLE:q_lossless_profile]" + }, + "OP": "SET" + }, + { + "BUFFER_QUEUE_TABLE:Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet68,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet64,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet88,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet28,Ethernet60,Ethernet20,Ethernet24:0-1": { + "profile" : "[BUFFER_PROFILE_TABLE:q_lossy_profile]" + }, + "OP": "SET" + }, + { + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE:AZURE": { + "0": "0", + "1": "1", + "3": "3", + "4": "4" + }, + "OP": "SET" + }, + { + "PORT_QOS_MAP_TABLE:Ethernet8,Ethernet0,Ethernet4,Ethernet108,Ethernet100,Ethernet104,Ethernet68,Ethernet96,Ethernet124,Ethernet92,Ethernet120,Ethernet52,Ethernet56,Ethernet76,Ethernet72,Ethernet64,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet88,Ethernet116,Ethernet80,Ethernet112,Ethernet84,Ethernet48,Ethernet44,Ethernet40,Ethernet28,Ethernet60,Ethernet20,Ethernet24": { + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE:AZURE]" + }, + "OP": "SET" + } +] diff --git a/src/sonic-config-engine/tests/sample_output/rules_for_dataacl.json b/src/sonic-config-engine/tests/sample_output/rules_for_dataacl.json deleted file mode 100644 index 709468f9d945..000000000000 --- a/src/sonic-config-engine/tests/sample_output/rules_for_dataacl.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "ACL_RULE_TABLE:DATAACL:RULE_1":{ - "IP_PROTOCOL":17, - "PACKET_ACTION":"FORWARD", - "SRC_IP":"10.0.0.0/8", - "priority":9999 - }, - "OP":"SET" - }, - { - "ACL_RULE_TABLE:DATAACL:RULE_3":{ - "IP_PROTOCOL":17, - "PACKET_ACTION":"FORWARD", - "SRC_IP":"25.0.0.0/8", - "priority":9997 - }, - "OP":"SET" - }, - { - "ACL_RULE_TABLE:DATAACL:RULE_2":{ - "IP_PROTOCOL":17, - "PACKET_ACTION":"FORWARD", - "SRC_IP":"100.64.0.0/10", - "priority":9998 - }, - "OP":"SET" - }, - { - "ACL_RULE_TABLE:DATAACL:RULE_4":{ - "IP_PROTOCOL":6, - "PACKET_ACTION":"FORWARD", - "TCP_FLAGS":"0x10/0x10", - "priority":9996 - }, - "OP":"SET" - }, - { - "ACL_RULE_TABLE:DATAACL:DEFAULT_RULE":{ - "ETHER_TYPE":"0x0800", - "PACKET_ACTION":"DROP", - "priority":1 - }, - "OP":"SET" - } -] \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/rules_for_everflow.json b/src/sonic-config-engine/tests/sample_output/rules_for_everflow.json deleted file mode 100644 index 2f39a0dcc4a3..000000000000 --- a/src/sonic-config-engine/tests/sample_output/rules_for_everflow.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "ACL_RULE_TABLE:EVERFLOW:RULE_1":{ - "DST_IP":"127.0.0.1/32", - "IP_PROTOCOL":6, - "L4_DST_PORT":0, - "L4_SRC_PORT":0, - "MIRROR_ACTION":"everflow", - "SRC_IP":"127.0.0.1/32", - "priority":9999 - }, - "OP":"SET" - } -] \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/table_dataacl.json b/src/sonic-config-engine/tests/sample_output/table_dataacl.json deleted file mode 100644 index a099680821d4..000000000000 --- a/src/sonic-config-engine/tests/sample_output/table_dataacl.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "ACL_TABLE:DATAACL":{ - "policy_desc":"dataacl", - "ports":"Ethernet112,Ethernet116,Ethernet120,Ethernet124", - "type":"L3" - }, - "OP":"SET" - } -] \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/table_everflow.json b/src/sonic-config-engine/tests/sample_output/table_everflow.json deleted file mode 100644 index 9686f8e3890d..000000000000 --- a/src/sonic-config-engine/tests/sample_output/table_everflow.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "ACL_TABLE:EVERFLOW":{ - "policy_desc":"everflow", - "ports":"Ethernet24,Ethernet40,Ethernet20,Ethernet44,Ethernet48,Ethernet28,Ethernet96,Ethernet92,Ethernet76,Ethernet116,Ethernet72,Ethernet112,Ethernet52,Ethernet108,Ethernet56,Ethernet32,Ethernet16,Ethernet36,Ethernet12,Ethernet120,Ethernet8,Ethernet4,Ethernet0,Ethernet124,Ethernet68,Ethernet84,Ethernet100,Ethernet80,Ethernet60,Ethernet104,Ethernet64,Ethernet88", - "type":"mirror" - }, - "OP":"SET" - } -] \ No newline at end of file diff --git a/src/sonic-config-engine/tests/simple-sample-graph.xml b/src/sonic-config-engine/tests/simple-sample-graph.xml index 7daae24f49a6..89f53af83e41 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph.xml @@ -130,6 +130,7 @@ Vlan1000 fortyGigE0/8 + 192.0.0.1;192.0.0.2 1000 1000 192.168.0.0/27 diff --git a/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml b/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml index 8a21c041c80e..18a8baccdae2 100644 --- a/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml +++ b/src/sonic-config-engine/tests/t0-sample-bgp-speaker.xml @@ -203,6 +203,7 @@ False 0.0.0.0/0 + 192.0.0.1;192.0.0.2 1000 1000 192.168.0.0/27 diff --git a/src/sonic-config-engine/tests/t0-sample-graph-everflow.xml b/src/sonic-config-engine/tests/t0-sample-graph-everflow.xml index 355f01122f0d..6a078b48cf99 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph-everflow.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph-everflow.xml @@ -198,6 +198,7 @@ False 0.0.0.0/0 + 192.0.0.1;192.0.0.2 1000 1000 192.168.0.0/27 diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml index 62a41105f937..fe0b1a1e2500 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph.xml @@ -206,6 +206,7 @@ False 0.0.0.0/0 + 192.0.0.1;192.0.0.2 1000 1000 192.168.0.0/27 diff --git a/src/sonic-config-engine/tests/t1-sample-graph-mlnx.xml b/src/sonic-config-engine/tests/t1-sample-graph-mlnx.xml new file mode 100644 index 000000000000..04fc88c34370 --- /dev/null +++ b/src/sonic-config-engine/tests/t1-sample-graph-mlnx.xml @@ -0,0 +1,2240 @@ + + + + + + ARISTA01T0 + 10.0.0.33 + arc-switch1026 + 10.0.0.32 + 1 + 10 + 3 + + + ARISTA01T0 + FC00::42 + arc-switch1026 + FC00::41 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.0 + ARISTA01T2 + 10.0.0.1 + 1 + 10 + 3 + + + arc-switch1026 + FC00::1 + ARISTA01T2 + FC00::2 + 1 + 10 + 3 + + + ARISTA02T0 + 10.0.0.35 + arc-switch1026 + 10.0.0.34 + 1 + 10 + 3 + + + ARISTA02T0 + FC00::46 + arc-switch1026 + FC00::45 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.2 + ARISTA02T2 + 10.0.0.3 + 1 + 10 + 3 + + + arc-switch1026 + FC00::5 + ARISTA02T2 + FC00::6 + 1 + 10 + 3 + + + ARISTA03T0 + 10.0.0.37 + arc-switch1026 + 10.0.0.36 + 1 + 10 + 3 + + + ARISTA03T0 + FC00::4A + arc-switch1026 + FC00::49 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.4 + ARISTA03T2 + 10.0.0.5 + 1 + 10 + 3 + + + arc-switch1026 + FC00::9 + ARISTA03T2 + FC00::A + 1 + 10 + 3 + + + ARISTA04T0 + 10.0.0.39 + arc-switch1026 + 10.0.0.38 + 1 + 10 + 3 + + + ARISTA04T0 + FC00::4E + arc-switch1026 + FC00::4D + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.6 + ARISTA04T2 + 10.0.0.7 + 1 + 10 + 3 + + + arc-switch1026 + FC00::D + ARISTA04T2 + FC00::E + 1 + 10 + 3 + + + ARISTA05T0 + 10.0.0.41 + arc-switch1026 + 10.0.0.40 + 1 + 10 + 3 + + + ARISTA05T0 + FC00::52 + arc-switch1026 + FC00::51 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.8 + ARISTA05T2 + 10.0.0.9 + 1 + 10 + 3 + + + arc-switch1026 + FC00::11 + ARISTA05T2 + FC00::12 + 1 + 10 + 3 + + + ARISTA06T0 + 10.0.0.43 + arc-switch1026 + 10.0.0.42 + 1 + 10 + 3 + + + ARISTA06T0 + FC00::56 + arc-switch1026 + FC00::55 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.10 + ARISTA06T2 + 10.0.0.11 + 1 + 10 + 3 + + + arc-switch1026 + FC00::15 + ARISTA06T2 + FC00::16 + 1 + 10 + 3 + + + ARISTA07T0 + 10.0.0.45 + arc-switch1026 + 10.0.0.44 + 1 + 10 + 3 + + + ARISTA07T0 + FC00::5A + arc-switch1026 + FC00::59 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.12 + ARISTA07T2 + 10.0.0.13 + 1 + 10 + 3 + + + arc-switch1026 + FC00::19 + ARISTA07T2 + FC00::1A + 1 + 10 + 3 + + + ARISTA08T0 + 10.0.0.47 + arc-switch1026 + 10.0.0.46 + 1 + 10 + 3 + + + ARISTA08T0 + FC00::5E + arc-switch1026 + FC00::5D + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.14 + ARISTA08T2 + 10.0.0.15 + 1 + 10 + 3 + + + arc-switch1026 + FC00::1D + ARISTA08T2 + FC00::1E + 1 + 10 + 3 + + + ARISTA09T0 + 10.0.0.49 + arc-switch1026 + 10.0.0.48 + 1 + 10 + 3 + + + ARISTA09T0 + FC00::62 + arc-switch1026 + FC00::61 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.16 + ARISTA09T2 + 10.0.0.17 + 1 + 10 + 3 + + + arc-switch1026 + FC00::21 + ARISTA09T2 + FC00::22 + 1 + 10 + 3 + + + ARISTA10T0 + 10.0.0.51 + arc-switch1026 + 10.0.0.50 + 1 + 10 + 3 + + + ARISTA10T0 + FC00::66 + arc-switch1026 + FC00::65 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.18 + ARISTA10T2 + 10.0.0.19 + 1 + 10 + 3 + + + arc-switch1026 + FC00::25 + ARISTA10T2 + FC00::26 + 1 + 10 + 3 + + + ARISTA11T0 + 10.0.0.53 + arc-switch1026 + 10.0.0.52 + 1 + 10 + 3 + + + ARISTA11T0 + FC00::6A + arc-switch1026 + FC00::69 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.20 + ARISTA11T2 + 10.0.0.21 + 1 + 10 + 3 + + + arc-switch1026 + FC00::29 + ARISTA11T2 + FC00::2A + 1 + 10 + 3 + + + ARISTA12T0 + 10.0.0.55 + arc-switch1026 + 10.0.0.54 + 1 + 10 + 3 + + + ARISTA12T0 + FC00::6E + arc-switch1026 + FC00::6D + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.22 + ARISTA12T2 + 10.0.0.23 + 1 + 10 + 3 + + + arc-switch1026 + FC00::2D + ARISTA12T2 + FC00::2E + 1 + 10 + 3 + + + ARISTA13T0 + 10.0.0.57 + arc-switch1026 + 10.0.0.56 + 1 + 10 + 3 + + + ARISTA13T0 + FC00::72 + arc-switch1026 + FC00::71 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.24 + ARISTA13T2 + 10.0.0.25 + 1 + 10 + 3 + + + arc-switch1026 + FC00::31 + ARISTA13T2 + FC00::32 + 1 + 10 + 3 + + + ARISTA14T0 + 10.0.0.59 + arc-switch1026 + 10.0.0.58 + 1 + 10 + 3 + + + ARISTA14T0 + FC00::76 + arc-switch1026 + FC00::75 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.26 + ARISTA14T2 + 10.0.0.27 + 1 + 10 + 3 + + + arc-switch1026 + FC00::35 + ARISTA14T2 + FC00::36 + 1 + 10 + 3 + + + ARISTA15T0 + 10.0.0.61 + arc-switch1026 + 10.0.0.60 + 1 + 10 + 3 + + + ARISTA15T0 + FC00::7A + arc-switch1026 + FC00::79 + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.28 + ARISTA15T2 + 10.0.0.29 + 1 + 10 + 3 + + + arc-switch1026 + FC00::39 + ARISTA15T2 + FC00::3A + 1 + 10 + 3 + + + ARISTA16T0 + 10.0.0.63 + arc-switch1026 + 10.0.0.62 + 1 + 10 + 3 + + + ARISTA16T0 + FC00::7E + arc-switch1026 + FC00::7D + 1 + 10 + 3 + + + arc-switch1026 + 10.0.0.30 + ARISTA16T2 + 10.0.0.31 + 1 + 10 + 3 + + + arc-switch1026 + FC00::3D + ARISTA16T2 + FC00::3E + 1 + 10 + 3 + + + + + 65100 + arc-switch1026 + + +

10.0.0.33
+ + + + +
10.0.0.1
+ + +
+ +
10.0.0.35
+ + +
+ +
10.0.0.3
+ + +
+ +
10.0.0.37
+ + +
+ +
10.0.0.5
+ + +
+ +
10.0.0.39
+ + +
+ +
10.0.0.7
+ + +
+ +
10.0.0.41
+ + +
+ +
10.0.0.9
+ + +
+ +
10.0.0.43
+ + +
+ +
10.0.0.11
+ + +
+ +
10.0.0.45
+ + +
+ +
10.0.0.13
+ + +
+ +
10.0.0.47
+ + +
+ +
10.0.0.15
+ + +
+ +
10.0.0.49
+ + +
+ +
10.0.0.17
+ + +
+ +
10.0.0.51
+ + +
+ +
10.0.0.19
+ + +
+ +
10.0.0.53
+ + +
+ +
10.0.0.21
+ + +
+ +
10.0.0.55
+ + +
+ +
10.0.0.23
+ + +
+ +
10.0.0.57
+ + +
+ +
10.0.0.25
+ + +
+ +
10.0.0.59
+ + +
+ +
10.0.0.27
+ + +
+ +
10.0.0.61
+ + +
+ +
10.0.0.29
+ + +
+ +
10.0.0.63
+ + +
+ +
10.0.0.31
+ + +
+ + +
+ + 64001 + ARISTA01T0 + + + + 65200 + ARISTA01T2 + + + + 64002 + ARISTA02T0 + + + + 65200 + ARISTA02T2 + + + + 64003 + ARISTA03T0 + + + + 65200 + ARISTA03T2 + + + + 64004 + ARISTA04T0 + + + + 65200 + ARISTA04T2 + + + + 64005 + ARISTA05T0 + + + + 65200 + ARISTA05T2 + + + + 64006 + ARISTA06T0 + + + + 65200 + ARISTA06T2 + + + + 64007 + ARISTA07T0 + + + + 65200 + ARISTA07T2 + + + + 64008 + ARISTA08T0 + + + + 65200 + ARISTA08T2 + + + + 64009 + ARISTA09T0 + + + + 65200 + ARISTA09T2 + + + + 64010 + ARISTA10T0 + + + + 65200 + ARISTA10T2 + + + + 64011 + ARISTA11T0 + + + + 65200 + ARISTA11T2 + + + + 64012 + ARISTA12T0 + + + + 65200 + ARISTA12T2 + + + + 64013 + ARISTA13T0 + + + + 65200 + ARISTA13T2 + + + + 64014 + ARISTA14T0 + + + + 65200 + ARISTA14T2 + + + + 64015 + ARISTA15T0 + + + + 65200 + ARISTA15T2 + + + + 64016 + ARISTA16T0 + + + + 65200 + ARISTA16T2 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + HostIP1 + Loopback0 + + FC00:1::32/128 + + FC00:1::32/128 + + + + + HostIP + eth0 + + 10.224.23.80/24 + + 10.224.23.80/24 + + + V6HostIP + eth0 + + FC00:2::32/64 + + FC00:2::32/64 + + + + + + arc-switch1026 + + + + + + Ethernet0 + 10.0.0.0/31 + + + + Ethernet0 + FC00::1/126 + + + + Ethernet4 + 10.0.0.2/31 + + + + Ethernet4 + FC00::5/126 + + + + Ethernet8 + 10.0.0.4/31 + + + + Ethernet8 + FC00::9/126 + + + + Ethernet12 + 10.0.0.6/31 + + + + Ethernet12 + FC00::D/126 + + + + Ethernet16 + 10.0.0.8/31 + + + + Ethernet16 + FC00::11/126 + + + + Ethernet20 + 10.0.0.10/31 + + + + Ethernet20 + FC00::15/126 + + + + Ethernet24 + 10.0.0.12/31 + + + + Ethernet24 + FC00::19/126 + + + + Ethernet28 + 10.0.0.14/31 + + + + Ethernet28 + FC00::1D/126 + + + + Ethernet32 + 10.0.0.16/31 + + + + Ethernet32 + FC00::21/126 + + + + Ethernet36 + 10.0.0.18/31 + + + + Ethernet36 + FC00::25/126 + + + + Ethernet40 + 10.0.0.20/31 + + + + Ethernet40 + FC00::29/126 + + + + Ethernet44 + 10.0.0.22/31 + + + + Ethernet44 + FC00::2D/126 + + + + Ethernet48 + 10.0.0.24/31 + + + + Ethernet48 + FC00::31/126 + + + + Ethernet52 + 10.0.0.26/31 + + + + Ethernet52 + FC00::35/126 + + + + Ethernet56 + 10.0.0.28/31 + + + + Ethernet56 + FC00::39/126 + + + + Ethernet60 + 10.0.0.30/31 + + + + Ethernet60 + FC00::3D/126 + + + + Ethernet64 + 10.0.0.32/31 + + + + Ethernet64 + FC00::41/126 + + + + Ethernet68 + 10.0.0.34/31 + + + + Ethernet68 + FC00::45/126 + + + + Ethernet72 + 10.0.0.36/31 + + + + Ethernet72 + FC00::49/126 + + + + Ethernet76 + 10.0.0.38/31 + + + + Ethernet76 + FC00::4D/126 + + + + Ethernet80 + 10.0.0.40/31 + + + + Ethernet80 + FC00::51/126 + + + + Ethernet84 + 10.0.0.42/31 + + + + Ethernet84 + FC00::55/126 + + + + Ethernet88 + 10.0.0.44/31 + + + + Ethernet88 + FC00::59/126 + + + + Ethernet92 + 10.0.0.46/31 + + + + Ethernet92 + FC00::5D/126 + + + + Ethernet96 + 10.0.0.48/31 + + + + Ethernet96 + FC00::61/126 + + + + Ethernet100 + 10.0.0.50/31 + + + + Ethernet100 + FC00::65/126 + + + + Ethernet104 + 10.0.0.52/31 + + + + Ethernet104 + FC00::69/126 + + + + Ethernet108 + 10.0.0.54/31 + + + + Ethernet108 + FC00::6D/126 + + + + Ethernet112 + 10.0.0.56/31 + + + + Ethernet112 + FC00::71/126 + + + + Ethernet116 + 10.0.0.58/31 + + + + Ethernet116 + FC00::75/126 + + + + Ethernet120 + 10.0.0.60/31 + + + + Ethernet120 + FC00::79/126 + + + + Ethernet124 + 10.0.0.62/31 + + + + Ethernet124 + FC00::7D/126 + + + + + + + + + + + + DeviceInterfaceLink + arc-switch1026 + Ethernet0 + ARISTA01T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet4 + ARISTA02T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet8 + ARISTA03T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet12 + ARISTA04T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet16 + ARISTA05T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet20 + ARISTA06T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet24 + ARISTA07T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet28 + ARISTA08T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet32 + ARISTA09T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet36 + ARISTA10T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet40 + ARISTA11T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet44 + ARISTA12T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet48 + ARISTA13T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet52 + ARISTA14T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet56 + ARISTA15T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet60 + ARISTA16T2 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet64 + ARISTA01T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet68 + ARISTA02T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet72 + ARISTA03T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet76 + ARISTA04T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet80 + ARISTA05T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet84 + ARISTA06T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet88 + ARISTA07T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet92 + ARISTA08T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet96 + ARISTA09T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet100 + ARISTA10T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet104 + ARISTA11T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet108 + ARISTA12T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet112 + ARISTA13T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet116 + ARISTA14T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet120 + ARISTA15T0 + Ethernet1 + + + DeviceInterfaceLink + arc-switch1026 + Ethernet124 + ARISTA16T0 + Ethernet1 + + + + + arc-switch1026 + ACS-MSN2700 + + 10.224.23.80 + + + + "ARISTA01T0" + Arista-VM + + 10.224.23.196 + + + + "ARISTA01T2" + Arista-VM + + 10.224.23.180 + + + + "ARISTA02T0" + Arista-VM + + 10.224.23.197 + + + + "ARISTA02T2" + Arista-VM + + 10.224.23.181 + + + + "ARISTA03T0" + Arista-VM + + 10.224.23.198 + + + + "ARISTA03T2" + Arista-VM + + 10.224.23.182 + + + + "ARISTA04T0" + Arista-VM + + 10.224.23.199 + + + + "ARISTA04T2" + Arista-VM + + 10.224.23.183 + + + + "ARISTA05T0" + Arista-VM + + 10.224.23.200 + + + + "ARISTA05T2" + Arista-VM + + 10.224.23.184 + + + + "ARISTA06T0" + Arista-VM + + 10.224.23.201 + + + + "ARISTA06T2" + Arista-VM + + 10.224.23.185 + + + + "ARISTA07T0" + Arista-VM + + 10.224.23.202 + + + + "ARISTA07T2" + Arista-VM + + 10.224.23.186 + + + + "ARISTA08T0" + Arista-VM + + 10.224.23.203 + + + + "ARISTA08T2" + Arista-VM + + 10.224.23.187 + + + + "ARISTA09T0" + Arista-VM + + 10.224.23.152 + + + + "ARISTA09T2" + Arista-VM + + 10.224.23.188 + + + + "ARISTA10T0" + Arista-VM + + 10.224.23.153 + + + + "ARISTA10T2" + Arista-VM + + 10.224.23.189 + + + + "ARISTA11T0" + Arista-VM + + 10.224.23.154 + + + + "ARISTA11T2" + Arista-VM + + 10.224.23.190 + + + + "ARISTA12T0" + Arista-VM + + 10.224.23.155 + + + + "ARISTA12T2" + Arista-VM + + 10.224.23.191 + + + + "ARISTA13T0" + Arista-VM + + 10.224.23.156 + + + + "ARISTA13T2" + Arista-VM + + 10.224.23.192 + + + + "ARISTA14T0" + Arista-VM + + 10.224.23.157 + + + + "ARISTA14T2" + Arista-VM + + 10.224.23.193 + + + + "ARISTA15T0" + Arista-VM + + 10.224.23.158 + + + + "ARISTA15T2" + Arista-VM + + 10.224.23.194 + + + + "ARISTA16T0" + Arista-VM + + 10.224.23.159 + + + + "ARISTA16T2" + Arista-VM + + 10.224.23.195 + + + + + + + true + + + DeviceInterface + + true + true + 1 + Ethernet0 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet4 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet8 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet12 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet16 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet20 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet24 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet28 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet32 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet36 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet40 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet44 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet48 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet52 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet56 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet60 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet64 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet68 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet72 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet76 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet80 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet84 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet88 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet92 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet96 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet100 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet104 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet108 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet112 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet116 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet120 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + true + 1 + Ethernet124 + + false + 0 + 0 + 40000 + + + true + 0 + ACS-MSN2700 + + + + + + + arc-switch1026 + + + DhcpResources + + 10.0.0.1 + + + NTPResources + + 10.0.0.1;10.0.0.2 + + + DeploymentId + + 1 + + + QosProfile + + Profile0 + + + RadiusResources + + + + + SnmpResources + + 10.0.0.9 + + + SyslogResources + + 10.0.0.5;10.0.0.6 + + + TacacsGroup + + testlab + + + TacacsServer + + 10.0.0.9;10.0.0.8 + + + ForcedMgmtRoutes + + 10.0.0.100/31;10.250.0.8;10.255.0.0/28 + + + ErspanDestinationIpv4 + + 10.0.0.7 + + + + + + + arc-switch1026 + ACS-MSN2700 + diff --git a/src/sonic-config-engine/tests/test_acl.py b/src/sonic-config-engine/tests/test_acl.py deleted file mode 100644 index 319b2c1f73a7..000000000000 --- a/src/sonic-config-engine/tests/test_acl.py +++ /dev/null @@ -1,58 +0,0 @@ -import filecmp -import os -import subprocess - -from unittest import TestCase - -class TestAcl(TestCase): - def setUp(self): - self.test_dir = os.path.dirname(os.path.realpath(__file__)) - self.script_file = os.path.join(self.test_dir, '..', 'sonic-cfggen') - self.acl_script_file = os.path.join(self.test_dir, '..', 'translate_acl') - self.t0_minigraph = os.path.join(self.test_dir, 't0-sample-graph.xml') - self.t0_minigraph_everflow = os.path.join(self.test_dir, 't0-sample-graph-everflow.xml') - self.t0_acl = os.path.join(self.test_dir, 't0-sample-acl.json') - self.t0_port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') - - def run_script(self, argument): - print 'CMD: sonic-cfggen ' + argument - output = '' - try: - output = subprocess.check_output(self.script_file + ' ' + argument, shell=True, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError, (p): - print 'CalledProcessError: CMD:%s returncode:%s' % (p.cmd, p.returncode) - print p.output - return output - - def run_acl_script(self, argument): - print 'CMD: translate_acl ' + argument - output = '' - try: - output = subprocess.check_output(self.acl_script_file + ' ' + argument, shell=True, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError, (p): - print 'CalledProcessError: CMD:%s returncode:%s' % (p.cmd, p.returncode) - print p.output - return output - - def test_translate_acl(self): - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -o ' + self.test_dir + ' ' + self.t0_acl - self.run_acl_script(argument) - for filename in ['rules_for_dataacl.json','table_dataacl.json']: - sample_output_file = os.path.join(self.test_dir, 'sample_output', filename) - output_file = os.path.join(self.test_dir, filename) - assert filecmp.cmp(sample_output_file, output_file) - - def test_translate_everflow(self): - argument = '-m ' + self.t0_minigraph_everflow + ' -p ' + self.t0_port_config + ' -o ' + self.test_dir + ' ' + self.t0_acl - self.run_acl_script(argument) - for filename in ['rules_for_everflow.json','table_everflow.json']: - sample_output_file = os.path.join(self.test_dir, 'sample_output', filename) - output_file = os.path.join(self.test_dir, filename) - assert filecmp.cmp(sample_output_file, output_file) - - def tearDown(self): - for filename in ['rules_for_dataacl.json','table_dataacl.json','rules_for_everflow.json','table_everflow.json']: - try: - os.remove(os.path.join(self.test_dir, filename)) - except OSError: - pass diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 337c06761762..47cc006f4662 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -3,7 +3,7 @@ import os class TestCfgGen(TestCase): - + def setUp(self): self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = os.path.join(self.test_dir, '..', 'sonic-cfggen') @@ -29,7 +29,7 @@ def test_dummy_run(self): argument = '' output = self.run_script(argument) self.assertEqual(output, '') - + def test_device_desc(self): argument = '-v "DEVICE_METADATA[\'localhost\'][\'hwsku\']" -M "' + self.sample_device_desc + '"' output = self.run_script(argument) @@ -44,17 +44,17 @@ def test_minigraph_sku(self): argument = '-v "DEVICE_METADATA[\'localhost\'][\'hwsku\']" -m "' + self.sample_graph + '"' output = self.run_script(argument) self.assertEqual(output.strip(), 'Force10-Z9100') - + def test_print_data(self): argument = '-m "' + self.sample_graph + '" --print-data' output = self.run_script(argument) self.assertTrue(len(output.strip()) > 0) - + def test_jinja_expression(self): argument = '-m "' + self.sample_graph + '" -v "DEVICE_METADATA[\'localhost\'][\'type\']"' output = self.run_script(argument) self.assertEqual(output.strip(), 'LeafRouter') - + def test_additional_json_data(self): argument = '-a \'{"key1":"value1"}\' -v key1' output = self.run_script(argument) @@ -64,7 +64,7 @@ def test_read_yaml(self): argument = '-v yml_item -y ' + os.path.join(self.test_dir, 'test.yml') output = self.run_script(argument) self.assertEqual(output.strip(), '[\'value1\', \'value2\']') - + def test_render_template(self): argument = '-y ' + os.path.join(self.test_dir, 'test.yml') + ' -t ' + os.path.join(self.test_dir, 'test.j2') output = self.run_script(argument) @@ -73,17 +73,27 @@ def test_render_template(self): def test_minigraph_acl(self): argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v ACL_TABLE' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'dataacl': {'type': 'L3', 'policy_desc': 'dataacl', 'ports': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}}") + self.assertEqual(output.strip(), "{'DATAACL': {'type': 'L3', 'policy_desc': 'DATAACL', 'ports': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}}") + + def test_minigraph_everflow(self): + argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v MIRROR_SESSION' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '2.2.2.2'}}") def test_minigraph_interfaces(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v \'INTERFACE.keys()\'' output = self.run_script(argument) self.assertEqual(output.strip(), "[('Ethernet0', '10.0.0.58/31'), ('Ethernet0', 'FC00::75/126')]") - + def test_minigraph_vlans(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'Vlan1000': {'members': ['Ethernet8'], 'vlanid': '1000'}}") + self.assertEqual(output.strip(), "{'Vlan1000': {'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '1000'}}") + + def test_minigraph_vlan_members(self): + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v VLAN_MEMBER' + output = self.run_script(argument) + self.assertEqual(output.strip(), "{'Vlan1000|Ethernet8': {'tagging_mode': 'untagged'}}") def test_minigraph_vlan_interfaces(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "VLAN_INTERFACE.keys()"' @@ -128,4 +138,4 @@ def test_minigraph_deployment_id(self): def test_minigraph_ethernet_interfaces(self): argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" -v "PORT[\'Ethernet8\']"' output = self.run_script(argument) - self.assertEqual(output.strip(), "{'alias': 'fortyGigE0/8', 'speed': '40000'}") + self.assertEqual(output.strip(), "{'alias': 'fortyGigE0/8', 'lanes': '37,38,39,40', 'speed': '40000'}") diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 4bdc1b41f5b4..d1cc0d2a3296 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -12,6 +12,8 @@ def setUp(self): self.t0_minigraph = os.path.join(self.test_dir, 't0-sample-graph.xml') self.pc_minigraph = os.path.join(self.test_dir, 'pc-test-graph.xml') self.t0_port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') + self.t1_mlnx_minigraph = os.path.join(self.test_dir, 't1-sample-graph-mlnx.xml') + self.mlnx_port_config = os.path.join(self.test_dir, 'sample-port-config-mlnx.ini') self.output_file = os.path.join(self.test_dir, 'output') def run_script(self, argument): @@ -20,7 +22,7 @@ def run_script(self, argument): def test_interfaces(self): interfaces_template = os.path.join(self.test_dir, '..', '..', '..', 'files', 'image_config', 'interfaces', 'interfaces.j2') - argument = '-m ' + self.t0_minigraph + ' -t ' + interfaces_template + ' > ' + self.output_file + argument = '-m ' + self.t0_minigraph + ' -a \'{\"hwaddr\":\"e4:1d:2d:a5:f3:ad\"}\' -t ' + interfaces_template + ' > ' + self.output_file self.run_script(argument) self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'interfaces'), self.output_file)) @@ -29,14 +31,14 @@ def test_alias_map(self): argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + alias_map_template output = self.run_script(argument) data = json.loads(output) - self.assertEqual(data["Ethernet4"], "fortyGigE0/4") + self.assertEqual(data["Ethernet4"], "fortyGigE0/4") def test_lldp(self): lldpd_conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-lldp-sv2', 'lldpd.conf.j2') argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + lldpd_conf_template + ' > ' + self.output_file self.run_script(argument) self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'lldpd.conf'), self.output_file)) - + def test_teamd(self): def test_render_teamd(self, pc, minigraph, sample_output): @@ -75,14 +77,14 @@ def test_ipinip(self): assert filecmp.cmp(sample_output_file, self.output_file) - def test_everflow(self): - everflow_file = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent', 'mirror.json.j2') - argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + everflow_file + ' > ' + self.output_file + def test_msn27xx_32ports_buffers(self): + buffer_file = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent', 'msn27xx.32ports.buffers.json.j2') + argument = '-m ' + self.t1_mlnx_minigraph + ' -p ' + self.mlnx_port_config + ' -t ' + buffer_file + ' > ' + self.output_file self.run_script(argument) - sample_output_file = os.path.join(self.test_dir, 'sample_output', 'mirror.json') + sample_output_file = os.path.join(self.test_dir, 'sample_output', 'msn27.32ports.json') - assert filecmp.cmp(sample_output_file, self.output_file) + self.assertTrue(filecmp.cmp(sample_output_file, self.output_file)) def tearDown(self): diff --git a/src/sonic-config-engine/translate_acl b/src/sonic-config-engine/translate_acl deleted file mode 100755 index b8138cf36b18..000000000000 --- a/src/sonic-config-engine/translate_acl +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python - -import sys -import os.path -import json -import argparse - -import openconfig_acl -import pyangbind.lib.pybindJSON as pybindJSON -from minigraph import parse_xml - -def dump_json(filename, data): - with open(filename, 'w') as outfile: - json.dump(data, outfile, indent=4, sort_keys=True, separators=(',', ':')) - -def default_deny_rule(table_name): - rule_props = {} - rule_data = {} - rule_data["ACL_RULE_TABLE:"+table_name.upper()+":DEFAULT_RULE"] = rule_props - rule_data["OP"] = "SET" - rule_props["priority"] = 1 - rule_props["ETHER_TYPE"] = "0x0800" - rule_props["PACKET_ACTION"] = "DROP" - return rule_data - -def generate_rule_json(table_name, rule, max_priority, mirror): - rule_idx = rule.config.sequence_id - rule_props = {} - rule_data = {} - rule_data["ACL_RULE_TABLE:"+table_name.upper()+":RULE_"+str(rule_idx)] = rule_props - rule_data["OP"] = "SET" - - rule_props["priority"] = max_priority - rule_idx - if rule.actions.config.forwarding_action == "ACCEPT": - if mirror: - rule_props["MIRROR_ACTION"] = "everflow" - else: - rule_props["PACKET_ACTION"] = "FORWARD" - elif rule.actions.config.forwarding_action == "DROP": - rule_props["PACKET_ACTION"] = "DROP" - elif rule.actions.config.forwarding_action == "REJECT": - rule_props["PACKET_ACTION"] = "DROP" - else: - print "Unknown rule action %s in table %s, rule %d!" % (rule.actions.config.forwarding_action, table_name, rule_idx) - return {} - - ip_protocol_map = { - "IP_TCP" : 6, - "IP_ICMP" : 1, - "IP_UDP" : 17, - "IP_IGMP" : 2, - "IP_PIM" : 103, - "IP_RSVP" : 46, - "IP_GRE" : 47, - "IP_AUTH" : 51, - "IP_L2TP" : 115 - } - - if not rule.ip.config.protocol: - pass - elif ip_protocol_map.has_key(rule.ip.config.protocol): - rule_props["IP_PROTOCOL"] = ip_protocol_map[rule.ip.config.protocol] - else: - try: - int(rule.ip.config.protocol) - except: - print "Unknown rule protocol %s in table %s, rule %d!" % (rule.ip.config.protocol, table_name, rule_idx) - return {} - else: - rule_props["IP_PROTOCOL"] = rule.ip.config.protocol - - if rule.ip.config.source_ip_address != "": - rule_props["SRC_IP"] = rule.ip.config.source_ip_address - if rule.ip.config.destination_ip_address != "": - rule_props["DST_IP"] = rule.ip.config.destination_ip_address - - if rule.transport.config.source_port == "": - pass - elif str(rule.transport.config.source_port).find("..") < 0: - rule_props["L4_SRC_PORT"] = rule.transport.config.source_port - else: - rule_props["L4_SRC_PORT_RANGE"] = str(rule.transport.config.source_port).replace("..", "-") - - if rule.transport.config.destination_port == "": - pass - elif str(rule.transport.config.destination_port).find("..") < 0: - rule_props["L4_DST_PORT"] = rule.transport.config.destination_port - else: - rule_props["L4_DST_PORT_RANGE"] = str(rule.transport.config.destination_port).replace("..", "-") - - tcp_flags = 0x00; - for flag in rule.transport.config.tcp_flags: - if flag == "TCP_FIN": - tcp_flags = tcp_flags | 0x01 - if flag == "TCP_SYN": - tcp_flags = tcp_flags | 0x02 - if flag == "TCP_RST": - tcp_flags = tcp_flags | 0x04 - if flag == "TCP_PSH": - tcp_flags = tcp_flags | 0x08 - if flag == "TCP_ACK": - tcp_flags = tcp_flags | 0x10 - if flag == "TCP_URG": - tcp_flags = tcp_flags | 0x20 - if flag == "TCP_ECE": - tcp_flags = tcp_flags | 0x40 - if flag == "TCP_CWR": - tcp_flags = tcp_flags | 0x80 - if tcp_flags != 0x00: - rule_props["TCP_FLAGS"] = '0x{:02x}/0x{:02x}'.format(tcp_flags, tcp_flags) - return rule_data - -def generate_table_json(aclset, aclname, ports, t_type, max_priority, output_path='.'): - table_name = aclname.replace(" ", "_").replace("-", "_") - #table_name = generate_random_table_name() - mirror = (t_type == 'mirror') - - table_props = {} - table_props["policy_desc"] = table_name - table_props["type"] = t_type - table_props["ports"] = ports - - table_data = [{}] - table_data[0]["ACL_TABLE:"+table_name.upper()] = table_props - table_data[0]["OP"] = "SET" - dump_json(os.path.join(output_path, "table_"+table_name+".json"), table_data) - - rule_data = [] - for aclentryname in aclset.acl_entries.acl_entry: - aclentry = aclset.acl_entries.acl_entry[aclentryname] - rule_props = generate_rule_json(table_name, aclentry, max_priority, mirror) - if rule_props: - rule_data.append(rule_props) - if not mirror: - rule_data.append(default_deny_rule(table_name)) - dump_json(os.path.join(output_path, "rules_for_"+table_name+".json"), rule_data) - -def translate_acl_fixed_port(filename, output_path, port, max_priority): - yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl") - for aclsetname in yang_acl.acl.acl_sets.acl_set: - aclset = yang_acl.acl.acl_sets.acl_set[aclsetname] - generate_table_json(aclset, aclsetname, port, 'l3', max_priority, output_path) - return - -def translate_acl(filename, output_path, mini_acl, max_priority): - yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl") - for aclsetname in yang_acl.acl.acl_sets.acl_set: - tablename = aclsetname.replace(" ", "_").replace("-", "_") - if mini_acl.has_key(tablename): - t_type = mini_acl[tablename]['type'] - ports = ','.join(mini_acl[tablename]['ports']) - aclset = yang_acl.acl.acl_sets.acl_set[aclsetname] - generate_table_json(aclset, aclsetname, ports, t_type, max_priority, output_path) - return - -def main(): - parser = argparse.ArgumentParser(description="Translate openconfig ACL json into SONiC ACL jsons") - parser.add_argument('input', metavar='INPUT', help='input json file in openconfig format') - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-a', '--attach-to', help='the port(s) that this ACL is attached to') - group.add_argument('-m', '--minigraph', help='read ACL attaching information from minigraph') - parser.add_argument("-p", "--port-config", help="port config file, used with -m") - parser.add_argument('-n', '--max-priority', type=int, default=10000, help='the priority number of the first rule in ACL entries') - parser.add_argument('-o', '--output-path', default='.', help='output directory where SONiC ACL jsons will be generated') - args = parser.parse_args() - if args.attach_to: - translate_acl_fixed_port(args.input, args.output_path, args.port, args.max_priority) - elif args.minigraph: - mini_data = parse_xml(args.minigraph, port_config_file=args.port_config) - if mini_data['ACL_TABLE']: - translate_acl(args.input, args.output_path, mini_data['ACL_TABLE'], args.max_priority) - -if __name__ == "__main__": - main() diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index 80d5a9ad0900..b044781a60f2 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -5,11 +5,6 @@ SHELL = /bin/bash MAIN_TARGET = frr_$(FRR_VERSION)_amd64.deb $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : - # Cloning FRR repo if not already done - if [ ! -d "frr" ]; then \ - git clone -b stable/$(FRR_VERSION) https://github.com/FRRouting/frr.git; \ - fi - # Replacing frr's rules/install files with SONiC's own versions to activate # specific knobs and adjust install process to address SONiC's needs. cp sonic_frr.rules frr/debian/rules diff --git a/src/sonic-frr/frr b/src/sonic-frr/frr new file mode 160000 index 000000000000..5424c62d6e9d --- /dev/null +++ b/src/sonic-frr/frr @@ -0,0 +1 @@ +Subproject commit 5424c62d6e9d574a00529edfc0a0b3bb3beb8811 diff --git a/src/sonic-platform-daemons b/src/sonic-platform-daemons index d68c286ba7c9..d1df4717627a 160000 --- a/src/sonic-platform-daemons +++ b/src/sonic-platform-daemons @@ -1 +1 @@ -Subproject commit d68c286ba7c984c98ebfafc2bb5fe24905659e5f +Subproject commit d1df4717627acf9421861545b71e411acf3c5f32 diff --git a/src/sonic-py-swsssdk b/src/sonic-py-swsssdk index 96b4928e790b..294f5406e971 160000 --- a/src/sonic-py-swsssdk +++ b/src/sonic-py-swsssdk @@ -1 +1 @@ -Subproject commit 96b4928e790bbce7c959f0b5cbb0510e5954afb1 +Subproject commit 294f5406e971396352b06c3b4954a2f80dd8ba34 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index e4d24276cb6f..f5d9c8364f5f 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit e4d24276cb6fc7122f756c637f30ddea27487c70 +Subproject commit f5d9c8364f5fbcc487a5f1a3e3e6203ab2293a83 diff --git a/src/sonic-snmpagent b/src/sonic-snmpagent index bc4becf97ea6..39f1e23cb834 160000 --- a/src/sonic-snmpagent +++ b/src/sonic-snmpagent @@ -1 +1 @@ -Subproject commit bc4becf97ea69c15315414e8c7cba44067af2461 +Subproject commit 39f1e23cb834255955f5270234c8a72b14c11d6f diff --git a/src/sonic-swss b/src/sonic-swss index bcdea1323e70..b641aeeac349 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit bcdea1323e70c73fa0a85c6df55eaed886bded81 +Subproject commit b641aeeac349462dd3e3e370bfc55f16602c937f diff --git a/src/sonic-swss-common b/src/sonic-swss-common index f6ff19bee131..adf7d4cb3c22 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit f6ff19bee131048f2274a21ea1064a8493a7fd8b +Subproject commit adf7d4cb3c22061bf781ef6ce7b79964ce505730 diff --git a/src/sonic-utilities b/src/sonic-utilities index b27d4f9e976f..1d37c9c199b7 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit b27d4f9e976f944f50d81e2354ba826194971774 +Subproject commit 1d37c9c199b7934653f907095bf11e685889df23 diff --git a/src/supervisor/Makefile b/src/supervisor/Makefile index 5f06325960b1..778903194ffa 100644 --- a/src/supervisor/Makefile +++ b/src/supervisor/Makefile @@ -8,8 +8,8 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Remove any stale files rm -rf ./supervisor - # Clone isc-dhcp repo - git clone git://github.com/Supervisor/supervisor.git + # Clone supervisor repo + git clone https://github.com/Supervisor/supervisor.git pushd ./supervisor git checkout -f 3.3.2 From 54e176fb41f22e6c43539bfcca0467609dfd4a7a Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 6 Nov 2017 17:52:27 -0800 Subject: [PATCH 14/17] Auto-completion, help (?), cmd navigation (up arrow) not working in vtysh on host system. RB= G=lnos-reviewers R=ntrianta,rjonnadu,rmolina,sfardeen,zxu A= --- dockers/docker-fpm-frr/base_image_files/vtysh | 2 +- dockers/docker-fpm-quagga/base_image_files/vtysh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dockers/docker-fpm-frr/base_image_files/vtysh b/dockers/docker-fpm-frr/base_image_files/vtysh index 359101c06c61..18529b7522c7 100755 --- a/dockers/docker-fpm-frr/base_image_files/vtysh +++ b/dockers/docker-fpm-frr/base_image_files/vtysh @@ -1,2 +1,2 @@ #!/bin/bash -docker exec -i bgp vtysh "$@" +docker exec -it bgp vtysh "$@" diff --git a/dockers/docker-fpm-quagga/base_image_files/vtysh b/dockers/docker-fpm-quagga/base_image_files/vtysh index 359101c06c61..18529b7522c7 100755 --- a/dockers/docker-fpm-quagga/base_image_files/vtysh +++ b/dockers/docker-fpm-quagga/base_image_files/vtysh @@ -1,2 +1,2 @@ #!/bin/bash -docker exec -i bgp vtysh "$@" +docker exec -it bgp vtysh "$@" From 58082cd8cdc5a6a610deb2cc562f189b35fd9d3b Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Fri, 10 Nov 2017 14:50:31 -0800 Subject: [PATCH 15/17] Update sonic-quagga submodule --- src/sonic-quagga | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-quagga b/src/sonic-quagga index b066bef0e8dc..59f7c8ed56fa 160000 --- a/src/sonic-quagga +++ b/src/sonic-quagga @@ -1 +1 @@ -Subproject commit b066bef0e8dcf23b8e1751652397c09e61ee4bdd +Subproject commit 59f7c8ed56fa1c9df2070596b25f5f019bdba8ca From 15a0dd7136a045087d471c5496d64089e4fecdc4 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 12 Feb 2018 14:06:10 -0800 Subject: [PATCH 16/17] Upgrade supervisord to 3.3.3 and fix supervisord.conf --- dockers/docker-base/etc/supervisor/supervisord.conf | 5 +++++ rules/supervisor.mk | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dockers/docker-base/etc/supervisor/supervisord.conf b/dockers/docker-base/etc/supervisor/supervisord.conf index afead15524bf..5fdd8088be60 100644 --- a/dockers/docker-base/etc/supervisor/supervisord.conf +++ b/dockers/docker-base/etc/supervisor/supervisord.conf @@ -3,11 +3,14 @@ [unix_http_server] file=/var/run/supervisor.sock ; (the path to the socket file) chmod=0700 ; sockef file mode (default 0700) +username=nobody +password=nobody [supervisord] logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +user=root ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be @@ -17,6 +20,8 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket +username=nobody +password=nobody ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or diff --git a/rules/supervisor.mk b/rules/supervisor.mk index 7e7466bbad86..cd97eabf801d 100644 --- a/rules/supervisor.mk +++ b/rules/supervisor.mk @@ -1,6 +1,6 @@ # supervisor package -SUPERVISOR_VERSION = 3.3.2 +SUPERVISOR_VERSION = 3.3.3 export SUPERVISOR_VERSION From b680877f97056d1f568711ffdf18a6ce5dcf3c76 Mon Sep 17 00:00:00 2001 From: Nikos Triantafillis Date: Mon, 12 Feb 2018 14:06:10 -0800 Subject: [PATCH 17/17] Upgrade supervisord to 3.3.3 and fix supervisord.conf --- dockers/docker-base/etc/supervisor/supervisord.conf | 5 +++++ rules/supervisor.mk | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dockers/docker-base/etc/supervisor/supervisord.conf b/dockers/docker-base/etc/supervisor/supervisord.conf index afead15524bf..351cc06fc048 100644 --- a/dockers/docker-base/etc/supervisor/supervisord.conf +++ b/dockers/docker-base/etc/supervisor/supervisord.conf @@ -3,11 +3,14 @@ [unix_http_server] file=/var/run/supervisor.sock ; (the path to the socket file) chmod=0700 ; sockef file mode (default 0700) +username=dummy +password=dummy [supervisord] logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +user=root ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be @@ -17,6 +20,8 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket +username=dummy +password=dummy ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or diff --git a/rules/supervisor.mk b/rules/supervisor.mk index 7e7466bbad86..cd97eabf801d 100644 --- a/rules/supervisor.mk +++ b/rules/supervisor.mk @@ -1,6 +1,6 @@ # supervisor package -SUPERVISOR_VERSION = 3.3.2 +SUPERVISOR_VERSION = 3.3.3 export SUPERVISOR_VERSION