From 8dd582bff1d2c71f2d722ce792eaebf69c65ee61 Mon Sep 17 00:00:00 2001 From: Lars Kristan Date: Fri, 7 Aug 2020 02:20:00 +0200 Subject: [PATCH] Release 2.2.0.0 --- .version | 2 +- Makefile | 4 +- build/dirs.mk | 1 + build/fut.mk | 43 + build/stam.mk | 69 + build/unit-build.mk | 24 + doc/doxygen.conf | 12 +- interfaces/interface_stats.proto | 53 + interfaces/object_manager.proto | 45 + interfaces/opensync.ovsschema | 398 +++++- interfaces/opensync_stats.proto | 27 +- kconfig/Kconfig | 26 + kconfig/Kconfig.managers | 2 + kconfig/Kconfig.osn.pppoe_backend | 11 + kconfig/Kconfig.osn.vlan_backend | 11 + kconfig/Kconfig.osp_objm | 10 + kconfig/Kconfig.osp_objm.backend | 11 + kconfig/Kconfig.osp_unit.backend | 10 + ovsdb/20_kconfig.bridge_wan_ipv6.json.sh | 9 + .../OSN_LINUX_PPPOE/etc/ppp/chap-secrets | 1 + .../OSN_LINUX_PPPOE/etc/ppp/ip-down.jinja | 6 + .../OSN_LINUX_PPPOE/etc/ppp/ip-up.jinja | 15 + .../OSN_LINUX_PPPOE/etc/ppp/pap-secrets | 1 + rootfs/kconfig/OSN_LINUX_PPPOE/etc/ppp/peers | 1 + src/bm/src/bm_client.c | 131 +- src/bm/src/bm_client.h | 23 +- src/bm/src/bm_events.c | 29 +- src/bm/src/bm_events.h | 1 + src/bm/src/bm_group.c | 47 +- src/bm/src/bm_ieee80211.c | 5 + src/bm/src/bm_kick.h | 2 +- src/bm/src/bm_neighbor.c | 3 + src/cm2/fut/cm2_ble_status_interface_down.sh | 97 ++ src/cm2/fut/cm2_ble_status_internet_block.sh | 94 ++ src/cm2/fut/cm2_cloud_down.sh | 92 ++ src/cm2/fut/cm2_dns_failure.sh | 118 ++ src/cm2/fut/cm2_internet_lost.sh | 102 ++ src/cm2/fut/cm2_link_lost.sh | 149 ++ src/cm2/fut/cm2_setup.sh | 47 + src/cm2/fut/cm2_ssl_check.sh | 98 ++ src/cm2/fut/cm2_verify_gre_tunnel_dut_gw.sh | 297 ++++ .../fut/cm2_verify_gre_tunnel_ref_extender.sh | 156 ++ src/cm2/fut/unit.mk | 43 + src/cm2/kconfig/Kconfig.managers | 25 +- src/cm2/src/cm2.h | 78 +- src/cm2/src/cm2_event.c | 112 +- src/cm2/src/cm2_net.c | 29 +- src/cm2/src/cm2_ovsdb.c | 884 ++++++++++-- src/cm2/src/cm2_resolve.c | 8 +- src/cm2/src/cm2_resolve_ares.c | 127 +- src/cm2/src/cm2_resolve_sync.c | 41 +- src/cm2/src/cm2_stability.c | 135 +- src/cm2/src/cm2_stability.h | 49 + src/cpm/inc/captive_portal.h | 52 + src/cpm/kconfig/Kconfig.managers | 32 + src/cpm/src/captive_portal_main.c | 121 ++ src/cpm/src/captive_portal_ovsdb.c | 396 ++++++ src/cpm/src/captive_portal_proxy.c | 406 ++++++ src/cpm/unit.mk | 57 + src/dm/fut/brv_busybox_builtins.sh | 78 + src/dm/fut/brv_is_tool_on_system.sh | 79 ++ src/dm/fut/brv_ovs_correct_version.sh | 68 + src/dm/fut/brv_setup.sh | 38 + src/dm/fut/dm_fetch_managers_startup.sh | 43 + src/dm/fut/dm_setup.sh | 53 + src/dm/fut/onbrd_setup.sh | 47 + src/dm/fut/onbrd_verify_bridge_mode.sh | 145 ++ .../onbrd_verify_client_certificate_files.sh | 84 ++ .../fut/onbrd_verify_client_tls_connection.sh | 80 ++ .../onbrd_verify_device_mode_awlan_node.sh | 77 + .../fut/onbrd_verify_dhcp_dry_run_success.sh | 96 ++ .../onbrd_verify_dut_system_time_accuracy.sh | 93 ++ .../fut/onbrd_verify_fw_version_awlan_node.sh | 90 ++ .../onbrd_verify_home_vaps_on_home_bridge.sh | 94 ++ .../fut/onbrd_verify_home_vaps_on_radios.sh | 83 ++ src/dm/fut/onbrd_verify_id_awlan_node.sh | 67 + .../onbrd_verify_manager_hostname_resolved.sh | 105 ++ src/dm/fut/onbrd_verify_model_awlan_node.sh | 77 + src/dm/fut/onbrd_verify_number_of_radios.sh | 78 + .../fut/onbrd_verify_onbrd_vaps_on_radios.sh | 83 ++ ...rd_verify_redirector_address_awlan_node.sh | 77 + src/dm/fut/onbrd_verify_router_mode.sh | 122 ++ src/dm/fut/onbrd_verify_wan_ip_address.sh | 83 ++ src/dm/fut/unit.mk | 60 + src/dm/src/dm_cli.c | 43 +- src/dm/src/dm_ovsdb.c | 107 +- src/dm/src/dm_reboot.c | 2 +- src/fcm/inc/fcm.h | 1 + src/fcm/inc/fcm_mgr.h | 6 + src/fcm/inc/fcm_priv.h | 19 +- src/fcm/src/fcm_event.c | 173 +++ src/fcm/src/fcm_main.c | 2 + src/fcm/src/fcm_ovsdb.c | 10 +- src/fcm/unit.mk | 2 +- src/fcm/ut/test_fcm_mgr.c | 3 + src/fsm/inc/fsm.h | 46 + src/fsm/inc/fsm_oms.h | 64 + src/fsm/src/fsm_dpi.c | 2 +- src/fsm/src/fsm_main.c | 4 + src/fsm/src/fsm_oms.c | 262 ++++ src/fsm/src/fsm_ovsdb.c | 141 +- src/fsm/src/fsm_service.c | 6 +- src/fsm/unit.mk | 4 +- src/fsm/ut/test_fsm_core.c | 160 ++- src/fsm/ut/unit.mk | 2 + src/fut/shell/config/default_shell.sh | 63 + src/fut/shell/config/empty.sh | 26 + src/fut/shell/config/unit.mk | 35 + src/fut/shell/lib/base_lib.sh | 177 +++ src/fut/shell/lib/brv_lib.sh | 124 ++ src/fut/shell/lib/cm2_lib.sh | 242 ++++ src/fut/shell/lib/dm_lib.sh | 42 + src/fut/shell/lib/ledm_lib.sh | 92 ++ src/fut/shell/lib/nm2_lib.sh | 535 +++++++ src/fut/shell/lib/onbrd_lib.sh | 215 +++ src/fut/shell/lib/qm_lib.sh | 42 + src/fut/shell/lib/rpi_lib.sh | 400 ++++++ src/fut/shell/lib/sm_lib.sh | 366 +++++ src/fut/shell/lib/um_lib.sh | 191 +++ src/fut/shell/lib/unit.mk | 47 + src/fut/shell/lib/unit_lib.sh | 1255 +++++++++++++++++ src/fut/shell/lib/ut_lib.sh | 60 + src/fut/shell/lib/wm2_lib.sh | 892 ++++++++++++ src/fut/shell/tests/ut/unit.mk | 34 + src/fut/shell/tests/ut/ut_setup.sh | 47 + src/fut/shell/tools/device/change_channel.sh | 79 ++ src/fut/shell/tools/device/check_time.sh | 94 ++ .../shell/tools/device/check_wifi_presence.sh | 78 + .../tools/device/connect_to_fut_cloud.sh | 135 ++ .../tools/device/connect_to_fut_cloud_min.sh | 43 + .../tools/device/create_inet_interface.sh | 43 + .../device/create_radio_vif_interface.sh | 46 + src/fut/shell/tools/device/default_setup.sh | 73 + .../shell/tools/device/dut_ref/add_bridge.sh | 46 + .../tools/device/dut_ref/add_bridge_port.sh | 46 + .../shell/tools/device/dut_ref/gre_setup.sh | 88 ++ .../tools/device/dut_ref/initial_setup.sh | 73 + src/fut/shell/tools/device/dut_ref/unit.mk | 37 + src/fut/shell/tools/device/files/fut_ca.pem | 33 + src/fut/shell/tools/device/files/unit.mk | 34 + src/fut/shell/tools/device/genCA.sh | 50 + .../tools/device/get_radio_mac_from_ovsdb.sh | 73 + .../shell/tools/device/man_traffic_address.sh | 46 + .../tools/device/man_traffic_protocol.sh | 49 + .../tools/device/ovsdb/get_ovsdb_value.sh | 54 + src/fut/shell/tools/device/ovsdb/unit.mk | 34 + src/fut/shell/tools/device/start_udhcpc.sh | 45 + src/fut/shell/tools/device/unit.mk | 48 + src/fut/shell/tools/device/vif_clean.sh | 61 + src/fut/shell/tools/device/wm2_setup.sh | 45 + src/fut/shell/tools/rpi/cm/address_dns_man.sh | 63 + .../tools/rpi/cm/address_internet_man.sh | 63 + src/fut/shell/tools/rpi/cm/unit.mk | 35 + src/fut/shell/tools/rpi/connect_to_wpa2.sh | 84 ++ .../shell/tools/rpi/files/fut_controller.pem | 177 +++ src/fut/shell/tools/rpi/files/haproxy.cfg | 39 + .../shell/tools/rpi/files/plume_ca_chain.pem | 275 ++++ src/fut/shell/tools/rpi/files/unit.mk | 36 + .../shell/tools/rpi/start_cloud_simulation.sh | 69 + .../rpi/um/um_create_corrupt_image_file.sh | 53 + .../rpi/um/um_create_corrupt_md5_file.sh | 53 + .../tools/rpi/um/um_create_fw_key_file.sh | 54 + .../shell/tools/rpi/um/um_create_md5_file.sh | 53 + .../shell/tools/rpi/um/um_encrypt_image.sh | 54 + src/fut/shell/tools/rpi/um/unit.mk | 38 + src/fut/shell/tools/rpi/unit.mk | 35 + .../hello_world_insert_demo_fail_to_update.sh | 70 + .../hello_world_insert_demo_fail_to_write.sh | 69 + .../fut/hello_world_insert_foreign_module.sh | 76 + .../hello_world_insert_module_key_value.sh | 70 + src/hello_world/fut/hello_world_setup.sh | 55 + .../hello_world_update_module_key_value.sh | 79 ++ src/hello_world/fut/unit.mk | 39 + src/lib/arp_parse/inc/arp_parse.h | 230 +++ src/lib/arp_parse/src/arp_parse.c | 547 +++++++ .../arp_parse/tests/futs/create_arp_plugin.sh | 148 ++ .../arp_parse/tests/futs/delete_arp_plugin.sh | 50 + src/lib/arp_parse/tests/ut/pcap.c | 60 + src/lib/arp_parse/tests/ut/pkt42.c | 590 ++++++++ src/lib/arp_parse/tests/ut/test_arp_plugin.c | 521 +++++++ src/lib/arp_parse/tests/ut/unit.mk | 41 + src/lib/arp_parse/unit.mk | 56 + .../ct_stats/futs/create_ct_stats_plugin.sh | 361 +++++ .../ct_stats/futs/delete_ct_stats_plugin.sh | 73 + src/lib/ct_stats/src/ct_stats.c | 114 +- src/lib/ct_stats/unit.mk | 1 + src/lib/datapipeline/inc/dpp_client.h | 2 + src/lib/datapipeline/inc/dpp_survey.h | 2 + src/lib/datapipeline/inc/dpp_types.h | 8 + .../datapipeline/inc/opensync_stats.pb-c.h | 71 +- src/lib/datapipeline/src/dppline.c | 38 +- .../datapipeline/src/opensync_stats.pb-c.c | 190 ++- src/lib/dns_parse/inc/dns_parse.h | 36 +- src/lib/dns_parse/src/dns_parse.c | 418 ++++-- .../dns_parse/tests/fut/create_dns_plugin.sh | 29 + .../dns_parse/tests/fut/delete_dns_plugin.sh | 1 + src/lib/dns_parse/tests/ut/test_dns_parse.c | 70 +- src/lib/dns_parse/tests/ut/unit.mk | 2 + src/lib/dns_parse/unit.mk | 1 + src/lib/evx/kconfig/Kconfig.libs | 2 +- src/lib/fcm_filter/src/fcm_report_filter.c | 114 +- src/lib/fsm_policy/inc/fsm_policy.h | 8 +- src/lib/fsm_policy/src/fsm_policy.c | 12 +- src/lib/fsm_policy/src/fsm_policy_client.c | 14 +- src/lib/fsm_policy/src/fsm_policy_ovsdb.c | 23 +- .../ut/fsm_policy/test_fsm_policy.c | 9 +- src/lib/hostap/inc/opensync-hapd.h | 1 + src/lib/hostap/src/hapd.c | 83 +- src/lib/hostap/src/wpas.c | 3 +- src/lib/inet/inc/inet.h | 50 +- src/lib/inet/inc/inet_base.h | 3 +- src/lib/inet/inc/inet_eth.h | 1 + src/lib/inet/inc/inet_pppoe.h | 59 + src/lib/inet/inc/inet_vlan.h | 29 +- src/lib/inet/kconfig/Kconfig.libs | 12 - src/lib/inet/src/inet_base.c | 48 +- src/lib/inet/src/inet_eth.c | 99 +- src/lib/inet/src/inet_pppoe.c | 372 +++++ src/lib/inet/src/inet_vif.c | 6 + src/lib/inet/src/inet_vlan.c | 372 +++++ src/lib/inet/src/linux/inet_gretap.c | 4 +- src/lib/inet/src/linux/inet_vlan.c | 249 ---- src/lib/inet/unit.mk | 8 +- src/lib/intf_stats/inc/interface_stats.pb-c.h | 218 +++ src/lib/intf_stats/inc/intf_stats.h | 174 +++ src/lib/intf_stats/src/interface_stats.pb-c.c | 489 +++++++ src/lib/intf_stats/src/intf_stats.c | 632 +++++++++ src/lib/intf_stats/src/intf_stats_report.c | 831 +++++++++++ src/lib/intf_stats/tests/ut/test_intf_stats.c | 867 ++++++++++++ src/lib/intf_stats/tests/ut/unit.mk | 37 + src/lib/intf_stats/unit.mk | 56 + src/lib/intf_stats/update_proto.sh | 49 + src/lib/ndp_parse/inc/ndp_parse.h | 20 + src/lib/ndp_parse/src/ndp_parse.c | 75 + .../ndp_parse/tests/futs/create_ndp_plugin.sh | 5 + src/lib/neigh_table/inc/neigh_table.h | 10 + src/lib/neigh_table/src/neigh_src_ovsdb.c | 249 +++- src/lib/neigh_table/src/neigh_table.c | 53 + .../ut/neigh_table/test_neigh_table.c | 255 +++- .../inc/network_metadata_report.h | 38 + .../src/network_metadata_utils.c | 236 ++++ .../ut/test_network_metadata_report.c | 14 +- src/lib/objmfs/inc/objmfs.h | 36 + src/lib/objmfs/kconfig/Kconfig | 21 + src/lib/objmfs/src/objmfs.c | 196 +++ src/lib/objmfs/unit.mk | 42 + src/lib/oms/inc/object_manager.pb-c.h | 172 +++ src/lib/oms/inc/oms.h | 207 +++ src/lib/oms/inc/oms_report.h | 71 + src/lib/oms/src/object_manager.pb-c.c | 349 +++++ src/lib/oms/src/oms.c | 260 ++++ src/lib/oms/src/oms_ovsdb.c | 723 ++++++++++ src/lib/oms/src/oms_report.c | 606 ++++++++ src/lib/oms/unit.mk | 50 + src/lib/oms/update_proto.sh | 49 + src/lib/oms/ut/test_oms.c | 844 +++++++++++ src/lib/oms/ut/unit.mk | 47 + src/lib/osa/inc/os_backtrace.h | 2 +- src/lib/osa/src/os_nif_linux.c | 7 +- src/lib/osn/inc/osn_dhcp.h | 2 - src/lib/osn/inc/osn_dhcpv6.h | 2 +- src/lib/osn/inc/osn_fw.h | 3 +- src/lib/osn/inc/osn_inet.h | 2 +- src/lib/osn/inc/osn_inet6.h | 2 +- src/lib/osn/inc/osn_netif.h | 4 +- src/lib/osn/inc/osn_pppoe.h | 211 +++ src/lib/osn/inc/osn_types.h | 13 +- src/lib/osn/inc/osn_upnp.h | 2 +- src/lib/osn/inc/osn_vlan.h | 144 ++ src/lib/osn/kconfig/Kconfig.osn | 15 + src/lib/osn/kconfig/Kconfig.osn.pppoe_backend | 13 + src/lib/osn/kconfig/Kconfig.osn.vlan_backend | 14 + src/lib/osn/src/linux/lnx_ip.c | 22 +- src/lib/osn/src/linux/lnx_ip.h | 13 +- src/lib/osn/src/linux/lnx_netif.c | 28 +- src/lib/osn/src/linux/lnx_netlink.c | 6 + src/lib/osn/src/linux/lnx_pppoe.c | 481 +++++++ src/lib/osn/src/linux/lnx_pppoe.h | 62 + src/lib/osn/src/linux/lnx_vlan.c | 155 ++ src/lib/osn/src/linux/lnx_vlan.h | 51 + src/lib/osn/src/osn_pppoe_linux.c | 120 ++ src/lib/osn/src/osn_pppoe_null.c | 97 ++ src/lib/osn/src/osn_types.c | 27 + src/lib/osn/src/osn_vlan_linux.c | 86 ++ src/lib/osn/src/osn_vlan_null.c | 77 + src/lib/osn/unit.mk | 8 + src/lib/osp/inc/osp.h | 291 +--- src/lib/osp/inc/osp_btn.h | 146 ++ src/lib/osp/inc/osp_dl.h | 87 ++ src/lib/osp/inc/osp_l2switch.h | 2 +- src/lib/osp/inc/osp_objm.h | 90 ++ src/lib/osp/inc/osp_ps.h | 23 + src/lib/osp/inc/osp_reboot.h | 116 ++ src/lib/osp/inc/osp_tm.h | 2 +- src/lib/osp/inc/osp_unit.h | 226 +++ src/lib/osp/inc/osp_upg.h | 131 ++ src/lib/osp/kconfig/Kconfig.osp_objm | 3 + src/lib/osp/kconfig/Kconfig.osp_objm.backend | 5 + src/lib/osp/kconfig/Kconfig.osp_unit.backend | 5 + src/lib/osp/src/osp_led.c | 2 +- src/lib/osp/src/osp_objm_objmfs.c | 49 + src/lib/osp/src/osp_ps_psfs.c | 7 +- src/lib/osp/src/osp_reboot_pstore.c | 2 +- src/lib/osp/src/osp_unit_default.c | 146 ++ src/lib/osp/unit.mk | 8 +- src/lib/ovs_mac_learn/inc/ovs_mac_learn.h | 35 +- src/lib/ovs_mac_learn/src/ovs_mac_learn.c | 106 +- src/lib/policy_tags/inc/policy_tags.h | 32 +- src/lib/policy_tags/src/policy_tag_groups.c | 5 + src/lib/policy_tags/src/policy_tag_list.c | 3 + src/lib/policy_tags/src/policy_tag_utils.c | 71 + src/lib/policy_tags/src/policy_tags.c | 106 ++ src/lib/policy_tags/ut/test_schema_tags.c | 65 + src/lib/psfs/inc/psfs.h | 1 + src/lib/psfs/src/psfs.c | 49 +- src/lib/stam/README.md | 489 +++++++ src/lib/stam/devtest/stamtest.c | 160 +++ src/lib/stam/devtest/test.dot | 11 + src/lib/stam/devtest/unit.mk | 35 + src/lib/stam/inc/stam.h | 440 ++++++ src/lib/stam/inc/stam_gen.h | 50 + src/lib/stam/src/stam.c | 61 + src/lib/stam/tools/libstam_gen.py | 300 ++++ src/lib/stam/unit.mk | 33 + src/lib/target/inc/target.h | 123 +- src/lib/target/inc/target_common.h | 165 +-- src/lib/target/kconfig/Kconfig | 75 +- src/lib/target/src/target_kconfig.c | 310 ++-- src/lib/target/src/target_native.c | 48 - src/lib/target/src/target_stub.c | 176 +-- src/lib/unity/inc/unity.h | 334 ++++- src/lib/unity/inc/unity_internals.h | 412 ++++-- src/lib/unity/src/unity.c | 946 ++++++++++--- src/lib/unity/unit.mk | 2 + .../tests/fut/create_wc_null_plugin.sh | 31 +- src/lm/src/lm_ovsdb.c | 3 +- src/nfm/src/nfm_trule.c | 8 +- .../fut/nm2_configure_nonexistent_iface.sh | 137 ++ .../fut/nm2_enable_disable_iface_network.sh | 146 ++ .../nm2_ovsdb_configure_interface_dhcpd.sh | 175 +++ src/nm2/fut/nm2_ovsdb_ip_port_forward.sh | 126 ++ .../fut/nm2_ovsdb_remove_reinsert_iface.sh | 154 ++ .../nm2_rapid_multiple_insert_delete_iface.sh | 112 ++ ..._rapid_multiple_insert_delete_ovsdb_row.sh | 117 ++ src/nm2/fut/nm2_set_broadcast.sh | 127 ++ src/nm2/fut/nm2_set_dns.sh | 106 ++ src/nm2/fut/nm2_set_gateway.sh | 131 ++ src/nm2/fut/nm2_set_inet_addr.sh | 123 ++ src/nm2/fut/nm2_set_ip_assign_scheme.sh | 157 +++ src/nm2/fut/nm2_set_mtu.sh | 124 ++ src/nm2/fut/nm2_set_nat.sh | 138 ++ src/nm2/fut/nm2_set_netmask.sh | 110 ++ src/nm2/fut/nm2_set_parent_ifname.sh | 133 ++ src/nm2/fut/nm2_set_upnp_mode.sh | 140 ++ src/nm2/fut/nm2_set_vlan_id.sh | 133 ++ src/nm2/fut/nm2_setup.sh | 47 + src/nm2/fut/unit.mk | 52 + src/nm2/inc/nm2_iface.h | 5 +- src/nm2/src/nm2_iface.c | 33 +- src/nm2/src/nm2_inet_config.c | 35 +- src/nm2/src/nm2_port.c | 3 +- src/om/src/om_monitor.c | 66 +- src/om/src/om_template.c | 2 +- src/om/src/om_tflows.c | 7 +- src/pm/inc/pm.h | 1 + src/pm/inc/pm_objm.h | 62 + src/pm/inc/pm_objm_pjs.h | 53 + src/pm/inc/pm_tm.h | 3 +- src/pm/kconfig/Kconfig.managers | 28 + src/pm/src/pm_client_freeze.c | 3 +- src/pm/src/pm_client_nickname.c | 1 - src/pm/src/pm_gw_offline_cfg.c | 1016 +++++++++++++ src/pm/src/pm_led.c | 3 +- src/pm/src/pm_lm.c | 13 +- src/pm/src/pm_main.c | 15 + src/pm/src/pm_objm.c | 849 +++++++++++ src/pm/src/pm_tm.c | 5 +- src/pm/unit.mk | 12 +- src/qm/src/qm_mqtt.c | 3 +- src/sm/fut/sm_inspect_leaf_report.sh | 103 ++ src/sm/fut/sm_inspect_neighbor_report.sh | 115 ++ src/sm/fut/sm_inspect_survey_report.sh | 108 ++ src/sm/fut/sm_setup.sh | 47 + src/sm/fut/unit.mk | 37 + src/sm/src/sm_mqtt.c | 7 +- src/sm/src/sm_survey_report.c | 8 +- src/tools/osps/src/osps_main.c | 70 + src/tools/preboot/src/preboot.c | 2 +- src/um/fut/um_corrupt_image.sh | 109 ++ src/um/fut/um_corrupt_md5_sum.sh | 99 ++ src/um/fut/um_missing_md5_sum.sh | 99 ++ src/um/fut/um_set_correct_firmware_pass.sh | 102 ++ src/um/fut/um_set_firmware_url.sh | 108 ++ src/um/fut/um_set_invalid_firmware_pass.sh | 110 ++ src/um/fut/um_set_invalid_firmware_url.sh | 91 ++ src/um/fut/um_set_upgrade_dl_timer.sh | 103 ++ src/um/fut/um_set_upgrade_timer.sh | 130 ++ src/um/fut/um_setup.sh | 47 + src/um/fut/unit.mk | 43 + src/um/src/um_ovsdb.c | 4 +- src/wano/inc/wano.h | 478 +++++++ src/wano/inc/wano_localconfig.h | 36 + src/wano/inc/wano_localconfig.pjs.h | 60 + src/wano/kconfig/Kconfig.managers | 67 + src/wano/src/wano_connection_manager_uplink.c | 104 ++ src/wano/src/wano_inet_config.c | 136 ++ src/wano/src/wano_inet_state.c | 394 ++++++ src/wano/src/wano_internal.h | 43 + src/wano/src/wano_localconfig.c | 110 ++ src/wano/src/wano_main.c | 162 +++ src/wano/src/wano_plugin.c | 150 ++ src/wano/src/wano_ppline.c | 885 ++++++++++++ src/wano/src/wano_ppline.dot | 20 + src/wano/src/wanp_dhcpv4.c | 255 ++++ src/wano/src/wanp_dhcpv4.dot | 12 + src/wano/src/wanp_dhcpv6.c | 379 +++++ src/wano/src/wanp_dhcpv6.dot | 5 + src/wano/src/wanp_pppoe.c | 374 +++++ src/wano/src/wanp_pppoe.dot | 13 + src/wano/src/wanp_static_ipv4.c | 480 +++++++ src/wano/src/wanp_static_ipv4.dot | 13 + src/wano/src/wanp_vlan.c | 390 +++++ src/wano/src/wanp_vlan.dot | 9 + src/wano/unit.mk | 89 ++ src/wm2/fut/unit.mk | 50 + src/wm2/fut/wm2_dfs_cac_aborted.sh | 182 +++ .../fut/wm2_ht_mode_and_channel_iteration.sh | 162 +++ src/wm2/fut/wm2_immutable_radio_freq_band.sh | 159 +++ src/wm2/fut/wm2_immutable_radio_hw_mode.sh | 159 +++ src/wm2/fut/wm2_immutable_radio_hw_type.sh | 158 +++ src/wm2/fut/wm2_immutable_radio_if_name.sh | 155 ++ src/wm2/fut/wm2_set_bcn_int.sh | 147 ++ src/wm2/fut/wm2_set_channel.sh | 156 ++ src/wm2/fut/wm2_set_ht_mode.sh | 145 ++ src/wm2/fut/wm2_set_radio_country.sh | 141 ++ src/wm2/fut/wm2_set_radio_enabled.sh | 157 +++ src/wm2/fut/wm2_set_radio_fallback_parents.sh | 152 ++ .../fut/wm2_set_radio_thermal_tx_chainmask.sh | 186 +++ src/wm2/fut/wm2_set_radio_tx_chainmask.sh | 162 +++ src/wm2/fut/wm2_set_radio_tx_power.sh | 157 +++ src/wm2/fut/wm2_set_radio_vif_configs.sh | 160 +++ src/wm2/fut/wm2_setup.sh | 47 + src/wm2/src/wm2.h | 18 - src/wm2/src/wm2_clients.c | 32 +- src/wm2/src/wm2_radio.c | 79 +- src/wm2/src/wm2_radio1.c | 1196 ---------------- src/wm2/tests/unit.mk | 1 - src/wm2/unit.mk | 1 - 448 files changed, 47907 insertions(+), 3798 deletions(-) create mode 100644 build/fut.mk create mode 100644 build/stam.mk create mode 100644 interfaces/interface_stats.proto create mode 100644 interfaces/object_manager.proto create mode 100644 kconfig/Kconfig.osn.pppoe_backend create mode 100644 kconfig/Kconfig.osn.vlan_backend create mode 100644 kconfig/Kconfig.osp_objm create mode 100644 kconfig/Kconfig.osp_objm.backend create mode 100644 kconfig/Kconfig.osp_unit.backend create mode 120000 rootfs/kconfig/OSN_LINUX_PPPOE/etc/ppp/chap-secrets create mode 100755 rootfs/kconfig/OSN_LINUX_PPPOE/etc/ppp/ip-down.jinja create mode 100755 rootfs/kconfig/OSN_LINUX_PPPOE/etc/ppp/ip-up.jinja create mode 120000 rootfs/kconfig/OSN_LINUX_PPPOE/etc/ppp/pap-secrets create mode 120000 rootfs/kconfig/OSN_LINUX_PPPOE/etc/ppp/peers create mode 100755 src/cm2/fut/cm2_ble_status_interface_down.sh create mode 100755 src/cm2/fut/cm2_ble_status_internet_block.sh create mode 100755 src/cm2/fut/cm2_cloud_down.sh create mode 100755 src/cm2/fut/cm2_dns_failure.sh create mode 100755 src/cm2/fut/cm2_internet_lost.sh create mode 100755 src/cm2/fut/cm2_link_lost.sh create mode 100755 src/cm2/fut/cm2_setup.sh create mode 100755 src/cm2/fut/cm2_ssl_check.sh create mode 100755 src/cm2/fut/cm2_verify_gre_tunnel_dut_gw.sh create mode 100755 src/cm2/fut/cm2_verify_gre_tunnel_ref_extender.sh create mode 100644 src/cm2/fut/unit.mk create mode 100644 src/cm2/src/cm2_stability.h create mode 100644 src/cpm/inc/captive_portal.h create mode 100644 src/cpm/kconfig/Kconfig.managers create mode 100644 src/cpm/src/captive_portal_main.c create mode 100644 src/cpm/src/captive_portal_ovsdb.c create mode 100644 src/cpm/src/captive_portal_proxy.c create mode 100644 src/cpm/unit.mk create mode 100755 src/dm/fut/brv_busybox_builtins.sh create mode 100755 src/dm/fut/brv_is_tool_on_system.sh create mode 100755 src/dm/fut/brv_ovs_correct_version.sh create mode 100755 src/dm/fut/brv_setup.sh create mode 100755 src/dm/fut/dm_fetch_managers_startup.sh create mode 100755 src/dm/fut/dm_setup.sh create mode 100755 src/dm/fut/onbrd_setup.sh create mode 100755 src/dm/fut/onbrd_verify_bridge_mode.sh create mode 100755 src/dm/fut/onbrd_verify_client_certificate_files.sh create mode 100755 src/dm/fut/onbrd_verify_client_tls_connection.sh create mode 100755 src/dm/fut/onbrd_verify_device_mode_awlan_node.sh create mode 100755 src/dm/fut/onbrd_verify_dhcp_dry_run_success.sh create mode 100755 src/dm/fut/onbrd_verify_dut_system_time_accuracy.sh create mode 100755 src/dm/fut/onbrd_verify_fw_version_awlan_node.sh create mode 100755 src/dm/fut/onbrd_verify_home_vaps_on_home_bridge.sh create mode 100755 src/dm/fut/onbrd_verify_home_vaps_on_radios.sh create mode 100755 src/dm/fut/onbrd_verify_id_awlan_node.sh create mode 100755 src/dm/fut/onbrd_verify_manager_hostname_resolved.sh create mode 100755 src/dm/fut/onbrd_verify_model_awlan_node.sh create mode 100755 src/dm/fut/onbrd_verify_number_of_radios.sh create mode 100755 src/dm/fut/onbrd_verify_onbrd_vaps_on_radios.sh create mode 100755 src/dm/fut/onbrd_verify_redirector_address_awlan_node.sh create mode 100755 src/dm/fut/onbrd_verify_router_mode.sh create mode 100755 src/dm/fut/onbrd_verify_wan_ip_address.sh create mode 100644 src/dm/fut/unit.mk create mode 100644 src/fcm/src/fcm_event.c create mode 100644 src/fsm/inc/fsm_oms.h create mode 100644 src/fsm/src/fsm_oms.c create mode 100755 src/fut/shell/config/default_shell.sh create mode 100755 src/fut/shell/config/empty.sh create mode 100644 src/fut/shell/config/unit.mk create mode 100755 src/fut/shell/lib/base_lib.sh create mode 100755 src/fut/shell/lib/brv_lib.sh create mode 100755 src/fut/shell/lib/cm2_lib.sh create mode 100755 src/fut/shell/lib/dm_lib.sh create mode 100755 src/fut/shell/lib/ledm_lib.sh create mode 100755 src/fut/shell/lib/nm2_lib.sh create mode 100755 src/fut/shell/lib/onbrd_lib.sh create mode 100755 src/fut/shell/lib/qm_lib.sh create mode 100755 src/fut/shell/lib/rpi_lib.sh create mode 100755 src/fut/shell/lib/sm_lib.sh create mode 100755 src/fut/shell/lib/um_lib.sh create mode 100644 src/fut/shell/lib/unit.mk create mode 100755 src/fut/shell/lib/unit_lib.sh create mode 100755 src/fut/shell/lib/ut_lib.sh create mode 100755 src/fut/shell/lib/wm2_lib.sh create mode 100644 src/fut/shell/tests/ut/unit.mk create mode 100755 src/fut/shell/tests/ut/ut_setup.sh create mode 100755 src/fut/shell/tools/device/change_channel.sh create mode 100755 src/fut/shell/tools/device/check_time.sh create mode 100755 src/fut/shell/tools/device/check_wifi_presence.sh create mode 100755 src/fut/shell/tools/device/connect_to_fut_cloud.sh create mode 100755 src/fut/shell/tools/device/connect_to_fut_cloud_min.sh create mode 100755 src/fut/shell/tools/device/create_inet_interface.sh create mode 100755 src/fut/shell/tools/device/create_radio_vif_interface.sh create mode 100755 src/fut/shell/tools/device/default_setup.sh create mode 100755 src/fut/shell/tools/device/dut_ref/add_bridge.sh create mode 100755 src/fut/shell/tools/device/dut_ref/add_bridge_port.sh create mode 100755 src/fut/shell/tools/device/dut_ref/gre_setup.sh create mode 100755 src/fut/shell/tools/device/dut_ref/initial_setup.sh create mode 100644 src/fut/shell/tools/device/dut_ref/unit.mk create mode 100644 src/fut/shell/tools/device/files/fut_ca.pem create mode 100644 src/fut/shell/tools/device/files/unit.mk create mode 100755 src/fut/shell/tools/device/genCA.sh create mode 100755 src/fut/shell/tools/device/get_radio_mac_from_ovsdb.sh create mode 100755 src/fut/shell/tools/device/man_traffic_address.sh create mode 100755 src/fut/shell/tools/device/man_traffic_protocol.sh create mode 100755 src/fut/shell/tools/device/ovsdb/get_ovsdb_value.sh create mode 100644 src/fut/shell/tools/device/ovsdb/unit.mk create mode 100755 src/fut/shell/tools/device/start_udhcpc.sh create mode 100644 src/fut/shell/tools/device/unit.mk create mode 100755 src/fut/shell/tools/device/vif_clean.sh create mode 100755 src/fut/shell/tools/device/wm2_setup.sh create mode 100755 src/fut/shell/tools/rpi/cm/address_dns_man.sh create mode 100755 src/fut/shell/tools/rpi/cm/address_internet_man.sh create mode 100644 src/fut/shell/tools/rpi/cm/unit.mk create mode 100755 src/fut/shell/tools/rpi/connect_to_wpa2.sh create mode 100644 src/fut/shell/tools/rpi/files/fut_controller.pem create mode 100644 src/fut/shell/tools/rpi/files/haproxy.cfg create mode 100644 src/fut/shell/tools/rpi/files/plume_ca_chain.pem create mode 100644 src/fut/shell/tools/rpi/files/unit.mk create mode 100755 src/fut/shell/tools/rpi/start_cloud_simulation.sh create mode 100755 src/fut/shell/tools/rpi/um/um_create_corrupt_image_file.sh create mode 100755 src/fut/shell/tools/rpi/um/um_create_corrupt_md5_file.sh create mode 100755 src/fut/shell/tools/rpi/um/um_create_fw_key_file.sh create mode 100755 src/fut/shell/tools/rpi/um/um_create_md5_file.sh create mode 100755 src/fut/shell/tools/rpi/um/um_encrypt_image.sh create mode 100644 src/fut/shell/tools/rpi/um/unit.mk create mode 100644 src/fut/shell/tools/rpi/unit.mk create mode 100755 src/hello_world/fut/hello_world_insert_demo_fail_to_update.sh create mode 100755 src/hello_world/fut/hello_world_insert_demo_fail_to_write.sh create mode 100755 src/hello_world/fut/hello_world_insert_foreign_module.sh create mode 100755 src/hello_world/fut/hello_world_insert_module_key_value.sh create mode 100755 src/hello_world/fut/hello_world_setup.sh create mode 100755 src/hello_world/fut/hello_world_update_module_key_value.sh create mode 100644 src/hello_world/fut/unit.mk create mode 100644 src/lib/arp_parse/inc/arp_parse.h create mode 100644 src/lib/arp_parse/src/arp_parse.c create mode 100755 src/lib/arp_parse/tests/futs/create_arp_plugin.sh create mode 100755 src/lib/arp_parse/tests/futs/delete_arp_plugin.sh create mode 100644 src/lib/arp_parse/tests/ut/pcap.c create mode 100644 src/lib/arp_parse/tests/ut/pkt42.c create mode 100644 src/lib/arp_parse/tests/ut/test_arp_plugin.c create mode 100644 src/lib/arp_parse/tests/ut/unit.mk create mode 100644 src/lib/arp_parse/unit.mk create mode 100755 src/lib/ct_stats/futs/create_ct_stats_plugin.sh create mode 100755 src/lib/ct_stats/futs/delete_ct_stats_plugin.sh create mode 100644 src/lib/inet/inc/inet_pppoe.h create mode 100644 src/lib/inet/src/inet_pppoe.c create mode 100644 src/lib/inet/src/inet_vlan.c delete mode 100644 src/lib/inet/src/linux/inet_vlan.c create mode 100644 src/lib/intf_stats/inc/interface_stats.pb-c.h create mode 100644 src/lib/intf_stats/inc/intf_stats.h create mode 100644 src/lib/intf_stats/src/interface_stats.pb-c.c create mode 100644 src/lib/intf_stats/src/intf_stats.c create mode 100644 src/lib/intf_stats/src/intf_stats_report.c create mode 100644 src/lib/intf_stats/tests/ut/test_intf_stats.c create mode 100644 src/lib/intf_stats/tests/ut/unit.mk create mode 100644 src/lib/intf_stats/unit.mk create mode 100755 src/lib/intf_stats/update_proto.sh create mode 100644 src/lib/objmfs/inc/objmfs.h create mode 100644 src/lib/objmfs/kconfig/Kconfig create mode 100644 src/lib/objmfs/src/objmfs.c create mode 100644 src/lib/objmfs/unit.mk create mode 100644 src/lib/oms/inc/object_manager.pb-c.h create mode 100644 src/lib/oms/inc/oms.h create mode 100644 src/lib/oms/inc/oms_report.h create mode 100644 src/lib/oms/src/object_manager.pb-c.c create mode 100644 src/lib/oms/src/oms.c create mode 100644 src/lib/oms/src/oms_ovsdb.c create mode 100644 src/lib/oms/src/oms_report.c create mode 100644 src/lib/oms/unit.mk create mode 100755 src/lib/oms/update_proto.sh create mode 100644 src/lib/oms/ut/test_oms.c create mode 100644 src/lib/oms/ut/unit.mk create mode 100644 src/lib/osn/inc/osn_pppoe.h create mode 100644 src/lib/osn/inc/osn_vlan.h create mode 100644 src/lib/osn/kconfig/Kconfig.osn.pppoe_backend create mode 100644 src/lib/osn/kconfig/Kconfig.osn.vlan_backend create mode 100644 src/lib/osn/src/linux/lnx_pppoe.c create mode 100644 src/lib/osn/src/linux/lnx_pppoe.h create mode 100644 src/lib/osn/src/linux/lnx_vlan.c create mode 100644 src/lib/osn/src/linux/lnx_vlan.h create mode 100644 src/lib/osn/src/osn_pppoe_linux.c create mode 100644 src/lib/osn/src/osn_pppoe_null.c create mode 100644 src/lib/osn/src/osn_vlan_linux.c create mode 100644 src/lib/osn/src/osn_vlan_null.c create mode 100644 src/lib/osp/inc/osp_btn.h create mode 100644 src/lib/osp/inc/osp_dl.h create mode 100644 src/lib/osp/inc/osp_objm.h create mode 100644 src/lib/osp/inc/osp_reboot.h create mode 100644 src/lib/osp/inc/osp_unit.h create mode 100644 src/lib/osp/inc/osp_upg.h create mode 100644 src/lib/osp/kconfig/Kconfig.osp_objm create mode 100644 src/lib/osp/kconfig/Kconfig.osp_objm.backend create mode 100644 src/lib/osp/kconfig/Kconfig.osp_unit.backend create mode 100644 src/lib/osp/src/osp_objm_objmfs.c create mode 100644 src/lib/osp/src/osp_unit_default.c create mode 100644 src/lib/stam/README.md create mode 100644 src/lib/stam/devtest/stamtest.c create mode 100644 src/lib/stam/devtest/test.dot create mode 100644 src/lib/stam/devtest/unit.mk create mode 100644 src/lib/stam/inc/stam.h create mode 100644 src/lib/stam/inc/stam_gen.h create mode 100644 src/lib/stam/src/stam.c create mode 100755 src/lib/stam/tools/libstam_gen.py create mode 100644 src/lib/stam/unit.mk create mode 100755 src/nm2/fut/nm2_configure_nonexistent_iface.sh create mode 100755 src/nm2/fut/nm2_enable_disable_iface_network.sh create mode 100755 src/nm2/fut/nm2_ovsdb_configure_interface_dhcpd.sh create mode 100755 src/nm2/fut/nm2_ovsdb_ip_port_forward.sh create mode 100755 src/nm2/fut/nm2_ovsdb_remove_reinsert_iface.sh create mode 100755 src/nm2/fut/nm2_rapid_multiple_insert_delete_iface.sh create mode 100755 src/nm2/fut/nm2_rapid_multiple_insert_delete_ovsdb_row.sh create mode 100755 src/nm2/fut/nm2_set_broadcast.sh create mode 100755 src/nm2/fut/nm2_set_dns.sh create mode 100755 src/nm2/fut/nm2_set_gateway.sh create mode 100755 src/nm2/fut/nm2_set_inet_addr.sh create mode 100755 src/nm2/fut/nm2_set_ip_assign_scheme.sh create mode 100755 src/nm2/fut/nm2_set_mtu.sh create mode 100755 src/nm2/fut/nm2_set_nat.sh create mode 100755 src/nm2/fut/nm2_set_netmask.sh create mode 100755 src/nm2/fut/nm2_set_parent_ifname.sh create mode 100755 src/nm2/fut/nm2_set_upnp_mode.sh create mode 100755 src/nm2/fut/nm2_set_vlan_id.sh create mode 100755 src/nm2/fut/nm2_setup.sh create mode 100644 src/nm2/fut/unit.mk create mode 100644 src/pm/inc/pm_objm.h create mode 100644 src/pm/inc/pm_objm_pjs.h create mode 100644 src/pm/src/pm_gw_offline_cfg.c create mode 100644 src/pm/src/pm_objm.c create mode 100755 src/sm/fut/sm_inspect_leaf_report.sh create mode 100755 src/sm/fut/sm_inspect_neighbor_report.sh create mode 100755 src/sm/fut/sm_inspect_survey_report.sh create mode 100755 src/sm/fut/sm_setup.sh create mode 100644 src/sm/fut/unit.mk create mode 100755 src/um/fut/um_corrupt_image.sh create mode 100755 src/um/fut/um_corrupt_md5_sum.sh create mode 100755 src/um/fut/um_missing_md5_sum.sh create mode 100755 src/um/fut/um_set_correct_firmware_pass.sh create mode 100755 src/um/fut/um_set_firmware_url.sh create mode 100755 src/um/fut/um_set_invalid_firmware_pass.sh create mode 100755 src/um/fut/um_set_invalid_firmware_url.sh create mode 100755 src/um/fut/um_set_upgrade_dl_timer.sh create mode 100755 src/um/fut/um_set_upgrade_timer.sh create mode 100755 src/um/fut/um_setup.sh create mode 100644 src/um/fut/unit.mk create mode 100644 src/wano/inc/wano.h create mode 100644 src/wano/inc/wano_localconfig.h create mode 100644 src/wano/inc/wano_localconfig.pjs.h create mode 100644 src/wano/kconfig/Kconfig.managers create mode 100644 src/wano/src/wano_connection_manager_uplink.c create mode 100644 src/wano/src/wano_inet_config.c create mode 100644 src/wano/src/wano_inet_state.c create mode 100644 src/wano/src/wano_internal.h create mode 100644 src/wano/src/wano_localconfig.c create mode 100644 src/wano/src/wano_main.c create mode 100644 src/wano/src/wano_plugin.c create mode 100644 src/wano/src/wano_ppline.c create mode 100644 src/wano/src/wano_ppline.dot create mode 100644 src/wano/src/wanp_dhcpv4.c create mode 100644 src/wano/src/wanp_dhcpv4.dot create mode 100644 src/wano/src/wanp_dhcpv6.c create mode 100644 src/wano/src/wanp_dhcpv6.dot create mode 100644 src/wano/src/wanp_pppoe.c create mode 100644 src/wano/src/wanp_pppoe.dot create mode 100644 src/wano/src/wanp_static_ipv4.c create mode 100644 src/wano/src/wanp_static_ipv4.dot create mode 100644 src/wano/src/wanp_vlan.c create mode 100644 src/wano/src/wanp_vlan.dot create mode 100644 src/wano/unit.mk create mode 100644 src/wm2/fut/unit.mk create mode 100755 src/wm2/fut/wm2_dfs_cac_aborted.sh create mode 100755 src/wm2/fut/wm2_ht_mode_and_channel_iteration.sh create mode 100755 src/wm2/fut/wm2_immutable_radio_freq_band.sh create mode 100755 src/wm2/fut/wm2_immutable_radio_hw_mode.sh create mode 100755 src/wm2/fut/wm2_immutable_radio_hw_type.sh create mode 100755 src/wm2/fut/wm2_immutable_radio_if_name.sh create mode 100755 src/wm2/fut/wm2_set_bcn_int.sh create mode 100755 src/wm2/fut/wm2_set_channel.sh create mode 100755 src/wm2/fut/wm2_set_ht_mode.sh create mode 100755 src/wm2/fut/wm2_set_radio_country.sh create mode 100755 src/wm2/fut/wm2_set_radio_enabled.sh create mode 100755 src/wm2/fut/wm2_set_radio_fallback_parents.sh create mode 100755 src/wm2/fut/wm2_set_radio_thermal_tx_chainmask.sh create mode 100755 src/wm2/fut/wm2_set_radio_tx_chainmask.sh create mode 100755 src/wm2/fut/wm2_set_radio_tx_power.sh create mode 100755 src/wm2/fut/wm2_set_radio_vif_configs.sh create mode 100755 src/wm2/fut/wm2_setup.sh delete mode 100644 src/wm2/src/wm2_radio1.c diff --git a/.version b/.version index 51f600d8..0d04db05 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.0.7.0 +2.2.0.0 diff --git a/Makefile b/Makefile index 976496a4..f2023d43 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ include build/dirs.mk include build/verbose.mk include build/version.mk include build/git.mk +include build/stam.mk include build/unit-build.mk include build/tags.mk include build/app_install.mk @@ -74,8 +75,9 @@ include build/schema.mk include build/devshell.mk include build/help.mk include build/doc.mk +include build/fut.mk -build_all: workdirs schema-check unit-install +build_all: workdirs schema-check unit-install fut clean: $(NQ) " $(call color_clean,clean) [$(call COLOR_BOLD,workdir)] $(WORKDIR)" diff --git a/build/dirs.mk b/build/dirs.mk index c3f05c22..a5cbe619 100644 --- a/build/dirs.mk +++ b/build/dirs.mk @@ -26,6 +26,7 @@ SRCDIR = src OBJDIR = $(WORKDIR)/obj BINDIR = $(WORKDIR)/bin LIBDIR = $(WORKDIR)/lib +FUTDIR = $(WORKDIR)/fut BUILD_ROOTFS_DIR ?= $(WORKDIR)/rootfs APP_ROOTFS ?= $(BUILD_ROOTFS_DIR) IMAGEDIR = images diff --git a/build/fut.mk b/build/fut.mk new file mode 100644 index 00000000..884de958 --- /dev/null +++ b/build/fut.mk @@ -0,0 +1,43 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +FUT_PACK_NAME := $(TARGET)-$(shell $(call version-gen,make)) +FUT_PACK_FILENAME := fut-$(FUT_PACK_NAME).tar.bz2 +FUT_PACK_PATHNAME ?= $(IMAGEDIR)/$(FUT_PACK_FILENAME) + +.PHONY: fut-store + +fut-clean: + $(NQ) "$(call color_install,clean) $(call color_profile,$(FUTDIR))" + $(Q)rm -rf $(FUTDIR) + +fut-store: + $(NQ) "$(call color_install, create) $(FUT_PACK_FILENAME)" + $(Q)$(TAR) -cjf $(FUT_PACK_PATHNAME) -C $(dir $(FUTDIR)) $(notdir $(FUTDIR)) + +fut-make: $(UNIT_ALL_FUT_UNITS) + +fut: fut-clean + $(Q)$(MAKE) fut-make + $(Q)$(MAKE) fut-store diff --git a/build/stam.mk b/build/stam.mk new file mode 100644 index 00000000..da642eb7 --- /dev/null +++ b/build/stam.mk @@ -0,0 +1,69 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +define _stam_generate + $(if $(filter "$(STAM_NAME)",""),$(error Please define STAM_NAME before using stam generator)) + $(if $(filter "$(STAM_DOT_FILE)",""),$(error Please define STAM_DOT_FILE before using stam generator)) + $(if $(filter "$(STAM_DEST_DIR)",""),$(error Please define STAM_DEST_DIR before using stam generator)) + + $(NQ) " $(call color_generate,stam)[$(call COLOR_BOLD,$(STAM_NAME))] $@" + $(Q) src/lib/stam/tools/libstam_gen.py $(STAM_DOT_FILE) $(1) --file --dest $(STAM_DEST_DIR) $(EXTRA_OPTS) \ + $(if $(filter "$(STAM_DISABLE_ACTIONS_CHECKS)","y"),--disable-actions-checks) \ + $(if $(filter "$(STAM_DISABLE_TRANSITIONS_CHECKS)","y"),--disable-transitions-checks) +endef + +define stam_generate_source + $(call _stam_generate,--source) +endef + +define stam_generate_header + $(call _stam_generate,--header) +endef + +define stam_generate +$(call stam_generate2,$(1),$(basename $(notdir $(1)))) +endef + +define stam_generate2 + +UNIT_PRE += $(UNIT_BUILD)/$(2)_stam.h +UNIT_PRE += $(UNIT_BUILD)/$(2)_stam.c +UNIT_SRC_TOP += $(UNIT_BUILD)/$(2)_stam.c + +UNIT_CFLAGS += -I$(UNIT_BUILD) + +UNIT_CLEAN += $(UNIT_BUILD)/$(2)_stam.h +UNIT_CLEAN += $(UNIT_BUILD)/$(2)_stam.c + +UNIT_DEPS += src/lib/stam + +$(UNIT_BUILD)/$(2)_stam.h: $(UNIT_PATH)/$(1) + $(NQ) " $(call color_generate,stam_h) [$(call COLOR_BOLD,$(2))] $$@" + $(Q) src/lib/stam/tools/libstam_gen.py $(UNIT_PATH)/$(1) --file --dest "$(UNIT_BUILD)" --header + +$(UNIT_BUILD)/$(2)_stam.c: $(UNIT_PATH)/$(1) + $(NQ) " $(call color_generate,stam_c) [$(call COLOR_BOLD,$(2))] $$@" + $(Q) src/lib/stam/tools/libstam_gen.py $(UNIT_PATH)/$(1) --file --dest "$(UNIT_BUILD)" --source + +endef diff --git a/build/unit-build.mk b/build/unit-build.mk index f4085c09..d8e2d4bf 100644 --- a/build/unit-build.mk +++ b/build/unit-build.mk @@ -138,6 +138,28 @@ $(call UNIT_MAKE_CLEAN,$(TESTBINDIR)/$(UNIT_BIN)) $(call UNIT_C_RULES) endef +########################################################## +# Definition of a "FUT" type unit +########################################################## +define UNIT_BUILD_FUT +# Add the unit to the global list of units +UNIT_ALL += $(UNIT_PATH) +UNIT_ALL_INSTALL += $(UNIT_PATH)/install +UNIT_ALL_CLEAN += $(UNIT_PATH)/clean +UNIT_ALL_FUT_UNITS += $(UNIT_PATH) + +.PHONY: $(UNIT_PATH)/install +$(UNIT_PATH) $(UNIT_PATH)/: $(UNIT_PATH)/install +$(UNIT_PATH)/install: + $(NQ) " $(call color_copy,copy) [$(call COLOR_BOLD,$(UNIT_PATH))] -> $(FUTDIR)/$(UNIT_DIR)" + $(Q)$(MKDIR) $(foreach SRC,$(UNIT_FILE),'$(dir $(FUTDIR)/$(UNIT_DIR)/$(SRC))') + $(Q)$(foreach SRC,$(UNIT_FILE),$(CP) $(UNIT_PATH)/$(SRC) $(dir $(FUTDIR)/$(UNIT_DIR)/$(SRC));) + +$(call UNIT_MAKE_DIRS) +$(call UNIT_MAKE_INFO) +$(call UNIT_MAKE_CLEAN,$(FUTDIR)/$(UNIT_DIR)) +endef + ########################################################## # Definition of a "LIB" type unit ########################################################## @@ -357,6 +379,7 @@ $(UNIT_PATH)/info: $(NQ) "UNIT_OBJ: " $(UNIT_OBJ) $(NQ) "UNIT_EXPORT_CFLAGS: " $(UNIT_EXPORT_CFLAGS) $(NQ) "UNIT_EXPORT_LDFLAGS: " $(UNIT_EXPORT_LDFLAGS) + $(NQ) "UNIT_FILE: " $(UNIT_FILE) $(NQ) "UNIT_CLEAN: " $(UNIT_CLEAN) endef @@ -415,6 +438,7 @@ UNIT_PRE:= UNIT_DIR:= UNIT_POST_MACRO:= UNIT_INSTALL:= +UNIT_FILE:= UNIT_MK := $(1) UNIT_PATH := $(call CANNED_PATH,$(dir $(UNIT_MK))) diff --git a/doc/doxygen.conf b/doc/doxygen.conf index 7a53a0c0..133d307b 100644 --- a/doc/doxygen.conf +++ b/doc/doxygen.conf @@ -802,10 +802,18 @@ INPUT = \ ../src/lib/osn/inc/osn_inet6.h \ ../src/lib/osn/inc/osn_dhcpv6.h \ ../src/lib/osn/inc/osn_netif.h \ + ../src/lib/osn/inc/osn_pppoe.h \ + ../src/lib/osn/inc/osn_vlan.h \ ../src/lib/osp/inc/osp.h \ - ../src/lib/osp/inc/osp_led.h \ + ../src/lib/osp/inc/osp_unit.h \ ../src/lib/osp/inc/osp_tm.h \ - ../src/lib/osp/inc/osp_ps.h + ../src/lib/osp/inc/osp_reboot.h \ + ../src/lib/osp/inc/osp_led.h \ + ../src/lib/osp/inc/osp_btn.h \ + ../src/lib/osp/inc/osp_upg.h \ + ../src/lib/osp/inc/osp_ps.h \ + ../src/lib/osp/inc/osp_dl.h \ + ../src/lib/osp/inc/osp_objm.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/interfaces/interface_stats.proto b/interfaces/interface_stats.proto new file mode 100644 index 00000000..39c9fabe --- /dev/null +++ b/interfaces/interface_stats.proto @@ -0,0 +1,53 @@ +// Copyright (c) 2015, Plume Design Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Plume Design Inc. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; + +package intf.stats; + +message ObservationPoint { + optional string nodeId = 1; + optional string locationId = 2; +} + +message IntfStats { + optional string ifName = 1; + optional uint64 txBytes = 2; + optional uint64 rxBytes = 3; + optional uint64 txPackets = 4; + optional uint64 rxPackets = 5; + optional string role = 6; +} + +message ObservationWindow { + optional uint64 startedAt = 1; + optional uint64 endedAt = 2; + repeated IntfStats intfStats = 3; +} + +message IntfReport { + optional uint64 reportedAt = 1; + optional ObservationPoint observationPoint = 2; + repeated ObservationWindow observationWindow = 3; +} diff --git a/interfaces/object_manager.proto b/interfaces/object_manager.proto new file mode 100644 index 00000000..5ec27d19 --- /dev/null +++ b/interfaces/object_manager.proto @@ -0,0 +1,45 @@ +// Copyright (c) 2015, Plume Design Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the Plume Design Inc. nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; + +package objectManager.status; + +message ObservationPoint { + optional string nodeId = 1; + optional string locationId = 2; +} + +message ObjectStatus { + optional string objectName = 1; + optional string version = 2; + optional string status = 3; +} + + +message ObjectStatusReport { + optional uint64 reportedAt = 1; + optional ObservationPoint observationPoint = 2; + repeated ObjectStatus objectStatus = 3; +} \ No newline at end of file diff --git a/interfaces/opensync.ovsschema b/interfaces/opensync.ovsschema index 44fd1e6a..3d4c356b 100644 --- a/interfaces/opensync.ovsschema +++ b/interfaces/opensync.ovsschema @@ -1,7 +1,7 @@ { "name": "Open_vSwitch", - "version": "7.11.203", - "cksum": "3380660315 190193", + "version": "7.11.225", + "cksum": "558562310 199380", "tables": { "AWLAN_Node": { "columns": { @@ -196,6 +196,56 @@ "type": "integer" } } + }, + "vendor_name": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + }, + "min": 0, + "max": 1 + } + }, + "vendor_part_number": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + }, + "min": 0, + "max": 1 + } + }, + "vendor_manufacturer": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + }, + "min": 0, + "max": 1 + } + }, + "vendor_factory": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + }, + "min": 0, + "max": 1 + } + }, + "vendor_mfg_date": { + "type": { + "key": { + "type": "string", + "maxLength": 16 + }, + "min": 0, + "max": 1 + } } }, "isRoot": true, @@ -447,6 +497,15 @@ "max": 1 } }, + "bridge": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, "is_used": { "type": { "key": { @@ -828,6 +887,16 @@ "min": 0, "max": 1 } + }, + "role": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + }, + "min": 0, + "max": 1 + } } }, "isRoot": true, @@ -1249,7 +1318,8 @@ [ "auto", "manual", - "cloud" + "cloud", + "acs" ] ] }, @@ -1359,8 +1429,7 @@ "type": { "key": { "type": "integer", - "minInteger": 1, - "maxInteger": 32 + "minInteger": 1 }, "min": 0, "max": 1 @@ -1556,7 +1625,8 @@ [ "auto", "manual", - "cloud" + "cloud", + "acs" ] ] }, @@ -1672,8 +1742,7 @@ "type": { "key": { "type": "integer", - "minInteger": 1, - "maxInteger": 32 + "minInteger": 1 }, "min": 0, "max": 1 @@ -2297,7 +2366,7 @@ "refType": "weak" }, "min": 0, - "max": "unlimited" + "max": 256 } }, "vlan_id": { @@ -2675,7 +2744,7 @@ "type": { "key": { "type": "string", - "maxLength": 128 + "maxLength": 512 }, "min": 0, "max": 1 @@ -2755,6 +2824,15 @@ "max": 1 } }, + "connectable": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, "interval_millis" : { "type" : { "key": { @@ -2822,6 +2900,15 @@ "max": 1 } }, + "connectable": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + }, "interval_millis" : { "type" : { "key": { @@ -5890,6 +5977,31 @@ }, "isRoot": true }, + "Openflow_Local_Tag": { + "columns": { + "name": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 32 + } + } + }, + "values": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "min": 0, + "max": 1024 + } + } + }, + "isRoot": true + }, "Openflow_Tag_Group": { "columns": { "name": { @@ -6452,6 +6564,64 @@ }, "isRoot": true }, + "Wifi_Channels": { + "columns": { + "channel": { + "type": { + "key": { + "type": "integer", + "minInteger": 1 + }, + "min": 0, + "max": 1 + } + }, + "radio_ifname": { + "type": { + "key": { + "type": "string" + }, + "min": 0, + "max": 1 + } + }, + "tx_power": { + "type": { + "key": { + "type": "integer", + "minInteger": 1 + }, + "min": 0, + "max": 1 + } + }, + "max_tx_power_allowed": { + "type": { + "key": { + "type": "integer", + "minInteger": 1 + }, + "min": 0, + "max": 1 + } + }, + "acs_enable": { + "type": { + "key": { + "type": "boolean" + } + } + }, + "acs_is_enabled": { + "type": { + "key": { + "type": "boolean" + } + } + } + }, + "isRoot": true + }, "FCM_Collector_Config": { "columns": { "name": { @@ -8261,6 +8431,46 @@ }, "isRoot": true }, + "IPv4_Neighbors": { + "columns": { + "address": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 49 + } + } + }, + "hwaddr": { + "type": { + "key": { + "type": "string", + "minLength": 12, + "maxLength": 17 + } + } + }, + "if_name": { + "type": { + "key": { + "type": "string", + "minLength": 2, + "maxLength": 31 + } + } + }, + "source": { + "type": { + "key": { + "type": "string", + "maxLength": 16 + } + } + } + }, + "isRoot": true + }, "IGMP_Config": { "columns": { "query_interval": { @@ -8525,6 +8735,174 @@ } }, "isRoot": true + }, + "OMS_Config": { + "columns": { + "object_name": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + } + }, + "version": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + } + }, + "other_config": { + "type": { + "key": "string", + "value": { + "type": "string", + "maxLength": 128 + }, + "min": 0, + "max": "unlimited" + } + } + }, + "isRoot": true + }, + "Object_Store_Config": { + "columns": { + "name": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + } + } + }, + "version": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 16 + } + } + }, + "dl_url": { + "type": { + "key": { + "type": "string", + "maxLength": 512 + }, + "min": 0, + "max": 1 + } + }, + "dl_timeout": { + "type": { + "key": { + "type": "integer" + }, + "min": 0, + "max": 1 + } + } + }, + "isRoot": true + }, + "Object_Store_State": { + "columns": { + "name": { + "type": { + "key": { + "type": "string", + "maxLength": 64 + } + } + }, + "version": { + "type": { + "key": { + "type": "string", + "minLength": 1, + "maxLength": 16 + } + } + }, + "status": { + "type": { + "key": { + "type": "string", + "enum": [ + "set", + [ + "install-failed", + "install-done", + "download-started", + "download-failed", + "download-done", + "load-failed", + "active", + "error", + "obsolete" + ] + ] + }, + "min": 0, + "max": 1 + } + }, + "fw_integrated": { + "type": { + "key": { + "type": "boolean" + }, + "min": 0, + "max": 1 + } + } + }, + "isRoot": true + }, + "Captive_Portal": { + "columns": { + "name": { + "type": { + "key": { + "type": "string" + }, + "min": 1, + "max": 1 + } + }, + "uam_url": { + "type": { + "key": { + "type": "string" + }, + "min": 1, + "max": 1 + } + }, + "additional_headers": { + "type": { + "key": "string", + "value": "string", + "min": 0, + "max": "unlimited" + } + }, + "other_config": { + "type": { + "key": "string", + "value": "string", + "min": 0, + "max": "unlimited" + } + } + }, + "isRoot": true } } } diff --git a/interfaces/opensync_stats.proto b/interfaces/opensync_stats.proto index 3361b7b5..543ff5b5 100644 --- a/interfaces/opensync_stats.proto +++ b/interfaces/opensync_stats.proto @@ -125,6 +125,13 @@ message AvgType { optional uint32 num = 4; } +message AvgTypeSigned { + required int32 avg = 1; + optional int32 min = 2; + optional int32 max = 3; + optional uint32 num = 4; +} + enum DiffType { ADDED = 0; REMOVED = 1; @@ -175,9 +182,11 @@ message Client { optional uint64 tx_retries = 6; optional uint64 rx_errors = 7; optional uint64 tx_errors = 8; - optional double rx_rate = 9; - optional double tx_rate = 10; + optional double rx_rate = 9; /* best-effort report of SU capacity, mbps */ + optional double tx_rate = 10; /* best-effort report of SU capacity, mbps */ optional uint32 rssi = 11; + optional double rx_rate_perceived = 12; /* accounts mixed SU+MU, mbps */ + optional double tx_rate_perceived = 13; /* accounts mixed SU+MU, mbps */ } message RxStats { message ChainRSSI { @@ -263,14 +272,16 @@ message Survey { optional uint32 busy_self = 8; /* Rx_self (derived from succesful Rx frames)*/ optional uint32 offset_ms = 9; optional uint32 busy_ext = 10; /* 40MHz extention channel busy */ + optional int32 noise_floor = 11; /* dBm */ } message SurveyAvg { - required uint32 channel = 1; - optional AvgType busy = 2; /* Busy = Rx + Tx + Interference */ - optional AvgType busy_tx = 3; /* Tx */ - optional AvgType busy_rx = 4; /* Rx = Rx_obss + Rx_errr (self and obss errors) */ - optional AvgType busy_self = 5; /* Rx_self (derived from succesful Rx frames)*/ - optional AvgType busy_ext = 6; /* 40MHz extention channel busy */ + required uint32 channel = 1; + optional AvgType busy = 2; /* Busy = Rx + Tx + Interference */ + optional AvgType busy_tx = 3; /* Tx */ + optional AvgType busy_rx = 4; /* Rx = Rx_obss + Rx_errr (self and obss errors) */ + optional AvgType busy_self = 5; /* Rx_self (derived from succesful Rx frames)*/ + optional AvgType busy_ext = 6; /* 40MHz extention channel busy */ + optional AvgTypeSigned noise_floor = 7; /* dBm */ } required RadioBandType band = 1; required SurveyType survey_type = 2; diff --git a/kconfig/Kconfig b/kconfig/Kconfig index 97e82028..d77d132f 100644 --- a/kconfig/Kconfig +++ b/kconfig/Kconfig @@ -67,10 +67,28 @@ menu "Common" source "kconfig/Kconfig.osn.ipv6_radv_backend" endchoice + choice + prompt "PPPoE" + default OSN_BACKEND_PPPOE_LINUX + source "kconfig/Kconfig.osn.pppoe_backend" + endchoice + + choice + prompt "VLAN" + default OSN_BACKEND_VLAN_LINUX + source "kconfig/Kconfig.osn.vlan_backend" + endchoice + source "kconfig/Kconfig.osn" endmenu menu "Platform (OSP)" + comment "Unit (OSP unit)" + choice + prompt "OSP Unit Backend" + source "kconfig/Kconfig.osp_unit.backend" + endchoice + comment "Persistent Storage (OSP_PS)" choice prompt "Persistent Storage Backend" @@ -94,6 +112,14 @@ menu "Common" source "kconfig/Kconfig.osp_l2switch.backend" endchoice + comment "Object Management (OSP_OBJM)" + choice + prompt "Object Management Backend" + source "kconfig/Kconfig.osp_objm.backend" + endchoice + source "kconfig/Kconfig.osp_objm" + + endmenu endmenu diff --git a/kconfig/Kconfig.managers b/kconfig/Kconfig.managers index 2bd815f6..82bd124b 100644 --- a/kconfig/Kconfig.managers +++ b/kconfig/Kconfig.managers @@ -5,6 +5,7 @@ comment "Core Managers" # source "src/dm/kconfig/Kconfig.managers" source "src/cm2/kconfig/Kconfig.managers" +source "src/wano/kconfig/Kconfig.managers" source "src/nm2/kconfig/Kconfig.managers" source "src/wm2/kconfig/Kconfig.managers" source "src/sm/kconfig/Kconfig.managers" @@ -18,6 +19,7 @@ source "src/fsm/kconfig/Kconfig.managers" source "src/fcm/kconfig/Kconfig.managers" source "src/nfm/kconfig/Kconfig.managers" source "src/xm/kconfig/Kconfig.managers" +source "src/cpm/kconfig/Kconfig.managers" source "src/hello_world/kconfig/Kconfig.managers" # diff --git a/kconfig/Kconfig.osn.pppoe_backend b/kconfig/Kconfig.osn.pppoe_backend new file mode 100644 index 00000000..392972b6 --- /dev/null +++ b/kconfig/Kconfig.osn.pppoe_backend @@ -0,0 +1,11 @@ +# +# OpenSync core network PPPoE backend +# +source "src/lib/osn/kconfig/Kconfig.osn.pppoe_backend" + +# +# Platform/vendor PPPoE backends +# +osource "platform/*/kconfig/Kconfig.osn.pppoe_backend" +osource "vendor/*/kconfig/Kconfig.osn.pppoe_backend" + diff --git a/kconfig/Kconfig.osn.vlan_backend b/kconfig/Kconfig.osn.vlan_backend new file mode 100644 index 00000000..b4664998 --- /dev/null +++ b/kconfig/Kconfig.osn.vlan_backend @@ -0,0 +1,11 @@ +# +# OpenSync core network VLAN backend +# +source "src/lib/osn/kconfig/Kconfig.osn.vlan_backend" + +# +# Platform/vendor VLAN backends +# +osource "platform/*/kconfig/Kconfig.osn.vlan_backend" +osource "vendor/*/kconfig/Kconfig.osn.vlan_backend" + diff --git a/kconfig/Kconfig.osp_objm b/kconfig/Kconfig.osp_objm new file mode 100644 index 00000000..f2f7d4fc --- /dev/null +++ b/kconfig/Kconfig.osp_objm @@ -0,0 +1,10 @@ +# +# Include core OSP OBJM modules +# +source "src/lib/osp/kconfig/Kconfig.osp_objm" + +# +# Include platform/vendor OSP OBJM modules +# +osource "platform/*/kconfig/Kconfig.osp_objm" +osource "vendor/*/kconfig/Kconfig.osp_objm" diff --git a/kconfig/Kconfig.osp_objm.backend b/kconfig/Kconfig.osp_objm.backend new file mode 100644 index 00000000..be812009 --- /dev/null +++ b/kconfig/Kconfig.osp_objm.backend @@ -0,0 +1,11 @@ +# +# Core OBJM modules +# +source "src/lib/osp/kconfig/Kconfig.osp_objm.backend" + +# +# Vendor/Platform OBMJ modules +# +osource "platform/*/kconfig/Kconfig.osp_objm.backend" +osource "vendor/*/kconfig/Kconfig.osp_objm.backend" + diff --git a/kconfig/Kconfig.osp_unit.backend b/kconfig/Kconfig.osp_unit.backend new file mode 100644 index 00000000..17cbcff3 --- /dev/null +++ b/kconfig/Kconfig.osp_unit.backend @@ -0,0 +1,10 @@ +# +# OpenSync core platform OSP Unit backend +# +source "src/lib/osp/kconfig/Kconfig.osp_unit.backend" + +# +# Platform/vendor OSP Unit backends +# +osource "platform/*/kconfig/Kconfig.osp_unit.backend" +osource "vendor/*/kconfig/Kconfig.osp_unit.backend" diff --git a/ovsdb/20_kconfig.bridge_wan_ipv6.json.sh b/ovsdb/20_kconfig.bridge_wan_ipv6.json.sh index 6c2dd478..1bb977de 100644 --- a/ovsdb/20_kconfig.bridge_wan_ipv6.json.sh +++ b/ovsdb/20_kconfig.bridge_wan_ipv6.json.sh @@ -23,6 +23,15 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +exit_empty() +{ + echo '[ "Open_vSwitch" ]' + exit 0 +} + +[ -n "$CONFIG_MANAGER_WANO" ] && exit_empty +[ -z "$CONFIG_TARGET_WAN_BRIDGE_NAME" ] && exit_empty + cat <group) return; - if (!client->info->rrm_caps.bcn_rpt_active) + if (!client->info->is_RRM_supported) return; bm_client_reset_rrm_neighbors(client); num_channels = bm_neighbor_get_channels(client, rrm_req_type, channels, sizeof(channels), 0); for (i = 0; i < num_channels; i++) { + if (bm_client_is_dfs_channel(channels[i])) { + if (!client->info->rrm_caps.bcn_rpt_passive) { + LOGD("%s skip rrm_req while DFS and !rrm_passive", client->mac_addr); + continue; + } + } else { + if (!client->info->rrm_caps.bcn_rpt_active) { + LOGD("%s skip rrm_req while non-DFS and !rrm_active", client->mac_addr); + continue; + } + } + req = bm_client_get_rrm_req(client, channels[i]); if (!req) { LOGW("%s: could not get rrm_req slot", client->mac_addr); @@ -433,11 +445,15 @@ bm_client_send_rrm_req(bm_client_t *client, bm_client_rrm_req_type_t rrm_req_typ req->rrm_params.req_ssid = 1; req->rrm_params.meas_dur = BM_CLIENT_RRM_ACTIVE_MEASUREMENT_DURATION; - /* TODO should we change to passive for DFS case? */ req->rrm_params.channel = channels[i]; req->rrm_params.op_class = bm_neighbor_get_op_class(channels[i]); - delay_ms = EVSCHED_SEC(delay) + i * 3 * BM_CLIENT_RRM_ACTIVE_MEASUREMENT_DURATION; + if (bm_client_is_dfs_channel(channels[i])) { + req->rrm_params.meas_mode = 0; + req->rrm_params.meas_dur = BM_CLIENT_RRM_PASIVE_MEASUREMENT_DURATION; + } + + delay_ms = EVSCHED_SEC(delay) + i * 3 * req->rrm_params.meas_dur; if (!delay_ms) { bm_client_send_rrm_req_task(req); @@ -459,7 +475,7 @@ bm_client_update_rrm_neighbors(void) continue; if (!client->connected) continue; - if (!client->info->rrm_caps.bcn_rpt_active) + if (!client->info->is_RRM_supported) continue; if (!strlen(client->ifname)) continue; @@ -698,7 +714,7 @@ bm_client_add_to_group(bm_client_t *client, bm_group_t *group) if (!bm_client_ifcfg_set(group, client, group->ifcfg[i].ifname, group->ifcfg[i].radio_type, - group->ifcfg[i].bs_allowed)) { + group->ifcfg[i].bs_allowed, &cli_conf)) { LOGE("Failed to add client '%s' band %s to client ifcfg[] %s", client->mac_addr, c_get_str_by_key(map_bsal_bands, group->ifcfg[i].radio_type), @@ -751,7 +767,7 @@ bm_client_update_group(bm_client_t *client, bm_group_t *group) if (!bm_client_ifcfg_set(group, client, group->ifcfg[i].ifname, group->ifcfg[i].radio_type, - group->ifcfg[i].bs_allowed)) { + group->ifcfg[i].bs_allowed, &cli_conf)) { LOGE("Failed to update client '%s' band %s to client ifcfg[] %s", client->mac_addr, c_get_str_by_key(map_bsal_bands, group->ifcfg[i].radio_type), @@ -1092,8 +1108,6 @@ bm_client_get_cs_params( struct schema_Band_Steering_Clients *bscli, bm_client_t } if( !(val = bm_client_get_cs_param( bscli, "band" ))) { - // ABS: Check if this is correct - LOGD("%s - unknown radio_type", client->mac_addr); client->cs_radio_type = RADIO_TYPE_NONE; } else { item = c_get_item_by_str(map_bsal_bands, val); @@ -2196,7 +2210,7 @@ bm_client_connected(bm_client_t *client, bm_group_t *group, const char *ifname) STRSCPY(client->ifname, ifname); client->connected = true; - client->xing_snr = 0; + client->prev_xing_snr = 0; stats = bm_client_get_stats(client, ifname); if (WARN_ON(!stats)) @@ -2223,7 +2237,7 @@ void bm_client_disconnected(bm_client_t *client) { client->connected = false; - client->xing_snr = 0; + client->prev_xing_snr = 0; if (client->state == BM_CLIENT_STATE_CONNECTED) { bm_client_set_state(client, BM_CLIENT_STATE_DISCONNECTED); @@ -2757,7 +2771,7 @@ void bm_client_ifcfg_clean(bm_client_t *client) static bool bm_client_ifcfg_add(bm_group_t *group, bm_client_t *client, const char *ifname, radio_type_t radio_type, - bool bs_allowed) + bool bs_allowed, bsal_client_config_t *conf) { bm_client_ifcfg_t *ifcfg; unsigned int i; @@ -2779,6 +2793,7 @@ bm_client_ifcfg_add(bm_group_t *group, bm_client_t *client, ifcfg->radio_type= radio_type; ifcfg->bs_allowed = bs_allowed; ifcfg->group = group; + memcpy(&ifcfg->conf, conf, sizeof(*conf)); LOGD("%s: add ifcfg[%d]: ifname %s band %d allowed %d", client->mac_addr, client->ifcfg_num, ifcfg->ifname, ifcfg->radio_type, ifcfg->bs_allowed); @@ -2791,7 +2806,7 @@ bm_client_ifcfg_add(bm_group_t *group, bm_client_t *client, bool bm_client_ifcfg_set(bm_group_t *group, bm_client_t *client, const char *ifname, radio_type_t radio_type, - bool bs_allowed) + bool bs_allowed, bsal_client_config_t *conf) { unsigned int i; @@ -2803,6 +2818,7 @@ bm_client_ifcfg_set(bm_group_t *group, bm_client_t *client, client->ifcfg[i].radio_type = radio_type; client->ifcfg[i].group = group; client->ifcfg[i].bs_allowed = bs_allowed; + memcpy(&client->ifcfg[i].conf, conf, sizeof(*conf)); LOGD("%s: update ifcfg[%d]: ifname %s band %d allowed %d", client->mac_addr, i, client->ifcfg[i].ifname, client->ifcfg[i].radio_type, client->ifcfg[i].bs_allowed); @@ -2810,7 +2826,7 @@ bm_client_ifcfg_set(bm_group_t *group, bm_client_t *client, } } - return bm_client_ifcfg_add(group, client, ifname, radio_type, bs_allowed); + return bm_client_ifcfg_add(group, client, ifname, radio_type, bs_allowed, conf); } bool @@ -3147,6 +3163,76 @@ bm_client_activity_recalc(bm_client_t *client, bsal_client_info_t *info) client->bytes_report_time = now; } +/* handle client xing */ +static bsal_rssi_change_t +bm_client_recalc_rssi_change(uint8_t snr, uint8_t watermark) +{ + return (snr < watermark ? BSAL_RSSI_LOWER : BSAL_RSSI_HIGHER); +} + +static void +bm_client_xing_recalc(bm_client_t *client, bsal_client_info_t *info) +{ + bm_client_ifcfg_t *ifcfg; + bsal_rssi_change_t new_xing_low; + bsal_rssi_change_t new_xing_high; + bsal_rssi_change_t prev_xing_low; + bsal_rssi_change_t prev_xing_high; + uint8_t xing_lwm, xing_hwm; + bsal_event_t event; + uint8_t new_snr; + uint8_t prev_snr; + + ifcfg = bm_client_get_ifcfg(client, client->ifname); + if (WARN_ON(!ifcfg)) + return; + + new_snr = info->snr; + prev_snr = client->prev_xing_snr; + + xing_lwm = ifcfg->conf.rssi_low_xing; + xing_hwm = ifcfg->conf.rssi_high_xing ; + + new_xing_low = bm_client_recalc_rssi_change(new_snr, xing_lwm); + new_xing_high = bm_client_recalc_rssi_change(new_snr, xing_hwm); + prev_xing_low = bm_client_recalc_rssi_change(prev_snr, xing_lwm); + prev_xing_high = bm_client_recalc_rssi_change(prev_snr, xing_hwm); + + LOGD("%s new_snr %u old_snr %u lwm %u hwm %u low %d->%d high %d->%d", + client->mac_addr, new_snr, prev_snr, xing_lwm, xing_hwm, + prev_xing_low, new_xing_low, + prev_xing_high, new_xing_high); + + if (new_xing_low == prev_xing_low && + new_xing_high == prev_xing_high) + return; + + memset(&event, 0, sizeof(event)); + STRSCPY(event.ifname, client->ifname); + event.data.rssi_change.rssi = new_snr; + + if (new_xing_low == prev_xing_low) + event.data.rssi_change.low_xing = BSAL_RSSI_UNCHANGED; + else + event.data.rssi_change.low_xing = new_xing_low; + + if (new_xing_high == prev_xing_high) + event.data.rssi_change.high_xing = BSAL_RSSI_UNCHANGED; + else + event.data.rssi_change.high_xing = new_xing_high; + + /* While we don't know prev_snr we don't know xing */ + if (!prev_snr) { + event.data.rssi_change.low_xing = BSAL_RSSI_UNCHANGED; + event.data.rssi_change.high_xing = BSAL_RSSI_UNCHANGED; + } + + /* Save this to know (internal) prev state */ + client->prev_xing_snr = new_snr; + + bm_events_handle_rssi_xing(client, &event); +} + void bm_client_sta_info_update_callback(void) { bsal_client_info_t info; @@ -3163,7 +3249,7 @@ void bm_client_sta_info_update_callback(void) } bm_client_activity_recalc(client, &info); - + bm_client_xing_recalc(client, &info); } } @@ -3185,3 +3271,20 @@ void bm_client_handle_ext_activity(bm_client_t *client, const char *ifname, bool bm_client_activity_recalc(client, &info); } + +void bm_client_handle_ext_xing(bm_client_t *client, const char *ifname, bsal_event_t *event) +{ + bsal_client_info_t info; + + if (!client->connected) { + LOGD("%s %s skip ext xing while client not connected", ifname, client->mac_addr); + return; + } + + if (target_bsal_client_info(client->ifname, client->macaddr.addr, &info)) { + LOGI("%s: %s no client info, base on external xing event, snr %u", client->ifname, client->mac_addr, event->data.rssi_change.rssi); + info.snr = event->data.rssi_change.rssi; + } + + bm_client_xing_recalc(client, &info); +} diff --git a/src/bm/src/bm_client.h b/src/bm/src/bm_client.h index a46711ce..47feb06f 100644 --- a/src/bm/src/bm_client.h +++ b/src/bm/src/bm_client.h @@ -82,6 +82,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define BM_CLIENT_RRM_NEIGHBOR_MAX 16 #define BM_CLIENT_RRM_REQ_MAX 8 #define BM_CLIENT_RRM_ACTIVE_MEASUREMENT_DURATION 30 +#define BM_CLIENT_RRM_PASIVE_MEASUREMENT_DURATION 100 #define BM_CLIENT_DEFAULT_ACTIVITY_BPS_TH 2000 @@ -237,6 +238,7 @@ typedef struct { bm_group_t *group; bm_client_stats_t stats; bsal_client_info_t info; + bsal_client_config_t conf; } bm_client_ifcfg_t; typedef struct { @@ -293,9 +295,7 @@ typedef struct { uint8_t hwm; uint8_t lwm; - uint8_t xing_snr; - bsal_rssi_change_t xing_low; - bsal_rssi_change_t xing_high; + uint8_t prev_xing_snr; int max_rejects; int max_rejects_period; @@ -401,6 +401,20 @@ typedef struct { ds_tree_node_t dst_node; } bm_client_t; +static inline bm_client_ifcfg_t * +bm_client_get_ifcfg(bm_client_t *client, const char *ifname) +{ + unsigned int i; + + for (i = 0; i < client->ifcfg_num; i++) { + if (!strcmp(client->ifcfg[i].ifname, ifname)) { + return &client->ifcfg[i]; + } + } + + return NULL; +} + static inline bm_client_stats_t * bm_client_get_stats(bm_client_t *client, const char *ifname) { @@ -471,7 +485,7 @@ extern bm_client_t * bm_client_find_by_uuid(const char *uuid); extern bm_client_t * bm_client_find_by_macstr(char *mac_str); extern bm_client_t * bm_client_find_by_macaddr(os_macaddr_t mac_addr); extern bm_client_t * bm_client_find_or_add_by_macaddr(os_macaddr_t *mac_addr); -extern bool bm_client_ifcfg_set(bm_group_t *group, bm_client_t *client, const char *ifname, radio_type_t radio_type, bool bs_allowed); +extern bool bm_client_ifcfg_set(bm_group_t *group, bm_client_t *client, const char *ifname, radio_type_t radio_type, bool bs_allowed, bsal_client_config_t *conf); extern bool bm_client_ifcfg_remove(bm_client_t *client, const char *ifname); extern void bm_client_ifcfg_clean(bm_client_t *client); extern bool bm_client_bs_ifname_allowed(bm_client_t *client, const char *ifname); @@ -486,4 +500,5 @@ extern void bm_client_send_rrm_req(bm_client_t *client, bm_clien extern void bm_client_parse_assoc_ies(bm_client_t *client, const uint8_t *ies, size_t ies_len); extern void bm_client_sta_info_update_callback(void); extern void bm_client_handle_ext_activity(bm_client_t *client, const char *ifname, bool active); +extern void bm_client_handle_ext_xing(bm_client_t *client, const char *ifname, bsal_event_t *event); #endif /* BM_CLIENT_H_INCLUDED */ diff --git a/src/bm/src/bm_events.c b/src/bm/src/bm_events.c index 19bcd477..6935212c 100644 --- a/src/bm/src/bm_events.c +++ b/src/bm/src/bm_events.c @@ -115,7 +115,6 @@ static c_item_t map_bsal_disc_reasons[] = { /*****************************************************************************/ static void bm_events_handle_event(bsal_event_t *event ); -static void bm_events_handle_rssi_xing( bm_client_t *client, bsal_event_t *event ); /*****************************************************************************/ // Callback function for BSAL upon receiving steering events from the driver @@ -443,8 +442,7 @@ bm_events_handle_event(bsal_event_t *event) break; } - bm_events_handle_rssi_xing( client, event ); - + bm_client_handle_ext_xing(client, client->ifname, event); break; case BSAL_EVENT_RSSI: @@ -534,10 +532,11 @@ bm_events_handle_event(bsal_event_t *event) bm_stats_add_event_to_report( client, event, AUTH_BLOCK, false ); } - if (client->state == BM_CLIENT_STATE_CONNECTED && !strcmp(client->ifname, event->ifname)) { + if (client->state == BM_CLIENT_STATE_CONNECTED) { bsal_event_t disconnect_event; - LOGI("[%s]: %s in connected state (assume we lost last deauth/disassoc)", bandstr, ifname); + LOGI("[%s]: %s in connected state %s (assume we lost last deauth/disassoc)", bandstr, + client->ifname, event->ifname); memset(&disconnect_event, 0, sizeof(disconnect_event)); STRSCPY(disconnect_event.ifname, client->ifname); @@ -669,11 +668,6 @@ bm_events_handle_rssi_xing_bs(bm_client_t *client, bsal_event_t *event) LOGI("[%s]: xing_bs '%s' snr %d (%d,%d)", event->ifname, client->mac_addr, event->data.rssi_change.rssi, event->data.rssi_change.low_xing, event->data.rssi_change.high_xing); - if (client->xing_snr == 0 && (now - times->last_connect < 4)) { - LOGI("[%s]: xing_bs '%s' skip XING event (first after connection)", event->ifname, client->mac_addr); - return; - } - if (client->backoff && !client->steer_during_backoff) { LOGI("[%s]: xing_bs '%s' skip XING event, don't steer during pre-assoc backoff ", event->ifname, client->mac_addr); return; @@ -785,17 +779,9 @@ bm_events_handle_rssi_xing_cs(bm_client_t *client, bsal_event_t *event) } } -static void +void bm_events_handle_rssi_xing(bm_client_t *client, bsal_event_t *event) { - if (event->data.rssi_change.low_xing == client->xing_low && - event->data.rssi_change.high_xing == client->xing_high && - (abs(event->data.rssi_change.rssi - client->xing_snr) <= BM_CLIENT_SNR_XING_DIFF)) { - LOGT("%s same xing skip (%d, %d) snr %d old %d", client->mac_addr, client->xing_low, client->xing_high, - event->data.rssi_change.rssi, client->xing_snr); - return; - } - switch (client->steering_state) { case BM_CLIENT_CLIENT_STEERING: bm_events_handle_rssi_xing_cs(client, event); @@ -806,11 +792,6 @@ bm_events_handle_rssi_xing(bm_client_t *client, bsal_event_t *event) bm_events_handle_rssi_xing_bs(client, event); break; } - - /* Save last XING values */ - client->xing_snr = event->data.rssi_change.rssi; - client->xing_low = event->data.rssi_change.low_xing; - client->xing_high = event->data.rssi_change.high_xing; } /*****************************************************************************/ diff --git a/src/bm/src/bm_events.h b/src/bm/src/bm_events.h index dea6ab23..1bc8c5db 100644 --- a/src/bm/src/bm_events.h +++ b/src/bm/src/bm_events.h @@ -37,5 +37,6 @@ extern bool bm_events_init(struct ev_loop *loop); extern bool bm_events_cleanup(void); void bm_event_action_frame(const char *ifname, const uint8_t *data, unsigned int data_len); +void bm_events_handle_rssi_xing(bm_client_t *client, bsal_event_t *event); #endif /* BM_EVENTS_H_INCLUDED */ diff --git a/src/bm/src/bm_group.c b/src/bm/src/bm_group.c index f2e6bd5b..2cc09be7 100644 --- a/src/bm/src/bm_group.c +++ b/src/bm/src/bm_group.c @@ -55,6 +55,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /*****************************************************************************/ +static ovsdb_table_t table_Wifi_VIF_Config; +static ovsdb_table_t table_Wifi_Radio_Config; + static ovsdb_update_monitor_t bm_group_ovsdb_update; static ds_tree_t bm_groups = DS_TREE_INIT((ds_key_cmp_t *)strcmp, bm_group_t, @@ -150,7 +153,40 @@ bm_ifconfigs_from_ovsdb(struct schema_Band_Steering_Config *bsconf, bm_group_t * static bool bm_ifconfigs_from_ovsdb_old(struct schema_Band_Steering_Config *bsconf, bm_group_t *group) { + struct schema_Wifi_Radio_Config rconf; + struct schema_Wifi_VIF_Config vconf; radio_type_t radio_type; + const char *column; + json_t *where; + int ret; + + column = SCHEMA_COLUMN(Wifi_VIF_Config, if_name); + where = ovsdb_tran_cond(OCLM_STR, column, OFUNC_EQ, bsconf->if_name_5g); + if (!where) { + LOGW("%s: Failed alloc ovsdb cond (5G VAP in Wifi_VIF_Config)", + bsconf->if_name_5g); + return false; + } + + ret = ovsdb_table_select_one_where(&table_Wifi_VIF_Config, where, &vconf); + if (!ret) { + LOGW("%s: 5G VAP not found in in Wifi_VIF_Config", bsconf->if_name_5g); + return false; + } + + column = SCHEMA_COLUMN(Wifi_Radio_Config, vif_configs); + where = ovsdb_tran_cond(OCLM_UUID, column, OFUNC_INC, vconf._uuid.uuid); + if (!where) { + LOGW("%s: Failed alloc ovsdb cond (5G VAP's UUID in Wifi_Radio_Config)", + bsconf->if_name_5g); + return false; + } + + ret = ovsdb_table_select_one_where(&table_Wifi_Radio_Config, where, &rconf); + if (!ret) { + LOGW("%s: 5G VAP's UUID not found in in table_Wifi_Radio_Config", bsconf->if_name_5g); + return false; + } /* This could be handled on the Cloud */ char *target_name_2g = target_map_ifname(bsconf->if_name_2g); @@ -168,13 +204,15 @@ bm_ifconfigs_from_ovsdb_old(struct schema_Band_Steering_Config *bsconf, bm_group if (!bm_ifconfig_from_ovsdb(target_name_2g, RADIO_TYPE_2G, false, bsconf, group)) { return false; } + /* - * So far we need this for SP and old if_name_2g/if_name_5g iface. + * Previously this code looked for "l50"/"u50" in ifname we used to distinguish + * between 5GL and 5GU. This was SP-specific. * We will not need this when cloud config ::ifnames */ - if (strstr(bsconf->if_name_5g, "u50")) + if (strcmp(rconf.freq_band, SCHEMA_CONSTS_RADIO_TYPE_STR_5GU) == 0) radio_type = RADIO_TYPE_5GU; - else if (strstr(bsconf->if_name_5g, "l50")) + else if (strcmp(rconf.freq_band, SCHEMA_CONSTS_RADIO_TYPE_STR_5GL) == 0) radio_type = RADIO_TYPE_5GL; else radio_type = RADIO_TYPE_5G; @@ -400,6 +438,9 @@ bm_group_init(void) return false; } + OVSDB_TABLE_INIT(Wifi_VIF_Config, if_name); + OVSDB_TABLE_INIT(Wifi_Radio_Config, if_name); + return true; } diff --git a/src/bm/src/bm_ieee80211.c b/src/bm/src/bm_ieee80211.c index 72d8c789..d6e917af 100644 --- a/src/bm/src/bm_ieee80211.c +++ b/src/bm/src/bm_ieee80211.c @@ -140,6 +140,11 @@ bm_action_frame_bss_trans_mgmt_query(bm_client_t *client, { bsal_btm_params_t btm_params; + if (!client->connected) { + LOGI("Client '%s': Not marked as connected. Can't process BTM yet", client->mac_addr); + return; + } + memset(&btm_params, 0, sizeof(btm_params)); btm_params.abridged = BTM_DEFAULT_ABRIDGED; btm_params.pref = BTM_DEFAULT_PREF; diff --git a/src/bm/src/bm_kick.h b/src/bm/src/bm_kick.h index 39ef0294..02d7d3ca 100644 --- a/src/bm/src/bm_kick.h +++ b/src/bm/src/bm_kick.h @@ -47,7 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define RRM_DEFAULT_CHANNEL 0 // All channels #define RRM_DEFAULT_RAND_IVL 0 #define RRM_DEFAULT_MEAS_DUR 100 -#define RRM_DEFAULT_MEAS_MODE 1 +#define RRM_DEFAULT_MEAS_MODE 1 // 0 - passive, 1 - active #define RRM_DEFAULT_REQ_SSID 2 // 1 for ssid, 2 for wildcard ssid #define RRM_DEFAULT_REP_COND 0 #define RRM_DEFAULT_RPT_DETAIL 0 diff --git a/src/bm/src/bm_neighbor.c b/src/bm/src/bm_neighbor.c index 16c2248f..bc2d1694 100644 --- a/src/bm/src/bm_neighbor.c +++ b/src/bm/src/bm_neighbor.c @@ -708,6 +708,9 @@ bm_neighbor_build_btm_neighbor_list( bm_client_t *client, bsal_btm_params_t *btm int max_regular_neighbors; unsigned int i; + if (WARN_ON(!client->group)) + return false; + if (!btm_params->inc_neigh) { LOGT(" Client '%s': NOT building sticky neighbor list", client->mac_addr ); btm_params->pref = 0; diff --git a/src/cm2/fut/cm2_ble_status_interface_down.sh b/src/cm2/fut/cm2_ble_status_interface_down.sh new file mode 100755 index 00000000..7655bd8c --- /dev/null +++ b/src/cm2/fut/cm2_ble_status_interface_down.sh @@ -0,0 +1,97 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + if_name=\$@ -- used as connection interface - (string) + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") eth0 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if_name=${1:-eth0} +bit_process="01 05 35 75" + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - CM OBSERVE BLE STATUS - interface down/up" +log "$tc_name: Simulating CM full reconnection by dropping interface" + +log "$tc_name: Dropping interface $if_name" +ifconfig "$if_name" down && + log "$tc_name: Interface $if_name is down" || + raise "Couldn't bring down interface $if_name" -l "$tc_name" -ds + +log "$tc_name: Sleeping for 5 seconds" +sleep 5 + +log "$tc_name: Bringing back interface $if_name" +ifconfig "$if_name" up && + log "$tc_name: Interface $if_name is up" || + raise "Couldn't bring up interface $if_name" -l "$tc_name" -ds + +for bit in $bit_process; do + log "$tc_name: Checking AW_Bluetooth_Config payload for $bit:00:00:00:00:00" + wait_ovsdb_entry AW_Bluetooth_Config -is payload "$bit:00:00:00:00:00" && + log "$tc_name: wait_ovsdb_entry - AW_Bluetooth_Config payload changed to $bit:00:00:00:00:00" || + raise "AW_Bluetooth_Config payload failed to change $bit:00:00:00:00:00" -l "$tc_name" -tc +done + +pass diff --git a/src/cm2/fut/cm2_ble_status_internet_block.sh b/src/cm2/fut/cm2_ble_status_internet_block.sh new file mode 100755 index 00000000..99ac22e4 --- /dev/null +++ b/src/cm2/fut/cm2_ble_status_internet_block.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + test_type=\$@ -- used as test step - (string)(required) + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") internet_blocked + /tmp/fut-base/shell/cm2/$(basename "$0") internet_recovered +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +test_type=$1 + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - CM OBSERVE BLE STATUS - internet blocked" + +case $test_type in + internet_blocked) + bit_process="75 35 15 05" + ;; + internet_recovered) + bit_process="75" + ;; + *) + raise "Incorrect test_type provided" -l "$tc_name" -arg +esac + +for bit in $bit_process; do + log "$tc_name: Checking AW_Bluetooth_Config payload for $bit:00:00:00:00:00" + wait_ovsdb_entry AW_Bluetooth_Config -is payload "$bit:00:00:00:00:00" && + log "$tc_name: wait_ovsdb_entry - AW_Bluetooth_Config payload changed to $bit:00:00:00:00:00" || + raise "AW_Bluetooth_Config payload failed to change $bit:00:00:00:00:00" -l "$tc_name" -tc +done + +pass diff --git a/src/cm2/fut/cm2_cloud_down.sh b/src/cm2/fut/cm2_cloud_down.sh new file mode 100755 index 00000000..d71c45a6 --- /dev/null +++ b/src/cm2/fut/cm2_cloud_down.sh @@ -0,0 +1,92 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + unreachable_cloud_counter=\$@ -- used as value counter must reach - (string) + test_type=\$@ -- used as test step - (string) + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") 4 check_counter + /tmp/fut-base/shell/cm2/$(basename "$0") 0 internet_recovered +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +unreachable_cloud_counter_val=${1:-4} +test_type=${2:-"check_counter"} + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - Cloud Failure" + +if [ "$test_type" = "check_counter" ]; then + log "$tc_name: Waiting for unreachable_cloud_counter to reach $unreachable_cloud_counter_val" + wait_ovsdb_entry Connection_Manager_Uplink -w if_name eth0 -is unreachable_cloud_counter "$unreachable_cloud_counter_val" && + log "$tc_name: Connection_Manager_Uplink unreachable_cloud_counter reached $unreachable_cloud_counter_val" || + raise "Connection_Manager_Uplink - {unreachable_cloud_counter:=$unreachable_cloud_counter_val}" -l "$tc_name" -ow +elif [ "$test_type" = "internet_recovered" ]; then + log "$tc_name: Waiting for unreachable_cloud_counter to reset to 0" + wait_ovsdb_entry Connection_Manager_Uplink -w if_name eth0 -is unreachable_cloud_counter "0" && + log "$tc_name: Connection_Manager_Uplink unreachable_cloud_counter reset to 0" || + raise "Connection_Manager_Uplink - {unreachable_cloud_counter:=0}" -l "$tc_name" -ow +else + raise "Wrong test type option" -l "$tc_name" -tc +fi + +pass diff --git a/src/cm2/fut/cm2_dns_failure.sh b/src/cm2/fut/cm2_dns_failure.sh new file mode 100755 index 00000000..277bc703 --- /dev/null +++ b/src/cm2/fut/cm2_dns_failure.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + test_type=\$@ -- used as test step - (string)(required) + manager_addr=\$@ -- used as manager address to be resolved - (string)(required) + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") dns_blocked ssl:54.200.0.59:443 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Input parameters +if [ $# -lt 2 ]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +test_type=$1 +manager_addr=$2 + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - DNS Failure" + +if [ "$test_type" = "dns_blocked" ]; then + log "$tc_name: Setting AWLAN_Node manager_addr to '$manager_addr'" + update_ovsdb_entry AWLAN_Node -u manager_addr "$manager_addr" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node table updated - manager_addr $manager_addr" || + raise "update_ovsdb_entry - Failed to update AWLAN_Node table - manager_addr $manager_addr" -l "$tc_name" -tc + + log "$tc_name: Waiting for Cloud status to go to BACKOFF" + wait_cloud_state BACKOFF && + log "$tc_name: wait_cloud_state - Cloud set to BACKOFF" || + raise "Failed to set cloud to BACKOFF" -l "$tc_name" -tc + + log "$tc_name: Waiting for Cloud status not to become ACTIVE" + wait_cloud_state_not ACTIVE && + log "$tc_name: wait_cloud_state - Cloud stayed in BACKOFF" || + raise "Cloud set to ACTIVE - but it should not be" -l "$tc_name" -tc +elif [ "$test_type" = "dns_recovered" ]; then + log "$tc_name: Setting AWLAN_Node manager_addr to '$manager_addr'" + update_ovsdb_entry AWLAN_Node -u manager_addr "$manager_addr" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node table updated - manager_addr $manager_addr" || + raise "update_ovsdb_entry - Failed to update AWLAN_Node table - manager_addr $manager_addr" -l "$tc_name" -tc + + log "$tc_name: Waiting for Cloud status to go to BACKOFF" + wait_cloud_state BACKOFF && + log "$tc_name: wait_cloud_state - Cloud set to BACKOFF" || + raise "Failed to set cloud to BACKOFF" -l "$tc_name" -tc + + log "$tc_name: Waiting for Cloud status to go to ACTIVE" + wait_cloud_state ACTIVE && + log "$tc_name: wait_cloud_state - Cloud set to ACTIVE" || + raise "Failed to set cloud to ACTIVE" -l "$tc_name" -tc +else + raise "Wrong test type option" -l "$tc_name" -arg +fi + +pass diff --git a/src/cm2/fut/cm2_internet_lost.sh b/src/cm2/fut/cm2_internet_lost.sh new file mode 100755 index 00000000..37731d2c --- /dev/null +++ b/src/cm2/fut/cm2_internet_lost.sh @@ -0,0 +1,102 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Internet lost test case for CM + +# TEST PROCEDURE +# Step 1 (script is called with parameters 4 and check_counter): +# - Internet connection is blocked for DUT. +# - Internet lost counter is suppose to reach its max. count. +# Step 2 (script is called with parameters 0 and internet_recover): +# - Internet connection is unblocked for DUT. +# - Internet lost counter is suppose to reset to zero. +# - Cloud connection should go to ACTIVE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + unreachable_internet_counter=\$@ -- used as value counter must reach - (string) + test_type=\$@ -- used as test step - (string) + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") 4 check_counter + /tmp/fut-base/shell/cm2/$(basename "$0") 0 internet_recovered +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +unreachable_internet_counter=${1:-4} +test_type=${2:-"check_counter"} + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - Internet lost - $test_type" + +if [ "$test_type" = "check_counter" ]; then + log "$tc_name: Waiting for unreachable_internet_counter to reach $unreachable_internet_counter" + wait_ovsdb_entry Connection_Manager_Uplink -w if_name eth0 -is unreachable_internet_counter "$unreachable_internet_counter" && + log "$tc_name: Connection_Manager_Uplink unreachable_internet_counter reached $unreachable_internet_counter" || + raise "Connection_Manager_Uplink - {unreachable_internet_counter:=$unreachable_internet_counter}" -l "$tc_name" -ow +elif [ "$test_type" = "internet_recovered" ]; then + log "$tc_name: Waiting for unreachable_internet_counter to reset to 0" + wait_ovsdb_entry Connection_Manager_Uplink -w if_name eth0 -is unreachable_internet_counter "0" && + log "$tc_name: Connection_Manager_Uplink unreachable_internet_counter reset to 0" || + raise "Connection_Manager_Uplink - {unreachable_internet_counter:=0}" -l "$tc_name" -ow +else + raise "Wrong test type option" -l "$tc_name" -tc +fi + +pass diff --git a/src/cm2/fut/cm2_link_lost.sh b/src/cm2/fut/cm2_link_lost.sh new file mode 100755 index 00000000..2416b9cc --- /dev/null +++ b/src/cm2/fut/cm2_link_lost.sh @@ -0,0 +1,149 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + if_name=\$@ -- used as connection interface - (string)(required) + wan_interface=\$@ -- used as name of WAN interface - (string)(required) + wan_ip=\$@ -- used as IP address of WAN interface - (string)(required) + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") eth0 br-wan 192.168.200.10 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 3 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +wan_interface=$2 +wan_ip=$3 + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - Link Lost" + +log "$tc_name: Dropping interface $if_name connection" +ifconfig "$if_name" down && + log "$tc_name: Interface $if_name is down" || + raise "Couldn't bring down interface $if_name" -l "$tc_name" -ds + +log "$tc_name: Waiting for Cloud status to go to BACKOFF" +wait_cloud_state BACKOFF && + log "$tc_name: wait_cloud_state - Cloud set to BACKOFF" || + raise "Failed to set cloud to BACKOFF" -l "$tc_name" -tc + +log "$tc_name: Waiting for has_L2 -> false on $if_name" +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L2 false && + log "$tc_name: wait_ovsdb_entry - Interface $if_name has_L2 -> false" || + raise "Connection_Manager_Uplink - {has_L2:=false}" -l "$tc_name" -ow + +log "$tc_name: Sleeping for 10 seconds" +sleep 10 + +log "$tc_name: Bringing up interface $if_name" +ifconfig "$if_name" up && + log "$tc_name: Interface $if_name is up" || + raise "Couldn't bring up interface $if_name" -l "$tc_name" -ds + +log "$tc_name: Waiting for Connection_Manager_Uplink::has_L2 -> true for ifname==$if_name" +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L2 true && + log "$tc_name: wait_ovsdb_entry - Interface $if_name has_L2 -> true" || + raise "Connection_Manager_Uplink - {has_L2:=true}" -l "$tc_name" -ow + +log "$tc_name: Waiting for Connection_Manager_Uplink::has_L3 -> true for ifname==$if_name" +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L3 true && + log "$tc_name: wait_ovsdb_entry - Interface $if_name has_L3 -> true" || + raise "Connection_Manager_Uplink - {has_L3:=true}" -l "$tc_name" -ow + + +log "$tc_name: Waiting for Connection_Manager_Uplink::is_used -> true for ifname==$if_name" +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is is_used true && + log "$tc_name: wait_ovsdb_entry - Interface $if_name is_used -> true" || + raise "wait_ovsdb_entry - Connection_Manager_Uplink - {is_used:=true}" -l "$tc_name" -ow + +log "$tc_name: Checking $if_name is added to $wan_interface" +wait_for_function_response 0 "check_if_port_in_bridge $if_name $wan_interface" && + log "$tc_name: check_if_port_in_bridge - port $if_name added to interface $wan_interface" || + raise "check_if_port_in_bridge - port $if_name NOT added to interface $wan_interface" -l "$tc_name" -tc + +log "$tc_name: Waiting for WAN interface to get WAN IP" +wait_ovsdb_entry Wifi_Inet_State -w if_name "$wan_interface" -is inet_addr "$wan_ip" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config - inet_addr is $wan_ip" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - inet_addr is NOT $wan_ip" -l "$tc_name" -tc + +log "$tc_name: Waiting for Connection_Manager_Uplink::ntp_state -> true for ifname==$if_name" +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is ntp_state true && + log "$tc_name: wait_ovsdb_entry - Interface $if_name ntp_state -> true" || + raise "wait_ovsdb_entry - Connection_Manager_Uplink - {ntp_state:=true}" -l "$tc_name" -ow + +log "$tc_name: Verify manager hostname resolved, waiting for Manager::is_connected -> true" +wait_ovsdb_entry Manager -is is_connected true && + log "$tc_name: wait_ovsdb_entry - Manager is_connected is true" || + raise "wait_ovsdb_entry - Manager - {is_connected:=true}" -l "$tc_name" -tc + +log "$tc_name: Waiting for Cloud status to go to ACTIVE" +wait_cloud_state ACTIVE && + log "$tc_name: wait_cloud_state - Cloud set to ACTIVE" || + raise "Failed to set cloud to ACTIVE" -l "$tc_name" -tc + +pass diff --git a/src/cm2/fut/cm2_setup.sh b/src/cm2/fut/cm2_setup.sh new file mode 100755 index 00000000..81ce040d --- /dev/null +++ b/src/cm2/fut/cm2_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for CM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="cm2/$(basename "$0")" + +cm_setup_test_environment "$@" && + log "$tc_name: cm_setup_test_environment - Success " || + raise "cm_setup_test_environment - Failed" -l "$tc_name" -ds + +exit 0 diff --git a/src/cm2/fut/cm2_ssl_check.sh b/src/cm2/fut/cm2_ssl_check.sh new file mode 100755 index 00000000..a4b78ab9 --- /dev/null +++ b/src/cm2/fut/cm2_ssl_check.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/cm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + check_restore_management_access || true + run_setup_if_crashed cm || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running CM manager + - running NM manager + +example of usage: + /tmp/fut-base/shell/cm2/$(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +tc_name="cm2/$(basename "$0")" +log "$tc_name: CM2 test - SSL check" + +ca_cert_path=$(get_ovsdb_entry_value SSL ca_cert) +certificate_path=$(get_ovsdb_entry_value SSL certificate) +private_key_path=$(get_ovsdb_entry_value SSL private_key) + +[ -e "$ca_cert_path" ] && + log "$tc_name: ca_cert file is valid - $ca_cert_path" || + raise "ca_cert file is missing - $ca_cert_path" -l "$tc_name" -tc + +[ -e "$certificate_path" ] && + log "$tc_name: certificate file is valid - $certificate_path" || + raise "certificate file is missing - $certificate_path" -l "$tc_name" -tc + +[ -e "$private_key_path" ] && + log "$tc_name: private_key file is valid - $private_key_path" || + raise "private_key file is missing - $private_key_path" -l "$tc_name" -tc + +[ -s "$ca_cert_path" ] && + log "$tc_name: ca_cert file is not empty - $ca_cert_path" || + raise "ca_cert file is empty - $ca_cert_path" -l "$tc_name" -tc + +[ -s "$certificate_path" ] && + log "$tc_name: certificate file is not empty - $certificate_path" || + raise "certificate file is empty - $certificate_path" -l "$tc_name" -tc + +[ -s "$private_key_path" ] && + log "$tc_name: private_key file is not empty - $private_key_path" || + raise "private_key file is empty - $private_key_path" -l "$tc_name" -tc + +pass diff --git a/src/cm2/fut/cm2_verify_gre_tunnel_dut_gw.sh b/src/cm2/fut/cm2_verify_gre_tunnel_dut_gw.sh new file mode 100755 index 00000000..a2e42740 --- /dev/null +++ b/src/cm2/fut/cm2_verify_gre_tunnel_dut_gw.sh @@ -0,0 +1,297 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +source /tmp/fut-base/shell/config/default_shell.sh +[ -e "/tmp/fut_set_env.sh" ] && source /tmp/fut_set_env.sh +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="cm2/$(basename "$0")" +help() +{ +cat << EOF +${tc_name} [-h] arguments + +The test establishes GRE tunnel via wireless backhaul connection to LEAF device. + +Options: + -h: show this help message +Positional arguments: + GW_WAN_ETH_IFACE=$1: Interface name of the wired ethernet uplink (str, required) + GW_BHAUL_AP_IFNAME=$2: Interface name of the backhaul AP interface (str, required) + GW_BHAUL_VIF_RADIO_IDX=$3: VIF index number of the backhaul AP interface (int, required) + GW_RADIO_IF=$4: Interface name of the radio linked to the GW backhaul AP interface (str, required) + GW_RADIO_CHANNEL=$5: Desired channel for the radio linked to the backhaul AP interface (int, required) + GW_RADIO_HT_MODE=$6: Desired ht_mode for the radio linked to the backhaul AP interface (str, required) + GW_RADIO_HW_MODE=$7: hw_mode of the radio linked to the backhaul AP interface (str, required) + GW_WAN_MTU=$8: MTU of the GW WAN interface (int, required) + GW_GRE_MTU=$9: MTU of the GW GRE parent interface (int, required) + GW_BHAUL_MTU=${10}: MTU of the GW backhaul interface (int, required) + LEAF_RADIO_MAC_RAW=${11}: Physical (MAC) address of the LEAF radio linked to the backhaul STA interface (str, required) + LEAF_WAN_INET_ADDR=${12}: WAN IP address of the LEAF (str, required) + BHAUL_PSK=${13} Backhaul Pre-Shared Key (str, required) + BHAUL_SSID=${14} Backhaul SSID (str, required) + GW_LAN_BRIDGE=${15}: Interface name for GW LAN bridge (str, optional, default: "br-home") + GW_WAN_BRIDGE=${16}: Interface name for GW WAN bridge (str, optional, default: "br-wan") + GW_PATCH_HOME_TO_WAN=${17}: Interface name for GW LAN-to-WAN patch port (str, optional, default: "patch-h2w") + GW_PATCH_WAN_TO_HOME=${18}: Interface name for GW WAN-to-LAN patch port (str, optional, default: "patch-w2h") + UPSTREAM_ROUTER_IP=${19}: IP address of the upstream router - RPI server (str, optional, default: "192.168.200.1") + INTERNET_CHECK_IP=${20}: IP address to test internet connection (str, optional, default: "1.1.1.1") + ASSOCIATE_RETRY_COUNT=${21}: Number of checks for LEAF backhaul association to GW (int, optional, default: 30) + ASSOCIATE_RETRY_SLEEP=${22}: Seconds between checks for LEAF backhaul association to GW (int, optional, default: 5}) + N_PING=${23}: Number of ping packets to send when checking connectivity (int, optional, default: 10) + +Dependencies: + This script is executed on GW, simultaneously as the corresponding script on LEAF + Coordinate GW and LEAF backhaul radios, channels + GW operates in bridge mode +Examples of usage: + ${tc_name} "eth0" "bhaul-ap-50" "1" "wifi1" "44" "HT80" "11ac" "1500" "1562" "1600" \ + "60:b4:f7:f0:21:47" 192.168.200.11" "PreSharedKey" "fut.bhaul" + ${tc_name} "eth0" "bhaul-ap-50" "1" "wifi1" "44" "HT80" "11ac" "1500" "1562" "1600" \ + "60:b4:f7:f0:21:47" "192.168.200.11" "PreSharedKey" "fut.bhaul" \ + "br-home" "br-wan" "patch-h2w" "patch-w2h" "192.168.200.1" "1.1.1.1" "11" "4" "2" +EOF +raise "Printed help and usage string" -l "$tc_name" -arg +} + +while getopts h option; do + case "$option" in + h) + help + ;; + esac +done + +# INPUT ARGUMENTS: +NARGS=14 +[ $# -lt ${NARGS} ] && raise "Requires at least '${NARGS}' input argument(s)" -arg +# Input arguments specific to GW, required: +GW_WAN_ETH_IFACE=${1} +GW_BHAUL_AP_IFNAME=${2} +GW_BHAUL_VIF_RADIO_IDX=${3} +GW_RADIO_IF=${4} +GW_RADIO_CHANNEL=${5} +GW_RADIO_HT_MODE=${6} +GW_RADIO_HW_MODE=${7} +GW_WAN_MTU=${8} +GW_GRE_MTU=${9} +GW_BHAUL_MTU=${10} +LEAF_RADIO_MAC_RAW=${11} +LEAF_WAN_INET_ADDR=${12} +# Input arguments common to GW and LEAF, required: +BHAUL_PSK=${13} +BHAUL_SSID=${14} +# Enforce required arguments: +[ -z "${GW_WAN_ETH_IFACE}" ] && raise "Empty parameter GW_WAN_ETH_IFACE" -l "${tc_name}" -arg +[ -z "${GW_BHAUL_AP_IFNAME}" ] && raise "Empty parameter GW_BHAUL_AP_IFNAME" -l "${tc_name}" -arg +[ -z "${GW_BHAUL_VIF_RADIO_IDX}" ] && raise "Empty parameter GW_BHAUL_VIF_RADIO_IDX" -l "${tc_name}" -arg +[ -z "${GW_RADIO_IF}" ] && raise "Empty parameter GW_RADIO_IF" -l "${tc_name}" -arg +[ -z "${GW_RADIO_CHANNEL}" ] && raise "Empty parameter GW_RADIO_CHANNEL" -l "${tc_name}" -arg +[ -z "${GW_RADIO_HT_MODE}" ] && raise "Empty parameter GW_RADIO_HT_MODE" -l "${tc_name}" -arg +[ -z "${GW_RADIO_HW_MODE}" ] && raise "Empty parameter GW_RADIO_HW_MODE" -l "${tc_name}" -arg +[ -z "${GW_WAN_MTU}" ] && raise "Empty parameter GW_WAN_MTU" -l "${tc_name}" -arg +[ -z "${GW_GRE_MTU}" ] && raise "Empty parameter GW_GRE_MTU" -l "${tc_name}" -arg +[ -z "${GW_BHAUL_MTU}" ] && raise "Empty parameter GW_BHAUL_MTU" -l "${tc_name}" -arg +[ -z "${LEAF_RADIO_MAC_RAW}" ] && raise "Empty parameter LEAF_RADIO_MAC_RAW" -l "${tc_name}" -arg +[ -z "${LEAF_WAN_INET_ADDR}" ] && raise "Empty parameter LEAF_WAN_INET_ADDR" -l "${tc_name}" -arg +[ -z "${BHAUL_PSK}" ] && raise "Empty parameter BHAUL_PSK" -l "${tc_name}" -arg +[ -z "${BHAUL_SSID}" ] && raise "Empty parameter BHAUL_SSID" -l "${tc_name}" -arg +# Input arguments specific to GW, optional: +GW_LAN_BRIDGE=${15:-"br-home"} +GW_WAN_BRIDGE=${16:-"br-wan"} +GW_PATCH_HOME_TO_WAN=${17:-"patch-h2w"} +GW_PATCH_WAN_TO_HOME=${18:-"patch-w2h"} +# Input arguments common to GW and LEAF, optional: +UPSTREAM_ROUTER_IP=${19:-"192.168.200.1"} +INTERNET_CHECK_IP=${20:-"1.1.1.1"} +ASSOCIATE_RETRY_COUNT=${21:-"30"} +ASSOCIATE_RETRY_SLEEP=${22:-"5"} +N_PING=${23:-"10"} +# Variables constructed from input arguments, constants: +GW_BHAUL_AP_MODE="ap" +GW_BHAUL_IP_ASSIGN_SCHEME="none" +GW_RADIO_CHANNEL_MODE="manual" +GW_BHAUL_BROADCAST_N="255" +GW_BHAUL_INET_ADDR_N="129" +GW_BHAUL_NETMASK="255.255.255.128" +GW_BHAUL_SUBNET="169.254.5" +GW_BHAUL_BROADCAST="${GW_BHAUL_SUBNET}.${GW_BHAUL_BROADCAST_N}" +GW_BHAUL_DHCPD_START="${GW_BHAUL_SUBNET}.$((GW_BHAUL_INET_ADDR_N + 1))" +GW_BHAUL_DHCPD_STOP="${GW_BHAUL_SUBNET}.$((GW_BHAUL_BROADCAST_N - 1))" +GW_BHAUL_INET_ADDR="${GW_BHAUL_SUBNET}.${GW_BHAUL_INET_ADDR_N}" +GW_BHAUL_DHCPD='["map",[["dhcp_option","26,1600"],["force","false"],["lease_time","12h"],["start","'${GW_BHAUL_DHCPD_START}'"],["stop","'${GW_BHAUL_DHCPD_STOP}'"]]]' +log "$tc_name: Get the corresponding LEAF radio interface MAC address, for whitelisting" +LEAF_RADIO_MAC="$(echo "$LEAF_RADIO_MAC_RAW" | tr [A-Z] [a-z])" + +# SETUP: +log "$tc_name: GW initial setup" +cm_disable_fatal_state +wpd_set_auto +stop_healthcheck +stop_managers +start_openswitch +start_wireless_driver +start_specific_manager nm +start_specific_manager wm + +log "$tc_name: Configure GW uplink" +MAC_ETH0=$(mac_get "${GW_WAN_ETH_IFACE}" | tr [A-Z] [a-z]) +[ -z "${MAC_ETH0}" ] && raise "Ethernet MAC 0 empty" -arg +MAC_ETH1=$(printf "%02x:%s" $(( 0x${MAC_ETH0%%:*} | 0x2 )) "${MAC_ETH0#*:}") +[ -z "${MAC_ETH1}" ] && raise "Ethernet MAC 1 empty" -arg + +add_ovs_bridge "${GW_WAN_BRIDGE}" "${MAC_ETH0}" "${GW_WAN_MTU}" +add_ovs_bridge "${GW_LAN_BRIDGE}" "${MAC_ETH1}" +add_bridge_port "${GW_WAN_BRIDGE}" "${GW_WAN_ETH_IFACE}" + +remove_sta_interfaces 60 && + log -deb "$tc_name: STA interfaces removed from GW" || + raise "Failed to remove STA interfaces from GW" -l "$tc_name" -ds + +create_inet_entry2 \ + -if_name "${GW_WAN_BRIDGE}" \ + -if_type "bridge" \ + -ip_assign_scheme "dhcp" \ + -upnp_mode "external" \ + -NAT true \ + -network true \ + -enabled true && + log -deb "$tc_name: Interface ${GW_WAN_BRIDGE} successfully created" || + raise "Failed to create interface ${GW_WAN_BRIDGE}" -l "$tc_name" -ds + +check_pid_udhcp "${GW_WAN_BRIDGE}" +# Enforce router connectivity, check-only internet connectivity +wait_for_function_response 0 "ping -c${N_PING} ${UPSTREAM_ROUTER_IP}" && + log -deb "$tc_name: Can ping router" || + raise "Can not ping router" -ds +wait_for_function_response 0 "ping -c${N_PING} ${INTERNET_CHECK_IP}" && + log -deb "$tc_name: Can ping internet" || + log -deb "$tc_name: Can not ping internet" + +log "$tc_name: Configure GW radio half way" +configure_radio_interface \ + -if_name "${GW_RADIO_IF}" \ + -channel_mode "${GW_RADIO_CHANNEL_MODE}" \ + -hw_mode "${GW_RADIO_HW_MODE}" \ + -enabled true && + log -deb "$tc_name: Success initial configure_radio_interface" || + raise "Failure initial configure_radio_interface" -l "$tc_name" -ds + +log "$tc_name: Create GW backhaul AP" +create_vif_interface \ + -radio_if_name "${GW_RADIO_IF}" \ + -if_name "${GW_BHAUL_AP_IFNAME}" \ + -dynamic_beacon false \ + -mac_list '["set",["'${LEAF_RADIO_MAC//" "/}'"]]' \ + -mac_list_type whitelist \ + -mode "${GW_BHAUL_AP_MODE}" \ + -security '["map",[["encryption","WPA-PSK"],["key","'${BHAUL_PSK}'"],["mode","2"]]]' \ + -ssid "${BHAUL_SSID}" \ + -ssid_broadcast "disabled" \ + -vif_radio_idx "${GW_BHAUL_VIF_RADIO_IDX}" \ + -enabled true && + log -deb "$tc_name - Success create_vif_interface" || + raise "Failure create_vif_interface" -l "$tc_name" -ds + +log "$tc_name: Configure GW radio channel and ht_mode now that AP is created" +configure_radio_interface \ + -if_name "${GW_RADIO_IF}" \ + -channel "${GW_RADIO_CHANNEL}" \ + -ht_mode "${GW_RADIO_HT_MODE}" && + log -deb "$tc_name - Success subsequent configure_radio_interface" || + raise "Failure subsequent configure_radio_interface" -l "$tc_name" -ds + +log "$tc_name: Configure GW backhaul AP" +create_inet_entry2 \ + -if_name "${GW_BHAUL_AP_IFNAME}" \ + -broadcast "${GW_BHAUL_BROADCAST}" \ + -dhcpd "${GW_BHAUL_DHCPD}" \ + -if_type "vif" \ + -inet_addr "${GW_BHAUL_INET_ADDR}" \ + -ip_assign_scheme "static" \ + -mtu "${GW_BHAUL_MTU}" \ + -NAT false \ + -netmask "${GW_BHAUL_NETMASK}" \ + -network true \ + -enabled true && + log -deb "$tc_name: Interface ${GW_BHAUL_AP_IFNAME} successfully created" || + raise "Failed to create interface ${GW_BHAUL_AP_IFNAME}" -l "$tc_name" -ds + +log "$tc_name: Waiting for LEAF backhaul STA to associate to GW backhaul AP" +fnc_str="get_ovsdb_entry_value DHCP_leased_IP inet_addr -w hwaddr ${LEAF_RADIO_MAC} -raw" +wait_for_function_output "notempty" "${fnc_str}" ${ASSOCIATE_RETRY_COUNT} ${ASSOCIATE_RETRY_SLEEP} +if [ $? -eq 0 ]; then + LEAF_STA_INET_ADDR=$($fnc_str) && + log -deb "$tc_name: LEAF ${LEAF_STA_INET_ADDR} associated" || + raise "Failure: LEAF ${LEAF_STA_INET_ADDR} not associated" -l "$tc_name" -ds +else + raise "$tc_name - LEAF ${LEAF_STA_INET_ADDR} NOT associated" -l "$tc_name" -ds +fi +GW_GRE_NAME="pgd$(echo ${LEAF_STA_INET_ADDR//./-}| cut -d'-' -f3-4)" +echo "${GW_GRE_NAME}" +GW_AP_INET_ADDR=$(${OVSH} s Wifi_Inet_Config -w if_name=="${GW_BHAUL_AP_IFNAME}" inet_addr -r) +echo "$GW_AP_INET_ADDR" + +# TESTCASE: +log "$tc_name: Create GW GRE parent interface" +create_inet_entry2 \ + -if_name "${GW_GRE_NAME}" \ + -if_type "gre" \ + -gre_ifname "${GW_BHAUL_AP_IFNAME}" \ + -gre_local_inet_addr "${GW_AP_INET_ADDR// /}" \ + -gre_remote_inet_addr "$LEAF_STA_INET_ADDR" \ + -ip_assign_scheme "${GW_BHAUL_IP_ASSIGN_SCHEME}" \ + -mtu "${GW_GRE_MTU}" \ + -network true \ + -enabled true && + log -deb "$tc_name: Interface ${GW_GRE_NAME} successfully created" || + raise "Failed to create interface ${GW_GRE_NAME}" -l "$tc_name" -tc + +wait_for_function_exitcode 0 "interface_is_up ${GW_GRE_NAME}" "${ASSOCIATE_RETRY_COUNT}" "${ASSOCIATE_RETRY_SLEEP}" && + log -deb "$tc_name: Interface ${GW_GRE_NAME} is up on system" || + raise "Interface ${GW_GRE_NAME} is not up on system" -l "$tc_name" -tc + +log "$tc_name: Put GW GRE interface into LAN bridge, create WAN-LAN patch ports" +add_bridge_port "${GW_LAN_BRIDGE}" "${GW_GRE_NAME}" +add_bridge_port "${GW_WAN_BRIDGE}" "${GW_PATCH_WAN_TO_HOME}" +set_interface_patch "${GW_WAN_BRIDGE}" "${GW_PATCH_WAN_TO_HOME}" "${GW_PATCH_HOME_TO_WAN}" +add_bridge_port "${GW_LAN_BRIDGE}" "${GW_PATCH_HOME_TO_WAN}" +set_interface_patch "${GW_LAN_BRIDGE}" "${GW_PATCH_HOME_TO_WAN}" "${GW_PATCH_WAN_TO_HOME}" + +log "$tc_name: Test GW connectivity to LEAF GRE and WAN IP" + +LEAF_GRE_INET_ADDR=$(cat /tmp/dhcp.leases | grep "${LEAF_RADIO_MAC}" | awk '{print $3}') +[ -z "${LEAF_GRE_INET_ADDR}" ] && raise "Failed to get LEAF GRE IP" -l "${tc_name}" -tc +ping -c${N_PING} "${LEAF_GRE_INET_ADDR}" && log -deb "Can ping LEAF GRE" || raise "Can not ping LEAF GRE" -tc + +[ -z "${LEAF_WAN_INET_ADDR}" ] && raise "Failed to get LEAF WAN IP" -l "${tc_name}" -tc +ping -c${N_PING} "${LEAF_WAN_INET_ADDR}" && log -deb "Can ping LEAF WAN" || raise "Can not ping LEAF WAN" -tc + +pass diff --git a/src/cm2/fut/cm2_verify_gre_tunnel_ref_extender.sh b/src/cm2/fut/cm2_verify_gre_tunnel_ref_extender.sh new file mode 100755 index 00000000..67605a44 --- /dev/null +++ b/src/cm2/fut/cm2_verify_gre_tunnel_ref_extender.sh @@ -0,0 +1,156 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +source /tmp/fut-base/shell/config/default_shell.sh +[ -e "/tmp/fut_set_env.sh" ] && source /tmp/fut_set_env.sh +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="cm2/$(basename "$0")" +help() +{ +cat << EOF +${tc_name} [-h] arguments + +The test checks for an established GRE tunnel via wireless backhaul connection to GW device. +This script is only complementary to the one running on GW device. The assumption is, that the LEAF device +is a tested reference device, and GW device acts DUT, where all procedures are done manually. This script +does minimal configuring, only ensuring that backhaul SSID and PSK are configured correctly, as this is usually +preconfigured into device firmware. Intermediate steps are executed automatically by OpenSync managers, +running independently from FUT scripts, and only checks are made by the script, not configuration steps. + +Options: + -h: show this help message +Arguments: + LEAF_BHAUL_STA_IFNAME=$1: Interface name of the backhaul STA interface (str, required) + LEAF_WAN_BRIDGE=$2: Interface name for LEAF WAN bridge (str, required) + BHAUL_PSK=$3 Backhaul Pre-Shared Key (str, required) + BHAUL_SSID=$4 Backhaul SSID (str, required) + UPSTREAM_ROUTER_IP=$5: IP address of the upstream router - RPI server (str, optional, default: "192.168.200.1") + INTERNET_CHECK_IP=$6: IP address to test internet connection (str, optional, default: "1.1.1.1") + ASSOCIATE_RETRY_COUNT=$7: Number of checks for LEAF backhaul association to GW (int, optional, default: 30) + ASSOCIATE_RETRY_SLEEP=$8: Seconds between checks for LEAF backhaul association to GW (int, optional, default: 5}) + N_PING=$9: Number of ping packets to send when checking connectivity (int, optional, default: 5) +Dependencies: + It is assumed that LEAF has been configured to "default" OpenSync state, without prior FUT configuration: utility/device/default_setup.sh + This script is executed on LEAF, simultaneously as the corresponding script on GW + Coordinate GW and LEAF backhaul radios, channels + GW operates in bridge mode +Examples of usage: + ${tc_name} "bhaul-sta-l50" "br-wan" "PreSharedKey" "fut.bhaul" + ${tc_name} "bhaul-sta-l50" "br-wan" "PreSharedKey" "fut.bhaul" "192.168.200.1" "1.1.1.1" "10" "3" "2" +EOF +raise "Printed help and usage string" -l "$tc_name" -arg +} + +while getopts h option; do + case "$option" in + h) + help + ;; + esac +done + +# INPUT ARGUMENTS: +NARGS=4 +[ $# -lt ${NARGS} ] && raise "Requires at least '${NARGS}' input argument(s)" -arg +# Input arguments specific to LEAF, required: +LEAF_BHAUL_STA_IFNAME=${1} +LEAF_WAN_BRIDGE=${2} +# Input arguments common to GW and LEAF, required: +BHAUL_PSK=${3} +BHAUL_SSID=${4} +# Enforce required arguments: +[ -z "${LEAF_BHAUL_STA_IFNAME}" ] && raise "Empty parameter LEAF_BHAUL_STA_IFNAME" -l "${tc_name}" -arg +[ -z "${LEAF_WAN_BRIDGE}" ] && raise "Empty parameter LEAF_WAN_BRIDGE" -l "${tc_name}" -arg +[ -z "${BHAUL_PSK}" ] && raise "Empty parameter BHAUL_PSK" -l "${tc_name}" -arg +[ -z "${BHAUL_SSID}" ] && raise "Empty parameter BHAUL_SSID" -l "${tc_name}" -arg +# Input arguments common to GW and LEAF, optional: +UPSTREAM_ROUTER_IP=${5:-"192.168.200.1"} +INTERNET_CHECK_IP=${6:-"1.1.1.1"} +ASSOCIATE_RETRY_COUNT=${7:-"30"} +ASSOCIATE_RETRY_SLEEP=${8:-"5"} +N_PING=${9:-"5"} +# Variables constructed from input arguments, constants: +LEAF_GRE_NAME="g-${LEAF_BHAUL_STA_IFNAME}" + +log "$tc_name: Check LEAF backhaul STA interface" +fnc_str="check_interface_exists2 ${LEAF_BHAUL_STA_IFNAME}" +wait_for_function_response 0 "${fnc_str}" && + log -deb "$tc_name: Interface ${LEAF_BHAUL_STA_IFNAME} exists on system" || + raise"Interface ${LEAF_BHAUL_STA_IFNAME} does NOT exist on system" -l "$tc_name" -ds +check_ovsdb_entry Wifi_VIF_Config -w if_name "${LEAF_BHAUL_STA_IFNAME}" && + log -deb "$tc_name: Entry ${LEAF_BHAUL_STA_IFNAME} exists in Wifi_VIF_Config" || + raise "Entry ${LEAF_BHAUL_STA_IFNAME} does NOT exist in Wifi_VIF_Config" -l "${tc_name}" -ds + +log "$tc_name: Insert new LEAF backhaul test credentials" +log -deb "$tc_name: LEAF backhaul credentials are preset on device FW, changing them serves test purposes only" +insert_ovsdb_entry2 Wifi_Credential_Config \ + -i onboard_type "gre" \ + -i ssid "${BHAUL_SSID}" \ + -i security '["map",[["encryption","WPA-PSK"],["key","'${BHAUL_PSK}'"],["mode","2"]]]' && + log -deb "$tc_name: Success insert_ovsdb_entry Wifi_Credential_Config" || + raise "Failure insert_ovsdb_entry Wifi_Credential_Config" -l "$tc_name" -tc +cred_uuid=$(get_ovsdb_entry_value Wifi_Credential_Config _uuid -w ssid "${BHAUL_SSID}" -r | cut -d'"' -f4) && + log -deb "$tc_name: Retrieved Wifi_Credential_Config UUID" || + raise "Failed to retrieve Wifi_Credential_Config UUID" -l "$tc_name" -tc + +log "$tc_name: Configure LEAF backhaul test credentials" +create_vif_interface \ + -if_name "${LEAF_BHAUL_STA_IFNAME}" \ + -credential_configs '["set",[["uuid","'${cred_uuid}'"]]]' \ + -security '["map",[["encryption","WPA-PSK"],["key","'${BHAUL_PSK}'"],["mode","2"]]]' \ + -ssid "${BHAUL_SSID}" && + log -deb "$tc_name - Successfully configured LEAF backhaul test credentials" || + raise "Failed to configure LEAF backhaul test credentials" -l "$tc_name" -ds + +log "$tc_name: Waiting for LEAF backhaul STA to associate to GW backhaul AP" +check_sta_associated "${LEAF_BHAUL_STA_IFNAME}" "${ASSOCIATE_RETRY_COUNT}" "${ASSOCIATE_RETRY_SLEEP}" && + log -deb "$tc_name - LEAF backhaul STA associated to GW backhaul AP" || + raise "Failed to associate to GW backhaul AP in ${ASSOCIATE_RETRY_COUNT} retries" -l "$tc_name" -ow + +log "$tc_name: LEAF creates GRE interface" +check_interface_exists2 "${LEAF_GRE_NAME}" + +log "$tc_name: Check that GRE interface is in WAN bridge on LEAF node" +check_if_port_in_bridge "${LEAF_WAN_BRIDGE}" "${LEAF_GRE_NAME}" + +log "$tc_name: Check that LEAF starts DHCP client on br-wan to get WAN IP" +check_pid_udhcp "${LEAF_WAN_BRIDGE}" + +# Enforce router connectivity, check-only internet connectivity +log "$tc_name: Check that LEAF has WAN connectivity via GRE tunnel" +wait_for_function_response 0 "ping -c${N_PING} ${UPSTREAM_ROUTER_IP}" && + log -deb "$tc_name: Can ping router" || + raise "Can not ping router" -tc +wait_for_function_response 0 "ping -c${N_PING} ${INTERNET_CHECK_IP}" && + log -deb "$tc_name: Can ping internet" || + log -deb "$tc_name: Can not ping internet" + +pass diff --git a/src/cm2/fut/unit.mk b/src/cm2/fut/unit.mk new file mode 100644 index 00000000..b3efd6da --- /dev/null +++ b/src/cm2/fut/unit.mk @@ -0,0 +1,43 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_cm + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_CM),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/cm + +UNIT_FILE := cm2_ble_status_interface_down.sh +UNIT_FILE += cm2_ble_status_internet_block.sh +UNIT_FILE += cm2_cloud_down.sh +UNIT_FILE += cm2_dns_failure.sh +UNIT_FILE += cm2_internet_lost.sh +UNIT_FILE += cm2_link_lost.sh +UNIT_FILE += cm2_setup.sh +UNIT_FILE += cm2_ssl_check.sh +UNIT_FILE += cm2_verify_gre_tunnel_dut_gw.sh +UNIT_FILE += cm2_verify_gre_tunnel_ref_extender.sh diff --git a/src/cm2/kconfig/Kconfig.managers b/src/cm2/kconfig/Kconfig.managers index 8e5db400..16f53d43 100644 --- a/src/cm2/kconfig/Kconfig.managers +++ b/src/cm2/kconfig/Kconfig.managers @@ -12,6 +12,12 @@ if MANAGER_CM help Manager startup options + config CM2_USE_WAN_LINK_MANAGEMENT + bool "Use CM to manage WAN links" + default y + help + Use Wifi_Master_State table to manage WAN links + config CM2_USE_DRYRUN_ON_GRE bool "Use udhcpc dryrun on gre interfaces" default y @@ -157,7 +163,7 @@ if MANAGER_CM help Threshold of subsequent check failures to restart OpenSync - config CM2_STABILITY_THRESH_REST_CON + config CM2_STABILITY_THRESH_ROUTER int "Threshold of restore connection" default 4 help @@ -181,16 +187,23 @@ if MANAGER_CM help Threshold of loadavg (number of currently executing kernel scheduling entities) to allow trigger stability checking - config CM2_STABILITY_THRESH_TCPDUMP + config CM2_STABILITY_THRESH_TCPDUMP int "Threshold of tcpdump running" default 4 help Threshold of subsequent router check failures to trigger collect data on main interface + config CM2_STABILITY_USE_RESTORE_SWITCH_CFG + bool "Use restoring switch configuration" + default n + help + Some devices require restoring switch configuration when problems with connectivity is detected + endif + config CM2_USE_EXTRA_DEBUGS - bool "Use additional debug logs" - default y - help - Enable additional debug logs" + bool "Use additional debug logs" + default y + help + Enable additional debug logs" endif diff --git a/src/cm2/src/cm2.h b/src/cm2/src/cm2.h index e7852a74..3242a191 100644 --- a/src/cm2/src/cm2.h +++ b/src/cm2/src/cm2.h @@ -41,9 +41,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define VIF_TYPE_NAME "vif" #define ETH_TYPE_NAME "eth" #define VLAN_TYPE_NAME "vlan" +#define PPPOE_TYPE_NAME "pppoe" #define GRE_TYPE_NAME "gre" #define BRIDGE_TYPE_NAME "bridge" +#ifdef CONFIG_TARGET_USE_WAN_BRIDGE +#ifdef CONFIG_TARGET_WAN_BRIDGE_NAME +#define CM2_WAN_BRIDGE_NAME CONFIG_TARGET_WAN_BRIDGE_NAME +#else +#define CM2_WAN_BRIDGE_NAME SCHEMA_CONSTS_BR_NAME_WAN +#endif /* CONFIG_TARGET_WAN_BRIDGE_NAME */ +#else +#define CM2_WAN_BRIDGE_NAME "" +#endif /* CONFIG_TARGET_USE_WAN_BRIDGE */ + typedef enum { CM2_LINK_NOT_DEFINED, @@ -98,6 +109,15 @@ typedef enum #define CM2_HOSTNAME_MAX 256 #define CM2_PROTO_MAX 6 +#ifdef BUILD_HAVE_LIBCARES +typedef struct +{ + char addr[INET6_ADDRSTRLEN]; + int addr_type; + ds_list_node_t le_node; +} cm2_addr_list_entry; +#endif + typedef struct { bool updated; @@ -111,15 +131,8 @@ typedef struct struct addrinfo *ai_list; struct addrinfo *ai_curr; #else - /* h_addr_list comes from hostent structure which - * is defined in - * An array of pointers to network addresses for the host (in - * network byte order), terminated by a null pointer. - * */ - char **h_addr_list; - int h_length; - int h_addrtype; - int h_cur_idx; + ds_dlist_t addr_list; + cm2_addr_list_entry *cur; #endif } cm2_addr_t; @@ -137,17 +150,32 @@ typedef struct { int blocked_tag; } cm2_vtag_t; +typedef enum { + CM2_IP_NOT_SET, + CM2_IP_NONE, + CM2_IP_STATIC, + CM2_IPV4_DHCP, + CM2_IPV6_DHCP, +} cm2_ip_assign_scheme; + +typedef struct { + cm2_ip_assign_scheme ips; + bool is_ipa; +} cm2_ip; + typedef struct { char if_name[IFNAME_SIZE]; char if_type[IFTYPE_SIZE]; - bool has_L3; + bool is_bridge; + char bridge_name[IFNAME_SIZE]; bool is_used; bool restart_pending; int priority; - bool is_ip; + cm2_ip ip; bool is_limp_state; bool gretap_softwds; + char gateway_hwaddr[OS_MACSTR_SZ]; cm2_vtag_t vtag; } cm2_main_link_t; @@ -183,6 +211,7 @@ typedef struct bool fast_reconnect; bool resolve_retry; int resolve_retry_cnt; + int gw_offline_cnt; } cm2_state_t; extern cm2_state_t g_state; @@ -236,6 +265,13 @@ bool cm2_ovsdb_connection_update_loop_state(const char *if_name, bool state); bool cm2_ovsdb_WiFi_Inet_State_is_ip(const char *if_name); void cm2_ovsdb_connection_clean_link_counters(char *if_name); bool cm2_ovsdb_validate_bridge_port_conf(char *bname, char *pname); +bool cm2_ovsdb_is_ipv6_global_link(const char *if_name); +void cm2_ovsdb_set_dhcp_client(const char *if_name, bool enabled); +bool cm2_ovsdb_is_gw_offline_ready(void); +bool cm2_ovsdb_enable_gw_offline_conf(void); +bool cm2_ovsdb_disable_gw_offline_conf(void); +int cm2_get_link_ip(char *if_name, cm2_ip *ip); + #ifdef CONFIG_CM2_USE_EXTRA_DEBUGS void cm2_ovsdb_dump_debug_data(void); #else @@ -308,6 +344,24 @@ static inline void cm2_wdt_close(struct ev_loop *loop) } #endif /* CONFIG_CM2_USE_WDT */ +static inline bool cm2_is_wan_bridge(void) +{ +#ifdef CONFIG_TARGET_USE_WAN_BRIDGE + return true; +#else + return false; +#endif +} + +static inline bool cm2_is_wan_link_management(void) +{ +#ifdef CONFIG_CM2_USE_WAN_LINK_MANAGEMENT + return true; +#else + return false; +#endif +} + // net int cm2_ovs_insert_port_into_bridge(char *bridge, char *port, int flag_add); void cm2_dhcpc_start_dryrun(char* ifname, char *iftype, int cnt); @@ -316,4 +370,6 @@ bool cm2_is_eth_type(const char *if_type); bool cm2_is_wifi_type(const char *if_type); void cm2_delayed_eth_update(char *if_name, int timeout); bool cm2_is_iface_in_bridge(const char *bridge, const char *port); +char* cm2_get_uplink_name(void); +void cm2_update_limp_state(void); #endif /* CM2_H_INCLUDED */ diff --git a/src/cm2/src/cm2_event.c b/src/cm2/src/cm2_event.c index aaa5849e..60ce561c 100644 --- a/src/cm2/src/cm2_event.c +++ b/src/cm2/src/cm2_event.c @@ -40,8 +40,8 @@ In link selection state: waiting for main link that can be used if yes goes to br wan ip state -In br wan ip state - Waiting for IP on br-wan with used link +In wan ip state + Waiting for IP on WAN bridge or uplink if yes goes to init ovs state In init ovs state: @@ -116,9 +116,11 @@ Note-1: the wait for re-connect back to same manager addr because #define CM2_ONBOARD_WAN_IP_TIMEOUT 20 #define CM2_RESOLVE_TIMEOUT 180 -#define CM2_MAX_DISCONNECTS 4 +#define CM2_MAX_DISCONNECTS 10 #define CM2_STABLE_PERIOD 300 // 5 min #define CM2_RESOLVE_RETRY_THRESHOLD 10 +#define CM2_GW_OFFLINE_RETRY_THRESHOLD 3 + // state info #define CM2_STATE_DIR "/tmp/plume/" #define CM2_STATE_FILE CM2_STATE_DIR"cm.state" @@ -384,14 +386,34 @@ static void cm2_link_sel_update_ble_state(void) { } static void cm2_trigger_restart_managers(void) { - if (!cm2_vtag_stability_check()) { + bool r; + + r = cm2_vtag_stability_check(); + if (!r) { LOGI("Skip restart system due to vtag pending"); cm2_reset_time(); return; } - if (g_state.link.is_limp_state) { - LOGI("Skip restart system due to limp state"); + if (g_state.gw_offline_cnt < CM2_GW_OFFLINE_RETRY_THRESHOLD) { + r = cm2_ovsdb_is_gw_offline_ready(); + if (r) + g_state.gw_offline_cnt++; + + if (g_state.gw_offline_cnt == CM2_GW_OFFLINE_RETRY_THRESHOLD) { + r = cm2_ovsdb_enable_gw_offline_conf(); + if (!r) { + LOGW("Enabling GW offline configuration failed"); + g_state.gw_offline_cnt--; + } else { + LOGI("GW offline configuration enabled"); + } + } + } + + if (g_state.link.is_limp_state || g_state.gw_offline_cnt > 0) { + LOGI("Skip restart managers. Limp state = %d gw_offline_cnt = %d", + g_state.link.is_limp_state, g_state.gw_offline_cnt); cm2_reset_time(); return; } @@ -426,9 +448,9 @@ static bool cm2_set_new_vtag(void) { } } - if (!cm2_ovsdb_update_Port_tag(CONFIG_TARGET_WAN_BRIDGE_NAME, g_state.link.vtag.tag, true)) { + if (!cm2_ovsdb_update_Port_tag(cm2_get_uplink_name(), g_state.link.vtag.tag, true)) { LOGW("vtag: Failed to set new vtag = %d on %s", - g_state.link.vtag.tag, CONFIG_TARGET_WAN_BRIDGE_NAME); + g_state.link.vtag.tag, cm2_get_uplink_name()); return false; } g_state.link.vtag.state = CM2_VTAG_PENDING; @@ -440,16 +462,36 @@ static bool cm2_block_vtag(void) { g_state.link.vtag.state = CM2_VTAG_BLOCKED; g_state.link.vtag.failure = 0; g_state.link.vtag.blocked_tag = g_state.link.vtag.tag; - if (!cm2_ovsdb_update_Port_tag(CONFIG_TARGET_WAN_BRIDGE_NAME, g_state.link.vtag.tag, false)) { + if (!cm2_ovsdb_update_Port_tag(cm2_get_uplink_name(), g_state.link.vtag.tag, false)) { LOGW("vtag: Failed to remove vtag = %d on %s", - g_state.link.vtag.tag, CONFIG_TARGET_WAN_BRIDGE_NAME); + g_state.link.vtag.tag, cm2_get_uplink_name()); return false; } return true; } +static void cm2_handle_link_used(char *if_name, char *if_type, cm2_ip *ip) +{ + if (!cm2_is_wan_link_management() && cm2_is_eth_type(if_type)) + return; + + if (ip->ips == CM2_IPV4_DHCP && ip->is_ipa) { + LOGN("Refresh WAN link"); + cm2_ovsdb_refresh_dhcp(if_name); + return; + } + + if (ip->ips == CM2_IP_NONE) { + LOGI("%s: Trigger dhcp client for used link", if_name); + cm2_ovsdb_set_dhcp_client(if_name, true); + } +} + void cm2_update_state(cm2_reason_e reason) { + int ret; + char *uplink; + start: cm2_log_state(reason); cm2_state_e old_state = g_state.state; @@ -464,18 +506,24 @@ void cm2_update_state(cm2_reason_e reason) g_state.state == CM2_STATE_WAN_IP || g_state.state == CM2_STATE_NTP_CHECK; + uplink = cm2_get_uplink_name(); + switch(reason) { case CM2_REASON_LINK_NOT_USED: cm2_set_state(true, CM2_STATE_LINK_SEL); break; case CM2_REASON_LINK_USED: - if (cm2_ovsdb_WiFi_Inet_State_is_ip(CONFIG_TARGET_WAN_BRIDGE_NAME)) { - LOGN("Refresh br-wan state"); - g_state.link.is_ip = false; - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); - } + ret = cm2_get_link_ip(uplink, &g_state.link.ip); + if (ret < 0) + LOGW("%s: Failed get ip info", uplink); + cm2_handle_link_used(uplink, g_state.link.if_type, &g_state.link.ip); cm2_link_sel_update_ble_state(); + if (g_state.link.is_bridge) { + ret = cm2_ovs_insert_port_into_bridge(g_state.link.bridge_name, g_state.link.if_name, true); + if (!ret) + LOGW("%s: Failed to add port %s into %s", __func__, g_state.link.if_name, g_state.link.bridge_name); + } cm2_ovsdb_connection_clean_link_counters(g_state.link.if_name); cm2_connection_req_stability_check(LINK_CHECK); cm2_set_state(true, CM2_STATE_WAN_IP); @@ -483,23 +531,22 @@ void cm2_update_state(cm2_reason_e reason) case CM2_REASON_SET_NEW_VTAG: LOGI("vtag: %d: creating", g_state.link.vtag.tag); if (cm2_set_new_vtag()) { - g_state.link.is_ip = false; - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); + g_state.link.ip.ips = CM2_IP_NONE; + cm2_ovsdb_refresh_dhcp(uplink); cm2_set_state(true, CM2_STATE_WAN_IP); } break; case CM2_REASON_BLOCK_VTAG: LOGI("vtag: %d: blocking", g_state.link.vtag.tag); if (cm2_block_vtag()) { - g_state.link.is_ip = false; - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); + g_state.link.ip.ips = CM2_IP_NONE; + cm2_ovsdb_refresh_dhcp(uplink); cm2_set_state(true, CM2_STATE_WAN_IP); } break; case CM2_REASON_OVS_INIT: LOGI("set async OVS INIT state"); - if (cm2_is_extender()) - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); + cm2_ovsdb_refresh_dhcp(uplink); cm2_set_state(true, CM2_STATE_OVS_INIT); break; default: @@ -577,7 +624,11 @@ void cm2_update_state(cm2_reason_e reason) { LOGI("Waiting for finish get WLAN IP"); } - if (g_state.link.is_ip) + ret = cm2_get_link_ip(uplink, &g_state.link.ip); + if (ret < 0) + LOGW("%s: Failed get ip info", g_state.link.if_name); + + if (g_state.link.ip.is_ipa) { cm2_connection_req_stability_check(ROUTER_CHECK); cm2_set_state(true, CM2_STATE_NTP_CHECK); @@ -643,6 +694,9 @@ void cm2_update_state(cm2_reason_e reason) case CM2_STATE_TRY_RESOLVE: if (cm2_state_changed() || g_state.resolve_retry) { + if (cm2_ovsdb_is_ipv6_global_link(uplink)) + g_state.link.ip.ips = CM2_IPV6_DHCP; + if (g_state.resolve_retry) { LOGI("Trigger retry resolving, cnt: %d/%d", g_state.resolve_retry_cnt, CM2_RESOLVE_RETRY_THRESHOLD); @@ -674,8 +728,7 @@ void cm2_update_state(cm2_reason_e reason) if (cm2_timeout(false) || g_state.resolve_retry_cnt > CM2_RESOLVE_RETRY_THRESHOLD) { cm2_resolve_timeout(); - if (cm2_is_extender()) - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); + cm2_ovsdb_refresh_dhcp(uplink); cm2_restart_ovs_connection(false); return; } @@ -778,6 +831,17 @@ void cm2_update_state(cm2_reason_e reason) cm2_ovsdb_connection_update_unreachable_cloud_counter(g_state.link.if_name, 0); } + if (g_state.gw_offline_cnt == CM2_GW_OFFLINE_RETRY_THRESHOLD) { + LOGI("Device is connected but gw_offline is set"); + ret = cm2_ovsdb_disable_gw_offline_conf(); + if (!ret) { + LOGW("Disabling GW offline configuration failed"); + } else { + g_state.gw_offline_cnt = 0; + LOGI("GW offline configuration disabled"); + } + } + if (!g_state.is_con_stable && cm2_get_time() > CM2_STABLE_PERIOD) { LOGI("Connection stable by %d sec, disconnects: %d", CM2_STABLE_PERIOD, g_state.disconnects); diff --git a/src/cm2/src/cm2_net.c b/src/cm2/src/cm2_net.c index f74452c1..db733dff 100644 --- a/src/cm2/src/cm2_net.c +++ b/src/cm2/src/cm2_net.c @@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "log.h" #include "schema.h" #include "target.h" +#include "osp_unit.h" #include "cm2.h" #include "kconfig.h" @@ -334,9 +335,9 @@ static void cm2_dhcpc_dryrun_cb(struct ev_loop *loop, ev_child *w, int revents) } if (cm2_is_eth_type(dhcp_dryrun->if_type) && - cm2_is_iface_in_bridge(SCHEMA_CONSTS_BR_NAME_HOME, dhcp_dryrun->if_name)) { + cm2_is_iface_in_bridge(CONFIG_TARGET_LAN_BRIDGE_NAME, dhcp_dryrun->if_name)) { LOGI("%s: Skip trigger new dryrun, iface in %s", - dhcp_dryrun->if_name, SCHEMA_CONSTS_BR_NAME_HOME); + dhcp_dryrun->if_name, CONFIG_TARGET_LAN_BRIDGE_NAME); goto release; } @@ -396,7 +397,7 @@ void cm2_dhcpc_start_dryrun(char* ifname, char *iftype, int cnt) { char vendor_classid[256]; - if (target_model_get(vendor_classid, sizeof(vendor_classid)) == false) + if (osp_unit_model_get(vendor_classid, sizeof(vendor_classid)) == false) { tsnprintf(vendor_classid, sizeof(vendor_classid), TARGET_NAME); @@ -480,10 +481,30 @@ void cm2_dhcpc_stop_dryrun(char *ifname) bool cm2_is_eth_type(const char *if_type) { return !strcmp(if_type, ETH_TYPE_NAME) || - !strcmp(if_type, VLAN_TYPE_NAME); + !strcmp(if_type, VLAN_TYPE_NAME)|| + !strcmp(if_type, PPPOE_TYPE_NAME); } bool cm2_is_wifi_type(const char *if_type) { return !strcmp(if_type, VIF_TYPE_NAME) || !strcmp(if_type, GRE_TYPE_NAME); } + +char* cm2_get_uplink_name(void) +{ + if (g_state.link.is_bridge) + return g_state.link.bridge_name; + + return g_state.link.if_name; +} + +void cm2_update_limp_state(void) +{ + if (!cm2_is_eth_type(g_state.link.if_type)) + return; + + if (cm2_is_wan_bridge()) + g_state.link.is_limp_state = !cm2_ovsdb_is_port_name("patch-w2h"); + else + g_state.link.is_limp_state = !g_state.link.is_bridge; +} diff --git a/src/cm2/src/cm2_ovsdb.c b/src/cm2/src/cm2_ovsdb.c index 78544ac4..e2539c72 100644 --- a/src/cm2/src/cm2_ovsdb.c +++ b/src/cm2/src/cm2_ovsdb.c @@ -69,6 +69,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CM2_VIF_MULTI_AP_STA_PARAM "backhaul_sta" +#define CM2_PM_MODULE_NAME "PM" +#define CM2_PM_GW_OFFLINE_CFG "gw_offline_cfg" +#define CM2_PM_GW_OFFLINE_CFG_EN "true" +#define CM2_PM_GW_OFFLINE "gw_offline" +#define CM2_PM_GW_OFFLINE_ON "true" +#define CM2_PM_GW_OFFLINE_OFF "false" +#define CM2_PM_GW_OFFLINE_STATUS "gw_offline_status" +#define CM2_PM_GW_OFFLINE_STATUS_READY "ready" +#define CM2_PM_GW_OFFLINE_STATUS_ACTIVE "active" + static bool cm2_ovsdb_connection_remove_uplink(char *if_name); @@ -85,6 +95,11 @@ ovsdb_table_t table_Wifi_VIF_Config; ovsdb_table_t table_Wifi_VIF_State; ovsdb_table_t table_Port; ovsdb_table_t table_Bridge; +ovsdb_table_t table_IP_Interface; +ovsdb_table_t table_IPv6_Address; +ovsdb_table_t table_Wifi_Route_State; +ovsdb_table_t table_Node_Config; +ovsdb_table_t table_Node_State; void callback_AWLAN_Node(ovsdb_update_monitor_t *mon, struct schema_AWLAN_Node *old_rec, @@ -265,29 +280,187 @@ cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(bool state, char *ifname) return ret == 1; } -static bool -cm2_util_is_static_ip_assign(char *if_name) { +static void +cm2_util_set_ip_cfg(struct schema_Wifi_Inet_State *istate, cm2_ip *ip) +{ + if (istate->ip_assign_scheme_exists) { + if (!strcmp(istate->ip_assign_scheme, "static")) + ip->ips = CM2_IP_STATIC; + else if (!strcmp(istate->ip_assign_scheme, "none")) + ip->ips = CM2_IP_NONE; + else if (!strcmp(istate->ip_assign_scheme, "dhcp")) + ip->ips = CM2_IPV4_DHCP; + } else { + ip->ips = CM2_IP_NOT_SET; + } + + if (!istate->inet_addr_exists || + (istate->inet_addr_exists && (strlen(istate->inet_addr) <= 0 || + !strcmp(istate->inet_addr, "0.0.0.0")))) { + ip->is_ipa = false; + } else { + ip->is_ipa = true; + } +} + +static int +cm2_util_get_ip_inet_state_cfg(char *if_name, cm2_ip *ip) +{ + struct schema_Wifi_Inet_State istate; + int ret; + + MEMZERO(istate); + + ret = ovsdb_table_select_one(&table_Wifi_Inet_State, + SCHEMA_COLUMN(Wifi_Inet_Config, if_name), if_name, &istate); + if (!ret) { + LOGI("%s: %s: Failed to get Wifi_Inet_State item", __func__, if_name); + return -1; + } + + LOGI("%s IP address info: inet_addr = %s assign_scheme = %s", if_name, istate.inet_addr, istate.ip_assign_scheme); + cm2_util_set_ip_cfg(&istate, ip); + + return 0; +} + +void +cm2_ovsdb_set_dhcp_client(const char *if_name, bool enabled) +{ struct schema_Wifi_Inet_Config iconf; + char *ip_assign; + char *filter[] = { "+", + SCHEMA_COLUMN(Wifi_Inet_Config, ip_assign_scheme), + SCHEMA_COLUMN(Wifi_Inet_Config, enabled), + SCHEMA_COLUMN(Wifi_Inet_Config, network), + NULL }; int ret; MEMZERO(iconf); - ret = ovsdb_table_select_one(&table_Wifi_Inet_Config, - SCHEMA_COLUMN(Wifi_Inet_Config, if_name), if_name, &iconf); + LOGI("%s: Updating DHCP settings [%d]", if_name, enabled); + ip_assign = enabled ? "dhcp" : "none"; + STRSCPY(iconf.ip_assign_scheme, ip_assign); + iconf.ip_assign_scheme_exists = true; + iconf.enabled = true; + iconf.network = true; + + ret = ovsdb_table_update_where_f(&table_Wifi_Inet_Config, + ovsdb_where_simple(SCHEMA_COLUMN(Wifi_Inet_Config, if_name), if_name), + &iconf, filter); if (!ret) - LOGI("%s: %s: Failed to get interface config", __func__, if_name); + LOGW("%s: Update dhcp client failed", if_name); +} + +int cm2_get_link_ip(char *if_name, cm2_ip *ip) +{ + if (cm2_ovsdb_is_ipv6_global_link(if_name)) { + ip->is_ipa = true; + ip->ips = CM2_IPV6_DHCP; + return 0; + } + + return cm2_util_get_ip_inet_state_cfg(if_name, ip); +} + +static int +cm2_ovsdb_copy_dhcp_ipv4_configuration(char *up_src, char *up_dst) +{ + struct schema_Wifi_Inet_Config ups_iconf; + struct schema_Wifi_Inet_Config upd_iconf; + char *filter[8]; + int idx; + int dns_idx; + int ret; + + MEMZERO(ups_iconf); + ret = ovsdb_table_select_one(&table_Wifi_Inet_Config, + SCHEMA_COLUMN(Wifi_Inet_Config, if_name), up_src, &ups_iconf); + if (!ret) { + LOGI("%s: %s: Failed to get interface config", __func__, up_src); + return -1; + } + + if (!ups_iconf.ip_assign_scheme_exists || + !strcmp(ups_iconf.ip_assign_scheme, "none")) { + cm2_ovsdb_set_dhcp_client(up_dst, true); + return 0; + } + + MEMZERO(upd_iconf); + ret = ovsdb_table_select_one(&table_Wifi_Inet_Config, + SCHEMA_COLUMN(Wifi_Inet_Config, if_name), up_dst, &upd_iconf); + if (!ret) { + LOGI("%s: %s: Failed to get interface config", __func__, up_dst); + return -1; + } + + idx = 0; + filter[idx++] = "+"; + + if (ups_iconf.ip_assign_scheme_exists) { + STRSCPY(upd_iconf.ip_assign_scheme, ups_iconf.ip_assign_scheme); + upd_iconf.ip_assign_scheme_exists = true; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, ip_assign_scheme); + } + + if (ups_iconf.gateway_exists) { + STRSCPY(upd_iconf.gateway, ups_iconf.gateway); + upd_iconf.gateway_exists = true; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, gateway); + } + + if (ups_iconf.inet_addr_exists) { + STRSCPY(upd_iconf.inet_addr, ups_iconf.inet_addr); + upd_iconf.inet_addr_exists = true; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, inet_addr); + } + + if (ups_iconf.netmask_exists) { + STRSCPY(upd_iconf.netmask, ups_iconf.netmask); + upd_iconf.netmask_exists = true; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, netmask); + } - LOGI("%s IP address info: inet_addr = %s assign_scheme = %s", if_name, iconf.inet_addr, iconf.ip_assign_scheme); - return !strcmp(iconf.ip_assign_scheme, "static"); + for (dns_idx = 0; dns_idx < ups_iconf.dns_len; dns_idx++) { + STRSCPY(upd_iconf.dns[dns_idx], ups_iconf.dns[dns_idx]); + STRSCPY(upd_iconf.dns_keys[dns_idx], ups_iconf.dns_keys[dns_idx]); + } + upd_iconf.dns_len = ups_iconf.dns_len; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, dns); + + upd_iconf.network_exists = true; + upd_iconf.network = true; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, network); + + upd_iconf.enabled_exists = true; + upd_iconf.enabled = true; + filter[idx++] = SCHEMA_COLUMN(Wifi_Inet_Config, enabled); + + LOGI("%s: Updating DHCP configuration: %s", up_dst, upd_iconf.ip_assign_scheme); + + cm2_ovsdb_set_dhcp_client(up_src, false); + + /* Enable new configuration for dest uplink */ + ret = ovsdb_table_update_where_f(&table_Wifi_Inet_Config, + ovsdb_where_simple(SCHEMA_COLUMN(Wifi_Inet_Config, if_name), up_dst), + &upd_iconf, filter); + if (!ret) { + LOGW("%s: Update DHCP for destination uplink failed", up_dst); + return -1; + } + + return 0; } static bool -cm2_util_set_dhcp(struct schema_Wifi_Master_State *master, bool refresh) +cm2_util_refresh_dhcp(struct schema_Wifi_Master_State *master, bool refresh) { struct schema_Wifi_Inet_Config iconf_update; struct schema_Wifi_Inet_Config iconf; bool dhcp_active; bool dhcp_static; + bool dhcp_enabled; bool empty_addr; int ret; @@ -296,6 +469,7 @@ cm2_util_set_dhcp(struct schema_Wifi_Master_State *master, bool refresh) MEMZERO(iconf); MEMZERO(iconf_update); + dhcp_enabled = false; ret = ovsdb_table_select_one(&table_Wifi_Inet_Config, SCHEMA_COLUMN(Wifi_Inet_Config, if_name), master->if_name, &iconf); @@ -308,55 +482,44 @@ cm2_util_set_dhcp(struct schema_Wifi_Master_State *master, bool refresh) dhcp_static = !strcmp(iconf.ip_assign_scheme, "static"); empty_addr = !((strlen(master->inet_addr) > 0) && strcmp(master->inet_addr, "0.0.0.0") != 0); - if (!empty_addr && dhcp_static) { - char gre_ifname[IFNAME_SIZE]; - - LOGI("%s: Use static static IP address: %s", master->if_name, master->inet_addr); - cm2_dhcpc_stop_dryrun(master->if_name); - cm2_util_ifname2gre(gre_ifname, sizeof(gre_ifname), master->if_name); - cm2_ovsdb_connection_update_L3_state(gre_ifname, true); - - return false; - } - - if (refresh && dhcp_active) { + if (dhcp_static) { if (!empty_addr) { - STRSCPY(iconf_update.ip_assign_scheme, "none"); - } - else { - if (iconf.enabled) { - ret = cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(false, master->if_name); - if (!ret) - LOGW("%s: %s: Failed to clear interface enabled", __func__, master->if_name); + char gre_ifname[IFNAME_SIZE]; - ret = cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(true, master->if_name); - if (!ret) - LOGW("%s: %s: Failed to set interface enabled", __func__, master->if_name); - } - return false; - } + LOGI("%s: Use static static IP address: %s", master->if_name, master->inet_addr); + cm2_dhcpc_stop_dryrun(master->if_name); + cm2_util_ifname2gre(gre_ifname, sizeof(gre_ifname), master->if_name); + cm2_ovsdb_connection_update_L3_state(gre_ifname, true); + } + return false; } if (!refresh && !empty_addr) return true; - if (empty_addr) { - if (!dhcp_active) - STRSCPY(iconf_update.ip_assign_scheme, "dhcp"); - else - return false; - } + if (empty_addr && dhcp_active) + return false; - iconf_update.ip_assign_scheme_exists = true; + if (!refresh && dhcp_active && !empty_addr) { + /* Trigger NM2 state machine */ + if (iconf.enabled) { + ret = cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(false, master->if_name); + if (!ret) + LOGW("%s: %s: Failed to clear interface enabled", __func__, master->if_name); + } + ret = cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(true, master->if_name); + if (!ret) + LOGW("%s: %s: Failed to set interface enabled", __func__, master->if_name); + return false; + } - char *filter[] = { "+", - SCHEMA_COLUMN(Wifi_Inet_Config, ip_assign_scheme), - NULL }; + if (refresh && dhcp_active && !empty_addr) + dhcp_enabled = false; - ret = ovsdb_table_update_where_f(&table_Wifi_Inet_Config, - ovsdb_where_simple(SCHEMA_COLUMN(Wifi_Inet_Config, if_name), master->if_name), - &iconf_update, filter); + if (empty_addr && !dhcp_active) + dhcp_enabled = true; + cm2_ovsdb_set_dhcp_client(master->if_name, dhcp_enabled); return false; } @@ -366,6 +529,12 @@ cm2_ovsdb_refresh_dhcp(char *if_name) struct schema_Wifi_Master_State mstate; int ret; + if (!cm2_is_extender()) + return; + + if (!cm2_is_wan_link_management() && cm2_is_eth_type(g_state.link.if_type)) + return; + LOGI("%s: Trigger refresh dhcp", if_name); MEMZERO(mstate); @@ -377,7 +546,7 @@ cm2_ovsdb_refresh_dhcp(char *if_name) return; } - cm2_util_set_dhcp(&mstate, true); + cm2_util_refresh_dhcp(&mstate, true); } static char* @@ -405,7 +574,6 @@ cm2_ovsdb_insert_Wifi_Inet_Config(struct schema_Wifi_Master_State *master) memset(&icfg, 0, sizeof(icfg)); - icfg.enabled = false; STRSCPY(icfg.if_type, GRE_TYPE_NAME); icfg.gre_local_inet_addr_exists = true; @@ -529,14 +697,13 @@ cm2_ovsdb_util_translate_master_ip(struct schema_Wifi_Master_State *master) bool is_sta; int ret; - LOGI("%s: Detected ip change = %s", master->if_name, master->inet_addr); + LOGI("%s: Detected ip change: %s uplink: %s", master->if_name, master->inet_addr, cm2_get_uplink_name()); is_sta = !strcmp(master->if_type, VIF_TYPE_NAME) && cm2_util_vif_is_sta(master->if_name); - - if (strcmp(master->if_name, CONFIG_TARGET_WAN_BRIDGE_NAME) && !is_sta) + if (strcmp(master->if_name, cm2_get_uplink_name()) && !is_sta) return; - if (!(cm2_util_set_dhcp(master, false))) + if (!(cm2_util_refresh_dhcp(master, false))) return; if (is_sta) { @@ -562,35 +729,58 @@ cm2_ovsdb_util_translate_master_ip(struct schema_Wifi_Master_State *master) } } +static bool +cm2_util_is_wds_station(const char *if_name) +{ + struct schema_Wifi_VIF_State vstate; + int ret; + int len; + + MEMZERO(vstate); + + ret = ovsdb_table_select_one(&table_Wifi_VIF_State, + SCHEMA_COLUMN(Wifi_VIF_State, if_name), if_name, &vstate); + if (!ret) { + LOGI("%s: VIF interface not ready", if_name); + return false; + } + + len = strlen(vstate.multi_ap); + return (len > 0 && !strncmp(vstate.multi_ap, CM2_VIF_MULTI_AP_STA_PARAM, len)) ? true : false; +} + static void cm2_ovsdb_util_handle_master_sta_port_state(struct schema_Wifi_Master_State *master, bool port_state, char *gre_ifname) { - int ret; + cm2_ip ip; + int ret; if (port_state) { - cm2_util_set_dhcp(master, true); - ret = cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(true, master->if_name); if (!ret) LOGW("%s: %s: Failed to set interface enabled", __func__, master->if_name); - } else { - ret = cm2_ovsdb_set_Wifi_Inet_Config_interface_enabled(false, master->if_name); + + ret = cm2_ovsdb_set_Wifi_Inet_Config_network_state(port_state, master->if_name); if (!ret) - LOGW("%s: %s: Failed to set interface enabled", __func__, master->if_name); + LOGW("%s: %s: Failed to set network state %d", __func__, master->if_name, port_state); - if (!strcmp(gre_ifname, g_state.link.if_name) && g_state.link.is_used) { - ret = cm2_ovs_insert_port_into_bridge(CONFIG_TARGET_WAN_BRIDGE_NAME, g_state.link.if_name, false); + if (!cm2_util_is_wds_station(master->if_name)) { + cm2_util_refresh_dhcp(master, true); + } + } else { + if (!strcmp(gre_ifname, g_state.link.if_name) && g_state.link.is_used && g_state.link.is_bridge) { + ret = cm2_ovs_insert_port_into_bridge(g_state.link.bridge_name, g_state.link.if_name, false); if (!ret) - LOGW("%s: Failed to remove port %s from %s", __func__, master->if_name, CONFIG_TARGET_WAN_BRIDGE_NAME); + LOGW("%s: Failed to remove port %s from %s", __func__, master->if_name, g_state.link.bridge_name); cm2_ovsdb_connection_remove_uplink(gre_ifname); } - if (!cm2_util_is_static_ip_assign(master->if_name)) + ret = cm2_util_get_ip_inet_state_cfg(master->if_name, &ip); + if (!ret && ip.ips != CM2_IP_STATIC) cm2_ovsdb_remove_Wifi_Inet_Config(gre_ifname, true); - } ret = cm2_ovsdb_set_Wifi_Inet_Config_network_state(port_state, master->if_name); @@ -598,26 +788,6 @@ cm2_ovsdb_util_handle_master_sta_port_state(struct schema_Wifi_Master_State *mas LOGW("%s: %s: Failed to set network state %d", __func__, master->if_name, port_state); } -static bool -cm2_util_is_wds_station(const char *if_name) -{ - struct schema_Wifi_VIF_State vstate; - int ret; - int len; - - MEMZERO(vstate); - - ret = ovsdb_table_select_one(&table_Wifi_VIF_State, - SCHEMA_COLUMN(Wifi_VIF_State, if_name), if_name, &vstate); - if (!ret) { - LOGI("%s: VIF interface not ready", if_name); - return false; - } - - len = strlen(vstate.multi_ap); - return (len > 0 && !strncmp(vstate.multi_ap, CM2_VIF_MULTI_AP_STA_PARAM, len)) ? true : false; -} - static bool cm2_util_is_supported_main_link(const char *if_name, const char *if_type) { @@ -664,6 +834,8 @@ cm2_ovsdb_util_translate_master_port_state(struct schema_Wifi_Master_State *mast LOGI("%s: Add/update uplink in Connection Manager Uplink table", master->if_name); + cm2_ovsdb_connection_get_connection_by_ifname(master->if_name, &con); + STRSCPY(con.if_name, master->if_name); STRSCPY(con.if_type, master->if_type); con.has_L2_exists = true; @@ -721,6 +893,156 @@ cm2_ovsdb_get_port_by_uuid(struct schema_Port *port, char *port_uuid) return ovsdb_table_select_one_where(&table_Port, where, port); } +bool +cm2_ovsdb_is_ipv6_global_link(const char *if_name) +{ + struct schema_IPv6_Address ipv6_addr; + struct schema_IP_Interface ip; + int ret; + int i; + json_t *where; + + ret = ovsdb_table_select_one(&table_IP_Interface, SCHEMA_COLUMN(IP_Interface, if_name), if_name, &ip); + if (!ret) + return false; + + + for (i = 0; i < ip.ipv6_addr_len; i++) { + if (!(where = ovsdb_where_uuid("_uuid", ip.ipv6_addr[i].uuid))) + continue; + + ret = ovsdb_table_select_one_where(&table_IPv6_Address, where, &ipv6_addr); + if (!ret) + continue; + + if (ipv6_addr.address_exists && + strlen(ipv6_addr.address) >= 4) { + LOGD("%s: ipv6 addrr: %s", if_name, ipv6_addr.address); + + if (strncmp(ipv6_addr.address, "fe80", 4) == 0) + continue; + + return true; + } + } + return false; +} + +static bool +cm2_ovsdb_set_gw_offline_config(bool gw_offline) +{ + struct schema_Node_Config nconfig; + json_t *where, *con; + char *gw_offline_val; + bool ret; + + memset(&nconfig, 0, sizeof(nconfig)); + + nconfig.module_exists = true; + STRSCPY(nconfig.module, CM2_PM_MODULE_NAME); + + nconfig.key_exists = true; + STRSCPY(nconfig.key, CM2_PM_GW_OFFLINE); + + nconfig.value_exists = true; + gw_offline_val = gw_offline ? CM2_PM_GW_OFFLINE_ON : CM2_PM_GW_OFFLINE_OFF; + STRSCPY(nconfig.value, gw_offline_val); + + where = json_array(); + + con = ovsdb_tran_cond_single("module", OFUNC_EQ, CM2_PM_MODULE_NAME); + json_array_append_new(where, con); + con = ovsdb_tran_cond_single("key", OFUNC_EQ, CM2_PM_GW_OFFLINE); + json_array_append_new(where, con); + + ret = ovsdb_table_upsert_where( + &table_Node_Config, + where, + &nconfig, + false); + + if (!ret) { + LOGE("%s Insert new row into Node_Config failed", __func__); + return false; + } + return true; +} + +static bool +cm2_ovsdb_is_gw_offline_status(char *status) +{ + struct schema_Node_State nstate; + json_t *where1; + json_t *where2; + json_t *con; + bool ret; + + where1 = json_array(); + where2 = json_array(); + + con = ovsdb_tran_cond_single("module", OFUNC_EQ, CM2_PM_MODULE_NAME); + json_array_append_new(where1, con); + json_array_append_new(where2, con); + + con = ovsdb_tran_cond_single("key", OFUNC_EQ, CM2_PM_GW_OFFLINE_CFG); + json_array_append_new(where1, con); + + con = ovsdb_tran_cond_single("key", OFUNC_EQ, CM2_PM_GW_OFFLINE_STATUS); + json_array_append_new(where2, con); + + memset(&nstate, 0, sizeof(nstate)); + ret = ovsdb_table_select_one_where(&table_Node_State, where1, &nstate); + if (!ret) { + LOGI("Persistent storage not enabled"); + return false; + } + + LOGD("Persistent storage: EN: %s", nstate.value); + + if (strcmp(nstate.value, CM2_PM_GW_OFFLINE_CFG_EN) != 0) + return false; + + memset(&nstate, 0, sizeof(nstate)); + ret = ovsdb_table_select_one_where(&table_Node_State, where2, &nstate); + if (!ret) { + LOGI("Persistent storage: status not avaialable"); + return false; + } + + LOGD("Persistent storage: status: %s", nstate.value); + if (strcmp(nstate.value, status) != 0) + return false; + + return true; +} + +bool cm2_ovsdb_is_gw_offline_ready(void) +{ + return cm2_ovsdb_is_gw_offline_status(CM2_PM_GW_OFFLINE_STATUS_READY); +} + +bool cm2_ovsdb_enable_gw_offline_conf(void) +{ + bool r; + + r = cm2_ovsdb_is_gw_offline_status(CM2_PM_GW_OFFLINE_STATUS_READY); + if (!r) + return r; + + return cm2_ovsdb_set_gw_offline_config(true); +} + +bool cm2_ovsdb_disable_gw_offline_conf(void) +{ + bool r; + + r = cm2_ovsdb_is_gw_offline_status(CM2_PM_GW_OFFLINE_STATUS_ACTIVE); + if (!r) + return true; + + return cm2_ovsdb_set_gw_offline_config(false); +} + static bool cm2_ovsdb_get_port_by_name(struct schema_Port *port, char *name) { @@ -757,6 +1079,8 @@ cm2_ovsdb_connection_update_L3_state(const char *if_name, bool state) char *filter[] = { "+", SCHEMA_COLUMN(Connection_Manager_Uplink, has_L3), NULL }; int ret; + LOGI("%s: Set has L3 state: %d", if_name, state); + memset(&con, 0, sizeof(con)); con.has_L3_exists = true; con.has_L3 = state; @@ -783,6 +1107,22 @@ cm2_ovsdb_connection_update_used_state(char *if_name, bool state) return ret; } +static bool +cm2_ovsdb_connection_update_bridge_state(char *if_name, const char *bridge) +{ + struct schema_Connection_Manager_Uplink con; + char *filter[] = { "+", SCHEMA_COLUMN(Connection_Manager_Uplink, bridge), NULL }; + + memset(&con, 0, sizeof(con)); + con.bridge_exists = true; + STRSCPY(con.bridge, bridge); + + int ret = ovsdb_table_update_where_f(&table_Connection_Manager_Uplink, + ovsdb_where_simple(SCHEMA_COLUMN(Connection_Manager_Uplink, if_name), if_name), + &con, filter); + return ret; +} + bool cm2_ovsdb_connection_update_loop_state(const char *if_name, bool state) { @@ -979,9 +1319,9 @@ void cm2_connection_set_L3(struct schema_Connection_Manager_Uplink *uplink) { if (!uplink->has_L2) return; - if (cm2_is_eth_type(uplink->if_name) && - cm2_ovs_insert_port_into_bridge(SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name, false)) - LOGW("%s: Failed to remove port %s from %s", __func__, SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name); + if (cm2_is_eth_type(uplink->if_type) && + cm2_ovs_insert_port_into_bridge(CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name, false)) + LOGW("%s: Failed to remove port %s from %s", __func__, CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name); if (cm2_util_block_udhcpc_on_gre(uplink->if_name, uplink->if_type)) cm2_util_skip_gre_configuration(uplink->if_name); @@ -995,16 +1335,18 @@ bool cm2_connection_get_used_link(struct schema_Connection_Manager_Uplink *uplin static void cm2_connection_clear_used(void) { - int ret; + int ret; if (g_state.link.is_used) { LOGN("%s: Remove old used link.", g_state.link.if_name); - cm2_ovs_insert_port_into_bridge(CONFIG_TARGET_WAN_BRIDGE_NAME, g_state.link.if_name, false); + if (g_state.link.is_bridge) + cm2_ovs_insert_port_into_bridge(g_state.link.bridge_name, g_state.link.if_name, false); ret = cm2_ovsdb_connection_update_used_state(g_state.link.if_name, false); if (!ret) LOGI("%s: %s: Failed to clear used state", __func__, g_state.link.if_name); + g_state.link.is_bridge = false; g_state.link.is_used = false; g_state.link.priority = -1; } @@ -1041,11 +1383,18 @@ static void cm2_connection_set_is_used(struct schema_Connection_Manager_Uplink * STRSCPY(g_state.link.if_type, uplink->if_type); g_state.link.is_used = true; g_state.link.priority = uplink->priority; + if (uplink->bridge_exists) { + g_state.link.is_bridge = true; + STRSCPY(g_state.link.bridge_name, uplink->bridge); + } LOGN("%s: Set new used link", uplink->if_name); - ret = cm2_ovs_insert_port_into_bridge(CONFIG_TARGET_WAN_BRIDGE_NAME, uplink->if_name, true); - if (!ret) - LOGW("%s: Failed to add port %s into %s", __func__, uplink->if_name, CONFIG_TARGET_WAN_BRIDGE_NAME); + + if (cm2_is_wan_bridge()) { + cm2_ovsdb_connection_update_bridge_state(uplink->if_name, CM2_WAN_BRIDGE_NAME); + } else if (cm2_is_wifi_type(uplink->if_type)) { + cm2_ovsdb_connection_update_bridge_state(uplink->if_name, CONFIG_TARGET_LAN_BRIDGE_NAME); + } ret = cm2_ovsdb_connection_update_used_state(uplink->if_name, true); if (!ret) @@ -1232,14 +1581,17 @@ void callback_Wifi_Master_State(ovsdb_update_monitor_t *mon, return; } + if (!cm2_is_wan_link_management() && cm2_is_eth_type(master->if_type)) + return; + if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Master_State, port_state))) cm2_ovsdb_util_translate_master_port_state(master); if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Master_State, network_state))) { LOGI("%s: Detected network_state change = %s", master->if_name, master->network_state); - - if (!strncmp(master->if_name, CONFIG_TARGET_WAN_BRIDGE_NAME, strlen(master->if_name))) { + if (g_state.link.is_bridge && + !strncmp(master->if_name, g_state.link.bridge_name, strlen(master->if_name))) { ret = cm2_ovsdb_set_Wifi_Inet_Config_network_state(true, master->if_name); if (!ret) LOGW("%s: %s: Failed to set network enabled", __func__, master->if_name); @@ -1277,9 +1629,106 @@ cm2_util_set_not_used_link(void) cm2_connection_recalculate_used_link(); } + +static int +cm2_util_update_bridge_conf(char *up_src, char *up_dst, char *up_raw) +{ + int ret; + + LOGI("Updating bridge configuration: %s -> %s", up_src, up_dst); + ret = cm2_ovsdb_copy_dhcp_ipv4_configuration(up_src, up_dst); + if (ret < 0) { + LOGI("%s: Failed to update IPv4 configuration from %s to %s", __func__, + up_src, up_dst); + return -1; + } + + if (up_raw) { + /* Put main raw interface into dest uplink */ + ret = cm2_ovs_insert_port_into_bridge(up_dst, up_raw, true); + if (!ret) + LOGI("%s: Failed to add port %s to %s", __func__, up_raw, up_dst); + } + + return 0; +} + +static void +cm2_util_update_bridge_handle( + struct schema_Connection_Manager_Uplink *old_uplink, + struct schema_Connection_Manager_Uplink *uplink) +{ + char s_uplink[126]; + char d_uplink[126]; + char r_uplink[126]; + char *r_p; + int ret; + + if (!cm2_util_get_link_is_used(uplink)) { + LOGI("%s: bridge [%s] updated for not main link", uplink->if_name, uplink->bridge); + return; + } + + if (cm2_ovsdb_is_ipv6_global_link(uplink->if_name)) { + LOGI("%s: bridge mode is not supported for IPv6", uplink->if_name); + return; + } + + r_p = NULL; + + if (uplink->bridge_exists) { + STRSCPY(g_state.link.bridge_name, uplink->bridge); + g_state.link.is_bridge = true; + + if (old_uplink->bridge_exists) { + if (strcmp(uplink->bridge, old_uplink->bridge) == 0) + return; + + STRSCPY(s_uplink, old_uplink->bridge); + STRSCPY(d_uplink, uplink->bridge); + STRSCPY(r_uplink, uplink->if_name); + ret = cm2_ovs_insert_port_into_bridge(s_uplink, r_uplink, false); + if (!ret) { + LOGI("%s: Failed to remove port %s from %s", __func__, r_uplink, s_uplink); + } + + } else { + STRSCPY(s_uplink, uplink->if_name); + STRSCPY(d_uplink, uplink->bridge); + STRSCPY(r_uplink, uplink->if_name); + } + r_p = r_uplink; + } else { + g_state.link.is_bridge = false; + STRSCPY(s_uplink, old_uplink->bridge); + STRSCPY(d_uplink, uplink->if_name); + ret = cm2_ovs_insert_port_into_bridge(s_uplink, d_uplink, false); + if (!ret) + LOGI("%s: Failed to remove port %s from %s", __func__, d_uplink, s_uplink); + } + + ret = cm2_util_update_bridge_conf(s_uplink, d_uplink, r_p ); + if (ret < 0) { + LOGI("%s: Failed to update IPv4 configuration from %s to %s", __func__, + s_uplink, d_uplink); + } +} + +static bool +cm2_uplink_skip_L2_handle(struct schema_Connection_Manager_Uplink *uplink) +{ + if (!cm2_is_wan_link_management() && cm2_is_eth_type(uplink->if_type)) { + LOGI("%s Uplink skipped", uplink->if_name); + return true; + } + LOGI("%s Uplink no skipped wan = %d eth = %d, type = %sX", uplink->if_name, cm2_is_wan_link_management(), cm2_is_eth_type(uplink->if_type), uplink->if_type); + return false; +} + static void cm2_Connection_Manager_Uplink_handle_update( ovsdb_update_monitor_t *mon, + struct schema_Connection_Manager_Uplink *old_uplink, struct schema_Connection_Manager_Uplink *uplink) { bool clean_up_counters = false; @@ -1301,43 +1750,53 @@ cm2_Connection_Manager_Uplink_handle_update( reconfigure = true; } } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Connection_Manager_Uplink, loop))) { LOGN("%s: Uplink table: detected loop change = %d", uplink->if_name, uplink->loop); } + if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Connection_Manager_Uplink, bridge))) { + cm2_util_update_bridge_handle(old_uplink, uplink); + } + if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Connection_Manager_Uplink, has_L2))) { LOGN("%s: Uplink table: detected hasL2 change = %d", uplink->if_name, uplink->has_L2); - if (!uplink->has_L2) { - cm2_dhcpc_stop_dryrun(uplink->if_name); - if (!strcmp(uplink->if_type, ETH_TYPE_NAME)) { - ret = cm2_ovs_insert_port_into_bridge(SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name, false); - if (!ret) - LOGI("%s: Failed to remove port %s from %s", __func__, SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name); - } + if (uplink->has_L2) + cm2_set_ble_onboarding_link_state(true, uplink->if_type, uplink->if_name); - if (cm2_util_get_link_is_used(uplink)) { - reconfigure = true; + if (!cm2_uplink_skip_L2_handle(uplink)) { + if (!uplink->has_L2) { + cm2_dhcpc_stop_dryrun(uplink->if_name); + + if (cm2_is_eth_type(uplink->if_type)) { + ret = cm2_ovs_insert_port_into_bridge(CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name, false); + if (!ret) + LOGI("%s: Failed to remove port %s from %s", __func__, + CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name); + } + + if (cm2_util_get_link_is_used(uplink)) { + reconfigure = true; + } else { + clean_up_counters = true; + } + + filter[idx++] = SCHEMA_COLUMN(Connection_Manager_Uplink, has_L3); + uplink->has_L3 = false; + g_state.link.vtag.state = CM2_VTAG_NOT_USED; + + if (!strcmp(g_state.link.if_name, uplink->if_name) && g_state.link.restart_pending) { + g_state.link.restart_pending = false; + LOGI("Restart link due to restart pending"); + ret = cm2_ovsdb_set_Wifi_Inet_Config_network_state(true, g_state.link.if_name); + if (!ret) + LOGW("Force enable main uplink interface failed"); + } } else { - clean_up_counters = true; - } - filter[idx++] = SCHEMA_COLUMN(Connection_Manager_Uplink, has_L3); - uplink->has_L3 = false; - g_state.link.vtag.state = CM2_VTAG_NOT_USED; - if (!strcmp(uplink->if_name, uplink->if_name) && g_state.link.restart_pending) { - g_state.link.restart_pending = false; - LOGI("Restart link due to restart pending"); - ret = cm2_ovsdb_set_Wifi_Inet_Config_network_state(true, g_state.link.if_name); - if (!ret) - LOGW("Force enable main uplink interface failed"); + cm2_connection_set_L3(uplink); } - } else { - cm2_set_ble_onboarding_link_state(true, uplink->if_type, uplink->if_name); - cm2_connection_set_L3(uplink); } } - /* End of configuration part */ /* Setting state part */ @@ -1440,14 +1899,14 @@ void callback_Connection_Manager_Uplink(ovsdb_update_monitor_t *mon, cm2_dhcpc_stop_dryrun(uplink->if_name); if (!strcmp(uplink->if_type, ETH_TYPE_NAME)) { - ret = cm2_ovs_insert_port_into_bridge(SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name, false); + ret = cm2_ovs_insert_port_into_bridge(CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name, false); if (!ret) - LOGI("%s: Failed to remove port %s from %s", __func__, SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name); + LOGI("%s: Failed to remove port %s from %s", __func__, CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name); } break; case OVSDB_UPDATE_NEW: case OVSDB_UPDATE_MODIFY: - cm2_Connection_Manager_Uplink_handle_update(mon, uplink); + cm2_Connection_Manager_Uplink_handle_update(mon, old_row, uplink); break; } } @@ -1462,9 +1921,8 @@ static void cm2_Wifi_Inet_State_handle_dhcpc(struct schema_Wifi_Inet_State *inet int i; LOGD("%s; Update dhcpc column", inet_state->if_name); - - if (strcmp(inet_state->if_name, CONFIG_TARGET_WAN_BRIDGE_NAME)) { - LOGD("%s: Skip update, only %s support", inet_state->if_name, CONFIG_TARGET_WAN_BRIDGE_NAME); + if (strcmp(inet_state->if_name, cm2_get_uplink_name())) { + LOGD("%s: Skip update, only %s support", inet_state->if_name, cm2_get_uplink_name()); return; } @@ -1552,12 +2010,15 @@ void callback_Wifi_Inet_State(ovsdb_update_monitor_t *mon, case OVSDB_UPDATE_NEW: case OVSDB_UPDATE_MODIFY: if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Inet_State, inet_addr))) { - if (!strcmp(inet_state->if_type, BRIDGE_TYPE_NAME)) { - if (strlen(inet_state->inet_addr) <= 0) - g_state.link.is_ip = false; - else - g_state.link.is_ip = strcmp(inet_state->inet_addr, "0.0.0.0") == 0 ? false : true; + LOGI("%s: inet state update: inet_addr: %s", inet_state->if_name, inet_state->inet_addr); + if (g_state.link.is_bridge) { + if (strcmp(inet_state->if_type, BRIDGE_TYPE_NAME) || + strcmp(inet_state->if_name, g_state.link.bridge_name)) + break; + } else if (strcmp(g_state.link.if_name, inet_state->if_name)) { + break; } + cm2_util_set_ip_cfg(inet_state, &g_state.link.ip); } if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Inet_State, dhcpc))) @@ -1603,8 +2064,8 @@ static void cm2_reconfigure_ethernet_states(bool blocked) if (!uplink->has_L2 || !uplink->has_L3_exists) continue; - if (cm2_is_iface_in_bridge(SCHEMA_CONSTS_BR_NAME_HOME, uplink->if_name)) { - LOGI("%s: Skip reconfigure iface in %s", uplink->if_name, SCHEMA_CONSTS_BR_NAME_HOME); + if (cm2_is_iface_in_bridge(CONFIG_TARGET_LAN_BRIDGE_NAME, uplink->if_name)) { + LOGI("%s: Skip reconfigure iface in %s", uplink->if_name, CONFIG_TARGET_LAN_BRIDGE_NAME); continue; } @@ -1644,6 +2105,33 @@ bool cm2_ovsdb_validate_bridge_port_conf(char *bname, char *pname) return true; } +void cm2_util_sync_limp_state(char *br, char *port, bool state) +{ + bool u; + + if (cm2_is_wan_bridge()) { + if (strstr(port, "patch-h2w")){ + LOGI("Patch port detected, added [%d]", state); + g_state.link.is_limp_state = !state; + } + } else { + u = state && + g_state.link.is_bridge && + strstr(g_state.link.bridge_name, br) && + strstr(g_state.link.if_name, port); + + if (!u) + u = !state && + !g_state.link.is_bridge && + strstr(g_state.link.if_name, port); + + if (u) { + LOGI("%s: Limp state updated: %d", port, !state); + g_state.link.is_limp_state = !state; + } + } +} + static void cm2_check_bridge_mismatch(struct schema_Bridge *base_bridge, struct schema_Bridge *bridge, bool added) @@ -1670,20 +2158,67 @@ static void cm2_check_bridge_mismatch(struct schema_Bridge *base_bridge, continue; } - if (strstr(port.name, "patch-h2w")){ - LOGI("Patch port detected, added [%d]", added); - g_state.link.is_limp_state = added ? false : true; - } + cm2_util_sync_limp_state(base_bridge->name, port.name, added); - if (strstr(port.name, ETH_TYPE_NAME)) { - if (added) + if (strstr(port.name, ETH_TYPE_NAME) && added) cm2_dhcpc_stop_dryrun(port.name); - //else ?? TODO - } } } } +void callback_IP_Interface(ovsdb_update_monitor_t *mon, + struct schema_IP_Interface *old_ip, + struct schema_IP_Interface *ip) +{ + struct schema_IPv6_Address ipv6_addr; + json_t *where; + int ret; + int i; + + + LOGD("%s mon_type = %d", __func__, mon->mon_type); + + switch (mon->mon_type) { + default: + case OVSDB_UPDATE_ERROR: + LOGW("%s: mon upd error: %d", __func__, mon->mon_type); + return; + + case OVSDB_UPDATE_DEL: + LOGI("%s: IP interface removed", ip->if_name); + break; + case OVSDB_UPDATE_NEW: + case OVSDB_UPDATE_MODIFY: + if (ovsdb_update_changed(mon, SCHEMA_COLUMN(IP_Interface, ipv6_addr))) { + if (strcmp(ip->if_name, cm2_get_uplink_name())) { + LOGI("%s: IP interface skip not main link %s", ip->name, cm2_get_uplink_name()); + return; + } + + for (i = 0; i < ip->ipv6_addr_len; i++) { + if (!(where = ovsdb_where_uuid("_uuid", ip->ipv6_addr[i].uuid))) + continue; + + ret = ovsdb_table_select_one_where(&table_IPv6_Address, where, &ipv6_addr); + if (!ret) + continue; + + if (ipv6_addr.address_exists && + strlen(ipv6_addr.address) >= 4) { + LOGI("%s: ipv6 addrr: %s", ip->if_name, ipv6_addr.address); + + if (strncmp(ipv6_addr.address, "fe80", 4) == 0) + continue; + + g_state.link.ip.ips = CM2_IPV6_DHCP; + g_state.link.ip.is_ipa = true; + } + } + } + break; + } +} + void callback_Bridge(ovsdb_update_monitor_t *mon, struct schema_Bridge *old_bridge, struct schema_Bridge *bridge) @@ -1699,26 +2234,30 @@ void callback_Bridge(ovsdb_update_monitor_t *mon, return; case OVSDB_UPDATE_DEL: - LOGI("%s: Bridge remove detected", bridge->name); + LOGI("%s: Bridge removed", bridge->name); break; case OVSDB_UPDATE_NEW: case OVSDB_UPDATE_MODIFY: if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Bridge, ports))) { - - if (strcmp(bridge->name, SCHEMA_CONSTS_BR_NAME_HOME) && - strcmp(bridge->name, SCHEMA_CONSTS_BR_NAME_WAN)) + if (strcmp(bridge->name, CONFIG_TARGET_LAN_BRIDGE_NAME) && + (!g_state.link.is_bridge || + (g_state.link.is_bridge && strcmp(bridge->name, g_state.link.bridge_name)))) break; - if (!strcmp(bridge->name, SCHEMA_CONSTS_BR_NAME_WAN)) { + if (g_state.link.is_bridge && !strcmp(bridge->name, g_state.link.bridge_name)) { if (g_state.link.is_used) { - r = cm2_ovsdb_validate_bridge_port_conf(SCHEMA_CONSTS_BR_NAME_WAN, + r = cm2_ovsdb_validate_bridge_port_conf(g_state.link.bridge_name, g_state.link.if_name); if (!r) { LOGI("Main uplink was removed from bridge %s, but still is in active state", - SCHEMA_CONSTS_BR_NAME_WAN); + g_state.link.if_name); } break; } + + if (!cm2_is_wan_link_management()) + break; + if (cm2_is_wifi_type(g_state.link.if_type)) { cm2_reconfigure_ethernet_states(true); break; @@ -1735,6 +2274,52 @@ void callback_Bridge(ovsdb_update_monitor_t *mon, } } +void callback_Wifi_Route_State(ovsdb_update_monitor_t *mon, + struct schema_Wifi_Route_State *old_route, + struct schema_Wifi_Route_State *route) +{ + LOGD("%s mon_type = %d", __func__, mon->mon_type); + + switch (mon->mon_type) { + default: + case OVSDB_UPDATE_ERROR: + LOGW("%s: mon upd error: %d", __func__, mon->mon_type); + return; + + case OVSDB_UPDATE_DEL: + LOGI("%s: Wifi_Route_State removed", route->if_name); + if (strcmp(route->if_name, cm2_get_uplink_name())) { + LOGD("%s: Wifi_Route_State skip not main link %s gateway_hwaddr = %s", + route->if_name, cm2_get_uplink_name(), route->gateway_hwaddr); + return; + } + + if (route->gateway_hwaddr_exists) { + LOGD("%s: GW hwaddr cached %s, removed = %s", + route->if_name, g_state.link.gateway_hwaddr, route->gateway_hwaddr); + } + break; + case OVSDB_UPDATE_NEW: + case OVSDB_UPDATE_MODIFY: + if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Route_State, gateway_hwaddr))) { + if (strcmp(route->if_name, cm2_get_uplink_name())) { + LOGI("%s: Wifi_Route_State skip not main link %s gateway_hwaddr = %s", + route->if_name, cm2_get_uplink_name(), route->gateway_hwaddr); + return; + } + + if (route->gateway_hwaddr_exists) { + STRSCPY(g_state.link.gateway_hwaddr, route->gateway_hwaddr); + LOGI("%s: GW hwaddr: %s updated", route->if_name, route->gateway_hwaddr); + } + else if (old_route->gateway_hwaddr_exists) { + LOGI("%s: GW hwaddr: %s cached", route->if_name, g_state.link.gateway_hwaddr); + } + } + break; + } +} + bool cm2_ovsdb_set_Manager_target(char *target) { struct schema_Manager manager; @@ -2072,6 +2657,11 @@ int cm2_ovsdb_init(void) OVSDB_TABLE_INIT_NO_KEY(AW_Bluetooth_Config); OVSDB_TABLE_INIT_NO_KEY(Port); OVSDB_TABLE_INIT_NO_KEY(Bridge); + OVSDB_TABLE_INIT_NO_KEY(IP_Interface); + OVSDB_TABLE_INIT_NO_KEY(IPv6_Address); + OVSDB_TABLE_INIT_NO_KEY(Wifi_Route_State); + OVSDB_TABLE_INIT_NO_KEY(Node_Config); + OVSDB_TABLE_INIT_NO_KEY(Node_State); // Initialize OVSDB monitor callbacks OVSDB_TABLE_MONITOR(AWLAN_Node, false); @@ -2082,6 +2672,8 @@ int cm2_ovsdb_init(void) OVSDB_TABLE_MONITOR(Connection_Manager_Uplink, false); OVSDB_TABLE_MONITOR(Wifi_Inet_State, false); OVSDB_TABLE_MONITOR(Bridge, false); + OVSDB_TABLE_MONITOR(IP_Interface, false); + OVSDB_TABLE_MONITOR(Wifi_Route_State, false); } char *filter[] = {"-", "_version", SCHEMA_COLUMN(Manager, status), NULL}; diff --git a/src/cm2/src/cm2_resolve.c b/src/cm2/src/cm2_resolve.c index 3860473d..56ae35d2 100644 --- a/src/cm2/src/cm2_resolve.c +++ b/src/cm2/src/cm2_resolve.c @@ -81,8 +81,12 @@ bool cm2_parse_resource(cm2_addr_t *addr, cm2_dest_e dest) bool cm2_set_addr(cm2_dest_e dest, char *resource) { - bool ret = false; - cm2_addr_t *addr = cm2_get_addr(dest); + cm2_addr_t *addr; + bool ret; + + addr = cm2_get_addr(dest); + ret = false; + STRSCPY(addr->resource, resource); addr->resolved = false; addr->updated = false; diff --git a/src/cm2/src/cm2_resolve_ares.c b/src/cm2/src/cm2_resolve_ares.c index 9d0b5198..ed2b86b8 100644 --- a/src/cm2/src/cm2_resolve_ares.c +++ b/src/cm2/src/cm2_resolve_ares.c @@ -49,27 +49,29 @@ static int cm2_start_ares_resolve(struct evx_ares *eares_p) void cm2_free_addr_list(cm2_addr_t *addr) { - int i; - - if (addr->h_addr_list) { - for (i = 0; !addr->h_addr_list[i]; i++) { - if (!addr->h_addr_list[i]) { - free(addr->h_addr_list[i]); - addr->h_addr_list[i] = NULL; - } - } - free(addr->h_addr_list); - addr->h_addr_list = NULL; - } + cm2_addr_list_entry *addr_e; + ds_dlist_iter_t list_iter; + + for (addr_e = ds_dlist_ifirst(&list_iter, &addr->addr_list); + addr_e != NULL; + addr_e = ds_dlist_inext(&list_iter)) { + ds_dlist_iremove(&list_iter); + free(addr_e); + addr_e = NULL; + } + + addr->cur = NULL; } static void cm2_ares_host_cb(void *arg, int status, int timeouts, struct hostent *hostent) { - cm2_addr_t *addr; - char buf[INET6_ADDRSTRLEN]; - int cnt; - int i; + cm2_addr_list_entry *n; + cm2_addr_t *addr; + char buf[INET6_ADDRSTRLEN]; + int ptype; + int cnt; + int i; addr = (cm2_addr_t *) arg; @@ -79,22 +81,37 @@ cm2_ares_host_cb(void *arg, int status, int timeouts, struct hostent *hostent) case ARES_SUCCESS: LOGN("ares: got address of host %s, timeouts: %d\n", hostent->h_name, timeouts); - for (i = 0; hostent->h_addr_list[i]; ++i) { + for (i = 0; hostent->h_addr_list[i]; ++i) + { inet_ntop(hostent->h_addrtype, hostent->h_addr_list[i], buf, INET6_ADDRSTRLEN); - LOGI("Addr%d: %s\n", i, buf); - } - - cnt = i; - addr->h_addr_list = (char **) malloc(sizeof(char*) * (cnt + 1)); + LOGI("Addr%d:[%d] %s\n", i, hostent->h_addrtype, buf); + } - for (i = 0; i < cnt; i++) { - addr->h_addr_list[i] = (char *) malloc(sizeof(char) * hostent->h_length); - memcpy(addr->h_addr_list[i], hostent->h_addr_list[i], hostent->h_length); + cnt = i; + + for (i = 0; i < cnt; i++) + { + n = malloc(sizeof(cm2_addr_list_entry)); + if (n == NULL) + { + LOGE("ares: Allocation new addres failed"); + cm2_free_addr_list(addr); + return; + } + memcpy(n->addr, hostent->h_addr_list[i], hostent->h_length); + n->addr_type = hostent->h_addrtype; + ptype = g_state.link.ip.ips == CM2_IPV6_DHCP ? AF_INET6 : AF_INET; + if (n->addr_type == ptype) + { + ds_dlist_insert_head(&addr->addr_list, n); + } + else + { + ds_dlist_insert_tail(&addr->addr_list, n); + } } - addr->h_addr_list[i] = NULL; addr->resolved = true; - addr->h_addrtype = hostent->h_addrtype;; - addr->h_cur_idx = 0; + addr->cur = ds_dlist_head(&addr->addr_list); break; case ARES_EDESTRUCTION: LOGI("ares: channel was destroyed"); @@ -128,15 +145,18 @@ bool cm2_resolve(cm2_dest_e dest) return false; cm2_free_addr_list(addr); - //ipv4 + + /* Initialize the list */ + ds_dlist_init(&addr->addr_list, cm2_addr_list_entry, le_node); if (!g_state.eares.chan_initialized) { LOGI("ares: channel not initialized yet"); return false; } LOGI("ares: trigger get hostname"); + /* IPv6 */ + ares_gethostbyname(g_state.eares.ares.channel, addr->hostname, AF_INET6, cm2_ares_host_cb, (void *) addr); + /* IPv4 */ ares_gethostbyname(g_state.eares.ares.channel, addr->hostname, AF_INET, cm2_ares_host_cb, (void *) addr); - //ipv6 - //ares_gethostbyname(g_state.eares.ares.channel, addr->hostname, AF_INET6, cm2_ares_host_cb, (void *) addr); return true; } @@ -148,33 +168,51 @@ void cm2_resolve_timeout(void) static bool cm2_write_target_addr(cm2_addr_t *addr) { - char target[256]; - char *buf; - - if (!addr->h_addr_list) + const char *result; + char target[256]; + char *buf; + bool ret; + + if (!addr->cur) + { + LOGD("ares: Current address item is null"); return false; + } - buf = addr->h_addr_list[addr->h_cur_idx]; + buf = addr->cur->addr; if (!buf) + { + LOGI("ares: Current address is null"); return false; + } - if (addr->h_addrtype == AF_INET) { + if (addr->cur->addr_type == AF_INET) + { char buffer[INET_ADDRSTRLEN] = ""; - const char* result = inet_ntop(AF_INET, buf, buffer, sizeof(buffer)); + + result = inet_ntop(AF_INET, buf, buffer, sizeof(buffer)); if (result == 0) + { + LOGD("ares: translation to ipv4 address failed"); return false; + } snprintf(target, sizeof(target), "%s:%s:%d", addr->proto, buffer, addr->port); } - else if (addr->h_addrtype == AF_INET6) { + else if (addr->cur->addr_type == AF_INET6) + { char buffer[INET6_ADDRSTRLEN] = ""; - const char* result = inet_ntop(AF_INET6, buf, buffer, sizeof(buffer)); + + result = inet_ntop(AF_INET6, buf, buffer, sizeof(buffer)); if (result == 0) + { + LOGD("ares: translation to ipv6 address failed"); return false; + } snprintf(target, sizeof(target), "%s:[%s]:%d", addr->proto, @@ -182,11 +220,14 @@ static bool cm2_write_target_addr(cm2_addr_t *addr) addr->port); } else + { + LOGI("ares: unsupported address type"); return false; + } - bool ret = cm2_ovsdb_set_Manager_target(target); + ret = cm2_ovsdb_set_Manager_target(target); if (ret) - LOGI("ares: trying to connect to: %s : %s", cm2_curr_dest_name(), target); + LOGI("trying to connect to: %s : %s", cm2_curr_dest_name(), target); return ret; } @@ -202,6 +243,6 @@ bool cm2_write_next_target_addr(void) cm2_addr_t *addr; addr = cm2_curr_addr(); - addr->h_cur_idx++; + addr->cur = ds_dlist_next(&addr->addr_list, addr->cur); return cm2_write_target_addr(addr); } diff --git a/src/cm2/src/cm2_resolve_sync.c b/src/cm2/src/cm2_resolve_sync.c index 4007031c..363cacbd 100644 --- a/src/cm2/src/cm2_resolve_sync.c +++ b/src/cm2/src/cm2_resolve_sync.c @@ -31,9 +31,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "log.h" #include "cm2.h" + void cm2_free_addr_list(cm2_addr_t *addr) { - if (addr->ai_list) freeaddrinfo(addr->ai_list); + if (addr->ai_list) + freeaddrinfo(addr->ai_list); + addr->ai_list = NULL; addr->ai_curr = NULL; } @@ -62,12 +65,22 @@ int cm2_getaddrinfo(char *hostname, struct addrinfo **res, char *msg) bool cm2_resolve(cm2_dest_e dest) { - cm2_addr_t *addr = cm2_get_addr(dest); - char *dstr = cm2_dest_name(dest); - int ret; - + struct addrinfo *ai, *found; + const char *result; + cm2_addr_t *addr; + size_t bsize; + char *dstr; + char buf[2048]; + char *bp; + int ret; + + addr = cm2_get_addr(dest); + dstr = cm2_dest_name(dest); addr->updated = false; addr->resolved = false; + found = NULL; + bp = buf; + bsize = sizeof(buf); if (!addr->valid) { @@ -78,18 +91,15 @@ bool cm2_resolve(cm2_dest_e dest) cm2_free_addr_list(addr); - struct addrinfo *ai, *found = NULL; - // resolve ret = cm2_getaddrinfo(addr->hostname, &addr->ai_list, dstr); if (ret != 0) { addr->ai_list = NULL; + LOGI("sync resolving: get address failed"); return false; } - char buf[2048] = "", *bp = buf; - size_t bsize = sizeof(buf); ai = addr->ai_list; while (ai) { @@ -97,11 +107,13 @@ bool cm2_resolve(cm2_dest_e dest) { char buffer[INET_ADDRSTRLEN] = ""; struct sockaddr_in *sain; + sain = (struct sockaddr_in *)ai->ai_addr; - const char* result = inet_ntop(AF_INET, &sain->sin_addr, buffer, sizeof(buffer)); + result = inet_ntop(AF_INET, &sain->sin_addr, buffer, sizeof(buffer)); if (result) { - if (!found) found = ai; + if (!found) + found = ai; append_snprintf(&bp, &bsize, "%s ", buffer); } } @@ -109,11 +121,13 @@ bool cm2_resolve(cm2_dest_e dest) { char buffer[INET6_ADDRSTRLEN] = ""; struct sockaddr_in6 *sain6; + sain6 = (struct sockaddr_in6 *)ai->ai_addr; - const char* result = inet_ntop(AF_INET6, &sain6->sin6_addr, buffer, sizeof(buffer)); + result = inet_ntop(AF_INET6, &sain6->sin6_addr, buffer, sizeof(buffer)); if (result) { - if(!found) found = ai; + if (!found) + found = ai; append_snprintf(&bp, &bsize, "[%s] ", buffer); } } @@ -130,6 +144,7 @@ bool cm2_resolve(cm2_dest_e dest) return true; } +/* Empty function not used in sync resolving process */ void cm2_resolve_timeout(void) { } diff --git a/src/cm2/src/cm2_stability.c b/src/cm2/src/cm2_stability.c index 8a1ef979..18eb873f 100644 --- a/src/cm2/src/cm2_stability.c +++ b/src/cm2/src/cm2_stability.c @@ -30,27 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "schema.h" #include "cm2.h" #include "kconfig.h" - -cm2_main_link_type cm2_util_get_link_type(void) -{ - cm2_main_link_type type = CM2_LINK_NOT_DEFINED; - - if (!g_state.link.is_used) - return type; - - if (!strcmp(g_state.link.if_type, "eth")) { - if (cm2_ovsdb_is_port_name("patch-w2h")) - type = CM2_LINK_ETH_BRIDGE; - else - type = CM2_LINK_ETH_ROUTER; - } - - if (!strcmp(g_state.link.if_type, "gre")) { - type = CM2_LINK_GRE; - } - - return type; -} +#include "cm2_stability.h" bool cm2_vtag_stability_check(void) { cm2_vtag_t *vtag = &g_state.link.vtag; @@ -109,41 +89,71 @@ static bool cm2_cpu_is_low_loadavg(void) { return retval; } -static void cm2_restore_connection(int cnt) +#ifdef CONFIG_CM2_STABILITY_USE_RESTORE_SWITCH_CFG +void cm2_restore_switch_cfg_params(int counter, int thresh, cm2_restore_con_t *ropt) { - char command[128]; - bool ret; - - if (cnt <= 0) - return; + *ropt |= 1 << CM2_RESTORE_SWITCH_FIX_PORT_MAP; - if (!cm2_is_eth_type(g_state.link.if_type)) - return; + if (counter % thresh == 0) + *ropt |= (1 << CM2_RESTORE_SWITCH_DUMP_DATA) | (1 << CM2_RESTORE_SWITCH_FIX_AUTON); +} - sprintf(command, "sh "CONFIG_INSTALL_PREFIX"/scripts/kick-ethernet.sh %d 0 3 ", cnt); - LOGD("%s: Command: %s", __func__, command); - ret = target_device_execute(command); - if (!ret) - LOGW("kick-ethernet.sh: Checking port map failed"); +void cm2_restore_switch_cfg(cm2_restore_con_t opt) +{ + char command[128]; + int ret; - if (cnt % CONFIG_CM2_STABILITY_THRESH_REST_CON == 0) { - LOGI("Trying restore connection"); - sprintf(command, "sh "CONFIG_INSTALL_PREFIX"/scripts/kick-ethernet.sh %d 0 2 ", cnt); + if (opt & (1 << CM2_RESTORE_SWITCH_DUMP_DATA)) { + LOGI("Switch: Dump debug data"); + sprintf(command, "sh "CONFIG_INSTALL_PREFIX"/scripts/kick-ethernet.sh 2 "); LOGD("%s: Command: %s", __func__, command); ret = target_device_execute(command); if (!ret) LOGW("kick-ethernet.sh: Dump data failed"); + } - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); + if (opt & (1 << CM2_RESTORE_SWITCH_FIX_PORT_MAP)) { + LOGI("Switch: Trigger fixing port map"); + sprintf(command, "sh "CONFIG_INSTALL_PREFIX"/scripts/kick-ethernet.sh 3 %s", + g_state.link.gateway_hwaddr); + LOGD("%s: Command: %s", __func__, command); + ret = target_device_execute(command); + if (!ret) + LOGW("kick-ethernet.sh: Fixing port map failed"); + } + + if (opt & (1 << CM2_RESTORE_SWITCH_FIX_AUTON)) { + LOGI("Switch: Trigger autoneg restart"); + sprintf(command, "sh "CONFIG_INSTALL_PREFIX"/scripts/kick-ethernet.sh 4 "); + LOGD("%s: Command: %s", __func__, command); + ret = target_device_execute(command); + if (!ret) + LOGW("kick-ethernet.sh: autoneg restart failed"); } } +#endif /* CONFIG_CM2_STABILITY_USE_RESTORE_SWITCH_CFG */ + +static void cm2_restore_connection(cm2_restore_con_t opt) +{ + if (opt == 0) + return; + + if (!cm2_is_eth_type(g_state.link.if_type)) + return; + + if (opt & (1 << CM2_RESTORE_IP)) + cm2_ovsdb_refresh_dhcp(cm2_get_uplink_name()); + else + cm2_restore_switch_cfg(opt); +} static void cm2_stability_handle_fatal_state(int counter) { if (counter > 0 && cm2_vtag_stability_check() && !g_state.link.is_limp_state && - counter + 1 > CONFIG_CM2_STABILITY_THRESH_FATAL) { + g_state.gw_offline_cnt == 0 && + counter + 1 > CONFIG_CM2_STABILITY_THRESH_FATAL) { LOGW("Restart managers due to exceeding the threshold for fatal failures"); cm2_ovsdb_dump_debug_data(); cm2_tcpdump_stop(g_state.link.if_name); @@ -155,7 +165,8 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) { struct schema_Connection_Manager_Uplink con; target_connectivity_check_t cstate; - cm2_main_link_type link_type; + cm2_restore_con_t ropt; + const char *bridge; bool ret; int counter; @@ -166,6 +177,8 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) //TODO for all active links const char *if_name = g_state.link.if_name; + ropt = 0; + if (!g_state.link.is_used) { LOGN("Waiting for new active link"); g_state.ble_status = 0; @@ -179,8 +192,9 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) return; } - if (!cm2_ovsdb_validate_bridge_port_conf(SCHEMA_CONSTS_BR_NAME_WAN, g_state.link.if_name)) { - LOGW("Detected abnormal situation, main link %s", g_state.link.if_name); + if (con.bridge_exists && + !cm2_ovsdb_validate_bridge_port_conf(con.bridge, g_state.link.if_name)) { + LOGW("Detected abnormal situation, main link %s con.bridge = %s", if_name, con.bridge); counter = con.unreachable_link_counter < 0 ? 1 : con.unreachable_link_counter + 1; LOGI("Detected broken link. Counter = %d", counter); @@ -190,7 +204,7 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) LOGW("Force disable main uplink interface failed"); else g_state.link.restart_pending = true; - + ret = cm2_ovsdb_set_Wifi_Inet_Config_network_state(true, g_state.link.if_name); if (counter + 1 > CONFIG_CM2_STABILITY_THRESH_FATAL) { cm2_stability_handle_fatal_state(counter); counter = 0; @@ -204,7 +218,14 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) } ret = target_device_connectivity_check(if_name, &cstate, opts); - LOGN("Connection status %d, main link: %s opts: = %x", ret, if_name, opts); + bridge = con.bridge_exists ? con.bridge : "none"; + LOGN("Connection status %d, main link: %s bridge: %s opts: = %x", + ret, if_name, bridge, opts); + LOGD("%s: Stability counters: [%d, %d, %d, %d]",if_name, + con.unreachable_link_counter, con.unreachable_router_counter, + con.unreachable_internet_counter, con.unreachable_cloud_counter); + LOGD("%s: Stability states: [%d, %d, %d]", if_name, + cstate.link_state, cstate.router_state, cstate.internet_state); if (opts & LINK_CHECK) { counter = 0; @@ -221,6 +242,9 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) if (!cstate.router_state) { counter = con.unreachable_router_counter < 0 ? 1 : con.unreachable_router_counter + 1; LOGW("Detected broken Router. Counter = %d", counter); + cm2_restore_switch_cfg_params(counter, CONFIG_CM2_STABILITY_THRESH_ROUTER + 2, &ropt); + if (counter % CONFIG_CM2_STABILITY_THRESH_ROUTER == 0) + ropt |= (1 << CM2_RESTORE_IP); } else if (kconfig_enabled(CONFIG_CM2_USE_TCPDUMP) && con.unreachable_router_counter >= CONFIG_CM2_STABILITY_THRESH_TCPDUMP) { @@ -231,8 +255,6 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) if (!ret) LOGW("%s Failed update router counter in ovsdb table", __func__); - cm2_restore_connection(counter); - if (kconfig_enabled(CONFIG_CM2_USE_TCPDUMP) && counter == CONFIG_CM2_STABILITY_THRESH_TCPDUMP && cm2_is_eth_type(g_state.link.if_type)) { @@ -242,16 +264,6 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) if (con.unreachable_router_counter + 1 == CONFIG_CM2_STABILITY_THRESH_FATAL) cm2_tcpdump_stop(g_state.link.if_name); - link_type = cm2_util_get_link_type(); - if (link_type == CM2_LINK_ETH_ROUTER) { - if (!g_state.link.is_limp_state) - LOGI("Device operates in Router mode"); - g_state.link.is_limp_state = true; - } else if (link_type == CM2_LINK_ETH_BRIDGE) { - if (g_state.link.is_limp_state) - LOGI("Device operates in Bridge mode"); - g_state.link.is_limp_state = false; - } cm2_stability_handle_fatal_state(con.unreachable_router_counter); } if (opts & INTERNET_CHECK) { @@ -259,11 +271,11 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) if (!cstate.internet_state) { counter = con.unreachable_internet_counter < 0 ? 1 : con.unreachable_internet_counter + 1; LOGW("Detected broken Internet. Counter = %d", counter); - if (counter % CONFIG_CM2_STABILITY_THRESH_INTERNET == 0) { - LOGN("Refresh br-wan interface due to Internet issue"); - cm2_ovsdb_refresh_dhcp(CONFIG_TARGET_WAN_BRIDGE_NAME); - } + cm2_restore_switch_cfg_params(counter, CONFIG_CM2_STABILITY_THRESH_INTERNET + 2, &ropt); + if (counter % CONFIG_CM2_STABILITY_THRESH_INTERNET == 0) + ropt |= (1 << CM2_RESTORE_IP); } + ret = cm2_ovsdb_connection_update_unreachable_internet_counter(if_name, counter); if (!ret) LOGW("%s Failed update internet counter in ovsdb table", __func__); @@ -276,6 +288,7 @@ void cm2_connection_req_stability_check(target_connectivity_check_option_t opts) else g_state.ntp_check = cstate.ntp_state; } + cm2_restore_connection(ropt); return; } @@ -283,7 +296,7 @@ static void cm2_connection_stability_check(void) { target_connectivity_check_option_t opts; - if (!cm2_cpu_is_low_loadavg()) + if (g_state.connected && !cm2_cpu_is_low_loadavg()) return; opts = LINK_CHECK | ROUTER_CHECK | NTP_CHECK; diff --git a/src/cm2/src/cm2_stability.h b/src/cm2/src/cm2_stability.h new file mode 100644 index 00000000..f393921e --- /dev/null +++ b/src/cm2/src/cm2_stability.h @@ -0,0 +1,49 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CM2_STABILITY_H_INCLUDED +#define CM2_STABILITY_H_INCLUDED + +typedef enum { + CM2_RESTORE_IP = 0, // Bit 0 + CM2_RESTORE_SWITCH_DUMP_DATA, // Bit 1 + CM2_RESTORE_SWITCH_FIX_PORT_MAP, // Bit 2 + CM2_RESTORE_SWITCH_FIX_AUTON // Bit 3 +} cm2_restore_con_t; + +#ifndef CONFIG_CM2_STABILITY_USE_RESTORE_SWITCH_CFG +static inline void cm2_restore_switch_cfg_params(int counter, int thresh, cm2_restore_con_t *ropt) +{ +} +static inline void cm2_restore_switch_cfg(cm2_restore_con_t opt) +{ +} +#else +void cm2_restore_switch_cfg_params(int counter, int thresh, cm2_restore_con_t *ropt); +void cm2_restore_switch_cfg(cm2_restore_con_t opt); +#endif + +#endif /* CM2_STABILITY_H_INCLUDED */ diff --git a/src/cpm/inc/captive_portal.h b/src/cpm/inc/captive_portal.h new file mode 100644 index 00000000..80ba26cf --- /dev/null +++ b/src/cpm/inc/captive_portal.h @@ -0,0 +1,52 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CAPTIVE_PORTAL_H_INCLUDED +#define CAPTIVE_PORTAL_H_INCLUDED +#include +#include +#include + +#include "ds_tree.h" + +struct cportal { + bool enabled; + char *name; + char *pkt_mark; + char *rt_tbl_id; + char *uam_url; + ds_tree_t *other_config; + ds_tree_t *additional_headers; + + ds_tree_node_t cp_tnode; +}; + +bool cportal_proxy_init(void); +bool cportal_proxy_set(struct cportal *self); +bool cportal_proxy_start(struct cportal *self); +bool cportal_proxy_stop(struct cportal *self); +int cportal_ovsdb_init(void); +#endif /* CAPTIVE_PORTAL_H_INCLUDED */ diff --git a/src/cpm/kconfig/Kconfig.managers b/src/cpm/kconfig/Kconfig.managers new file mode 100644 index 00000000..120eed51 --- /dev/null +++ b/src/cpm/kconfig/Kconfig.managers @@ -0,0 +1,32 @@ +menuconfig MANAGER_CAPTIVEPORTAL + bool "Captive Portal" + default y + help + Enable Captive Portal + + The Captive Portal manager is to run services related to bringing up captive portal + at a location. You can start it by using the following command: + + ovsh u Node_Services --where service==cpm enable:=true + + config MANAGER_CAPTIVEPORTAL_CFG + string "Captive Portal Startup configuration" + depends on MANAGER_CAPTIVEPORTAL + default "cpm;false" + help + Captive Portal startup configuration + + config CPM_TINYPROXY_PATH + string "Path to the tinyproxy binary" + depends on MANAGER_CAPTIVEPORTAL + default "/usr/sbin/tinyproxy" + help + Full path to the tinyproxy binary + + config CPM_TINYPROXY_ETC + string "tinyproxy configuration folder" + depends on MANAGER_CAPTIVEPORTAL + default "/tmp/tinyproxy" + help + This is the location where the tinyproxy.conf + file will be created. diff --git a/src/cpm/src/captive_portal_main.c b/src/cpm/src/captive_portal_main.c new file mode 100644 index 00000000..3a105843 --- /dev/null +++ b/src/cpm/src/captive_portal_main.c @@ -0,0 +1,121 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ds_tree.h" +#include "log.h" +#include "os.h" +#include "os_socket.h" +#include "ovsdb.h" +#include "evext.h" +#include "os_backtrace.h" +#include "json_util.h" +#include "target.h" + +#include "captive_portal.h" +#define MODULE_ID LOG_MODULE_ID_MAIN + +/*****************************************************************************/ + +static log_severity_t cpm_log_severity = LOG_SEVERITY_INFO; + +/****************************************************************************** + * PROTECTED definitions + *****************************************************************************/ + +/****************************************************************************** + * PUBLIC API definitions + *****************************************************************************/ + +int main(int argc, char ** argv) +{ + struct ev_loop *loop = EV_DEFAULT; + + // Parse command-line arguments + if (os_get_opt(argc, argv, &cpm_log_severity)){ + return -1; + } + + // enable logging + target_log_open("CPM", 0); + LOGN("Starting Captive Portal manager - CPM"); + log_severity_set(cpm_log_severity); + log_register_dynamic_severity(loop); + + backtrace_init(); + + json_memdbg_init(loop); + + // Connect to ovsdb + if (!ovsdb_init_loop(loop, "CPM")) { + LOGEM("Initializing CPM " + "(Failed to initialize OVSDB)"); + return 1; + } + + // Register to relevant OVSDB tables events + if (cportal_ovsdb_init()) + { + LOGE("Initializing CPM " + "(Failed to initialize CPM tables)"); + return 1; + } + + if (!cportal_proxy_init()) + { + LOGE("Initializing Captive Portal proxy service " + "(Failed to initialize proxy service)"); + return 1; + } + + // Start the event loop + ev_run(loop, 0); + + if (!ovsdb_stop_loop(loop)) + { + LOGE("Stopping Captive Portal " + "(Failed to stop OVSDB)"); + } + + ev_loop_destroy(loop); + + + LOGN("Exiting Captive Portal"); + + return 0; +} diff --git a/src/cpm/src/captive_portal_ovsdb.c b/src/cpm/src/captive_portal_ovsdb.c new file mode 100644 index 00000000..f30464d0 --- /dev/null +++ b/src/cpm/src/captive_portal_ovsdb.c @@ -0,0 +1,396 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ovsdb_update.h" +#include "ovsdb_sync.h" +#include "ovsdb_table.h" +#include "ovsdb_utils.h" +#include "schema.h" + +#include "captive_portal.h" + +/* Log entries from this file will contain "OVSDB" */ +#define MODULE_ID LOG_MODULE_ID_OVSDB + +ovsdb_table_t table_Captive_Portal; +static int cportal_cmp(void *a, void *b); +void callback_Captive_Portal( + ovsdb_update_monitor_t *mon, + struct schema_Captive_Portal *old, + struct schema_Captive_Portal *new); + +ds_tree_t cportal_list = DS_TREE_INIT(cportal_cmp, struct cportal, cp_tnode); + +/* + * Initialize table monitors + */ +int cportal_ovsdb_init(void) +{ + LOGI("Initializing Captive_Portal tables"); + + // Initialize OVSDB tables + OVSDB_TABLE_INIT_NO_KEY(Captive_Portal); + + // Initialize OVSDB monitor callbacks + OVSDB_TABLE_MONITOR(Captive_Portal, false); + + return 0; +} + +/** + * @brief compare portal instances + * + * @param a instance pointer + * @param b instance pointer + * @return 0 if sessions matches + */ +static int +cportal_cmp(void *a, void *b) +{ + /* + * For now we only support one instance of + * Captive Portal. + */ + return 0; +} + +static void +cportal_dump_map(ds_tree_t *conf) +{ + struct str_pair *pair = NULL; + + if (conf) + { + pair = ds_tree_head(conf); + LOGT("%s: config key-value pairs", __func__); + while (pair != NULL) + { + LOGT("%s:%s",pair->key,pair->value); + pair = ds_tree_next(conf, pair); + } + } +} + +static void +cportal_dump_instances(void) +{ + struct cportal *inst = ds_tree_head(&cportal_list); + + LOGT("%s: Walking cportal instances", __func__); + while (inst != NULL) + { + LOGT("service name: %s, uam_url: %s", + inst->name, inst->uam_url); + cportal_dump_map(inst->other_config); + cportal_dump_map(inst->additional_headers); + inst = ds_tree_next(&cportal_list, inst); + } +} + +char * +cportal_get_other_config_val(struct cportal *inst, char *key) +{ + struct str_pair *pair; + ds_tree_t *tree; + + tree = inst->other_config; + if (!tree) return NULL; + + pair = ds_tree_find(tree, key); + if (!pair) return NULL; + + LOGT("%s: cportal other_config %s:%s",__func__, key, pair->value); + return pair->value; +} + +static void +cportal_parse_additional_hdrs(struct cportal *inst, + struct schema_Captive_Portal *new) +{ + ds_tree_t *additional_headers; + + if (!inst || !new) return; + + additional_headers = schema2tree(sizeof(new->additional_headers_keys[0]), + sizeof(new->additional_headers[0]), + new->additional_headers_len, + new->additional_headers_keys, + new->additional_headers); + + if (!additional_headers) return; + + cportal_dump_map(additional_headers); + + if (inst->additional_headers) free_str_tree(inst->additional_headers); + + inst->additional_headers = additional_headers; + + return; +} + +static void +cportal_parse_other_config(struct cportal *inst, + struct schema_Captive_Portal *new) +{ + ds_tree_t *other_config; + + if (!inst || !new) return; + + other_config = schema2tree(sizeof(new->other_config_keys[0]), + sizeof(new->other_config[0]), + new->other_config_len, + new->other_config_keys, + new->other_config); + + if (!other_config) return; + + cportal_dump_map(other_config); + + if (inst->other_config) free_str_tree(inst->other_config); + + inst->other_config = other_config; + + inst->pkt_mark = cportal_get_other_config_val(inst, "pkt_mark"); + + inst->rt_tbl_id = cportal_get_other_config_val(inst, "rt_tbl_id"); + + return; +} + +static void +cportal_enable_inst(struct cportal *inst) +{ + if (!inst) return; + + if (inst->enabled) return; + + if (!cportal_proxy_set(inst)) + { + LOGE("%s: Couldn't configure proxy service for instance [%s]",__func__,inst->name); + return; + } + + if (!cportal_proxy_start(inst)) + { + LOGE("%s: Couldn't launch proxy service for instance [%s]",__func__,inst->name); + return; + } +} + +static void +cportal_disable_inst(struct cportal *inst) +{ + if (!inst->enabled) return; + + if (!cportal_proxy_stop(inst)) + { + LOGE("%s: Couldn't stop proxy service ",__func__); + return; + } +} + + +static void +cportal_free_cportal(struct cportal *inst) +{ + + if (!inst) return; + + free(inst->name); + free(inst->uam_url); + + free_str_tree(inst->other_config); + free_str_tree(inst->additional_headers); + free(inst); + return; +} + +static struct cportal * +cportal_alloc_inst(struct schema_Captive_Portal *new) +{ + struct cportal *inst; + + if (!new) return NULL; + + inst = calloc(1, sizeof(struct cportal)); + if (!inst) + { + LOG(ERR, "%s: Memory allocation failure\n", __func__); + return NULL; + } + + inst->name = strdup(new->name); + if (!inst->name) + { + LOG(ERR, "%s: Couldn't allocate memory for name[%s]", __func__, new->name); + goto err_name; + } + + inst->uam_url = strdup(new->uam_url); + if (!inst->uam_url) + { + LOG(ERR, "%s: Couldn't allocate memory for url[%s]", __func__, new->uam_url); + goto err_uam; + } + + cportal_parse_other_config(inst, new); + + cportal_parse_additional_hdrs(inst, new); + + return inst; +err_uam: + free(inst->name); +err_name: + free(inst); + + return NULL; +} + +static void +cportal_update(struct cportal *inst, + struct schema_Captive_Portal *mod) +{ + + if (!inst || !mod) return; + + cportal_disable_inst(inst); + + ds_tree_remove(&cportal_list, inst); + + cportal_free_cportal(inst); + + inst = cportal_alloc_inst(mod); + + ds_tree_insert(&cportal_list, inst, inst->name); + + cportal_enable_inst(inst); + return; +} + +static void +cportal_add(struct schema_Captive_Portal *new) +{ + struct cportal *inst; + + if (!new) return; + + inst = ds_tree_find(&cportal_list, new->name); + if (inst) + { + LOGD("%s: Allowing only one instance of captive portal %s.",__func__,inst->name); + return; + } + + inst = cportal_alloc_inst(new); + + if (!inst) + { + LOGE("%s: Could not allocate cportal instance %s", __func__, new->name); + return; + } + LOG(INFO, "%s: Created new cportal instance [%s]", __func__, inst->name); + ds_tree_insert(&cportal_list, inst, inst->name); + + cportal_enable_inst(inst); + + LOG(INFO, "%s: Created new cportal instance [%s]", __func__, inst->name); + +} + +static void +cportal_mod(struct schema_Captive_Portal *mod) +{ + struct cportal *inst; + + if (!mod) return; + + inst = ds_tree_find(&cportal_list, mod->name); + + if (!inst) return; + + if (strcmp(mod->name, inst->name)) return; + + cportal_update(inst, mod); + +} + +static void +cportal_del(struct schema_Captive_Portal *del) +{ + struct cportal *inst; + + if (!del) return; + + inst = ds_tree_find(&cportal_list, del->name); + if (!inst) return; + + if (strcmp(del->name, inst->name)) return; + + cportal_disable_inst(inst); + + ds_tree_remove(&cportal_list, inst); + + cportal_free_cportal(inst); + return; +} + +/* + * OVSDB monitor update callback for Captive_Portal + */ +void callback_Captive_Portal( + ovsdb_update_monitor_t *mon, + struct schema_Captive_Portal *old, + struct schema_Captive_Portal *new) +{ + + switch (mon->mon_type) + { + case OVSDB_UPDATE_NEW: + { + cportal_add(new); + cportal_dump_instances(); + break; + } + case OVSDB_UPDATE_MODIFY: + { + cportal_mod(new); + cportal_dump_instances(); + break; + } + case OVSDB_UPDATE_DEL: + { + cportal_del(old); + cportal_dump_instances(); + break; + } + default: + LOGW("%s:mon upd error: %d", __func__, mon->mon_type); + return; + } + return; +} + + diff --git a/src/cpm/src/captive_portal_proxy.c b/src/cpm/src/captive_portal_proxy.c new file mode 100644 index 00000000..3fbe984f --- /dev/null +++ b/src/cpm/src/captive_portal_proxy.c @@ -0,0 +1,406 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "evx.h" +#include "ovsdb_utils.h" +#include "daemon.h" + +#include "os.h" +#include "const.h" +#include "util.h" +#include "log.h" + +#include "captive_portal.h" + +#define TINYPROXY_CONF_PATH CONFIG_CPM_TINYPROXY_ETC "/tinyproxy.conf" + +#define TINYPROXY_DEBOUNCE_TIMER 1.0 + +static char cportal_proxy_conf_header[] = + "#\n" + "# Auto-generated by OpenSync\n" + "#\n" + "\n" + "DisableHttpErrors Yes\n" + "Syslog on\n" + "Loglevel connect\n" + "Timeout 600\n" + "MaxClients 255\n" + "XTinyproxy Yes\n" + "XTinyproxy-MAC Yes\n" + "\n"; + +static bool cportal_proxy_global_init = false; +static daemon_t cportal_proxy_process; +static ev_debounce cportal_proxy_debounce; + +struct cportal_proxy_other_config { + char *listenip; + char *listenport; + char *xtinyproxy_hdr; + char *xtinyproxy_mac_hdr; + char *viahdr; + char *timeout; + char *max_clients; + char *loglvl; +}; + +static char * +cportal_proxy_get_other_config_val(struct cportal *self, char *key) +{ + ds_tree_t *conf_pairs; + struct str_pair *pair; + + if (!self->other_config || !key) return NULL; + + conf_pairs = self->other_config; + pair = ds_tree_find(conf_pairs, key); + if (!pair) return NULL; + + return pair->value; +} + +static void +cportal_proxy_fill_vals(struct cportal *self, struct cportal_proxy_other_config *pconf) +{ + if (!self || !pconf) return; + + if (!self->other_config) return; + + pconf->listenip = cportal_proxy_get_other_config_val(self, "listenip"); + pconf->listenport = cportal_proxy_get_other_config_val(self, "listenport"); + pconf->xtinyproxy_hdr = cportal_proxy_get_other_config_val(self, "xtinyproxyhdr"); + pconf->xtinyproxy_hdr = cportal_proxy_get_other_config_val(self, "xtinyproxymachdr"); + pconf->viahdr = cportal_proxy_get_other_config_val(self, "viaproxyname"); + pconf->timeout = cportal_proxy_get_other_config_val(self, "timeout"); + pconf->max_clients = cportal_proxy_get_other_config_val(self, "max_clients"); + pconf->loglvl = cportal_proxy_get_other_config_val(self, "loglevel"); +} + +static bool +cportal_proxy_write_additional_hdrs(struct cportal *self) +{ + FILE *fconf = NULL; + ds_tree_t *add_hdrs; + struct str_pair *pair = NULL; + + if (!self) return false; + + if (!self->additional_headers) return false; + + fconf = fopen(TINYPROXY_CONF_PATH, "a"); + if (!fconf) fconf = fopen(TINYPROXY_CONF_PATH, "w"); + if (!fconf) + { + LOG(ERR, "%s: Error creating tinyproxy config file: %s", __func__, TINYPROXY_CONF_PATH); + return false; + } + + add_hdrs = self->additional_headers; + + pair = ds_tree_head(add_hdrs); + while (pair != NULL) + { + LOGT("%s: key:%s value:%s\n",__func__,pair->key, pair->value); + fprintf(fconf, "AddHeader \"%s\" \"%s\"\n", pair->key, pair->value); + pair = ds_tree_next(add_hdrs, pair); + } + + + fflush(fconf); + + if (fconf != NULL) fclose(fconf); + return true; +} + +static bool +cportal_proxy_write_other_config(struct cportal *self) +{ + FILE *fconf = NULL; + struct cportal_proxy_other_config pconf; + + if (!self) return false; + + memset(&pconf, 0, sizeof(struct cportal_proxy_other_config)); + cportal_proxy_fill_vals(self, &pconf); + + fconf = fopen(TINYPROXY_CONF_PATH, "w"); + if (fconf == NULL) + { + LOG(ERR, "%s: Error creating tinyproxy config file: %s", __func__, TINYPROXY_CONF_PATH); + return false; + } + + fprintf(fconf, "%s\n", cportal_proxy_conf_header); + + if (pconf.listenip) + fprintf(fconf, "Listen %s\n", pconf.listenip); + else + fprintf(fconf, "Listen 127.0.0.1\n"); + + if (pconf.listenport) + fprintf(fconf, "port %s\n", pconf.listenport); + else + fprintf(fconf, "port 8888\n"); + + if (self->uam_url) + fprintf(fconf, "upstream http %s\n", self->uam_url); + + if (pconf.xtinyproxy_hdr) + fprintf(fconf, "XTinyproxy %s\n",pconf.xtinyproxy_hdr); + + if (pconf.xtinyproxy_mac_hdr) + fprintf(fconf, "XTinyproxy-MAC %s\n",pconf.xtinyproxy_hdr); + + if (pconf.viahdr) + fprintf(fconf, "ViaProxyName \"%s\"\n", pconf.viahdr); + else + fprintf(fconf, "DisableViaHeader Yes\n"); + + if (pconf.timeout) + fprintf(fconf, "Timeout %s\n", pconf.timeout); + + if (pconf.max_clients) + fprintf(fconf, "MaxClients %s\n", pconf.max_clients); + + if (pconf.loglvl) + fprintf(fconf, "LogLevel %s\n", pconf.loglvl); + + + fflush(fconf); + + if (fconf != NULL) fclose(fconf); + return true; +} + +static bool +cportal_proxy_setup_nw_cfg(struct cportal *self, bool enable) +{ + char cmd_buff[512] = {0}; + char *pkt_mark = "0xa"; + char *rt_tbl_id = "100"; + char *listenip; + char *listenport; + + if (!self) return false; + + if (self->pkt_mark) pkt_mark = self->pkt_mark; + if (self->rt_tbl_id) rt_tbl_id = self->rt_tbl_id; + listenip = cportal_proxy_get_other_config_val(self, "listenip"); + if (!listenip) listenip = "127.0.0.1"; + listenport = cportal_proxy_get_other_config_val(self, "listenport"); + if (!listenport) listenport = "8888"; + + snprintf(cmd_buff, sizeof(cmd_buff), + "iptables -t mangle %s PREROUTING -m mark --mark %s -p tcp --dport 80" + " -j TPROXY --on-port %s --on-ip %s", + enable ? "-A" : "-D", + pkt_mark, listenport, listenip); + if (cmd_log(cmd_buff) == -1) + { + LOGE("%s: Failed to execute command %s", __func__, cmd_buff); + return false; + } + + memset(cmd_buff, 0, sizeof(cmd_buff)); + snprintf(cmd_buff, sizeof(cmd_buff), + "ip rule %s fwmark %s lookup %s", + enable ? "add" : "del", + pkt_mark, rt_tbl_id); + if (cmd_log(cmd_buff) == -1) + { + LOGE("%s: Failed to execute command %s", __func__, cmd_buff); + return false; + } + + memset(cmd_buff, 0, sizeof(cmd_buff)); + snprintf(cmd_buff, sizeof(cmd_buff), + "ip route %s local default dev lo table %s", + enable ? "add" : "del", + rt_tbl_id); + LOGT("%s: command %s", __func__, cmd_buff); + if (cmd_log(cmd_buff) == -1) + { + LOGE("%s: Failed to execute command %s", __func__, cmd_buff); + return false; + } + + return true; +} + +static bool +cportal_proxy_write_config(struct cportal *self) +{ + + if (!self) return false; + + if (mkdir(CONFIG_CPM_TINYPROXY_ETC, 0700) != 0 && errno != EEXIST) + { + LOG(ERR, "%s: Error creating tinyproxy config dir: %s", __func__, CONFIG_CPM_TINYPROXY_ETC); + return false; + } + + + if (!cportal_proxy_write_other_config(self)) + { + LOGE("%s: Failed to write proxy config.",__func__); + } + + if (!cportal_proxy_write_additional_hdrs(self)) + { + LOGW("%s: Failed to write additional headers config.",__func__); + } + return true; +} + +/** + * Global restart of the tinyproxy service + */ +static void +__cportal_proxy_restart(void) +{ + if (!cportal_proxy_global_init) return; + + LOG(INFO, "%s: daemon restart...\n",__func__); + + if (!daemon_stop(&cportal_proxy_process)) + { + LOG(WARN, "%s: Error stopping the tinyproxy process.",__func__); + } + + if (!daemon_start(&cportal_proxy_process)) + { + LOG(ERR, "%s: Error starting tinyproxy.",__func__); + goto exit; + } + +exit: + return; +} + +static void +cportal_proxy_restart_debounce(struct ev_loop *loop, ev_debounce *ev, int revent) +{ + (void)loop; + (void)ev; + (void)revent; + + __cportal_proxy_restart(); +} + +static void +cportal_proxy_restart(void) +{ + /* Do a delayed restart */ + ev_debounce_start(EV_DEFAULT, &cportal_proxy_debounce); +} + +bool cportal_proxy_init(void) +{ + + if (!cportal_proxy_global_init) + { + /* + * Initialize the tinyproxy global instance and process + */ + ev_debounce_init(&cportal_proxy_debounce, cportal_proxy_restart_debounce, TINYPROXY_DEBOUNCE_TIMER); + + if (!daemon_init(&cportal_proxy_process, CONFIG_CPM_TINYPROXY_PATH, 0)) + { + LOG(ERR, "%s: Error initializing proxy.", __func__); + return false; + } + + daemon_arg_add(&cportal_proxy_process, "-d"); /* Run in foreground */ + daemon_arg_add(&cportal_proxy_process, "-c", TINYPROXY_CONF_PATH); /* Config file path */ + + /* Path to the PID file */ + if (!daemon_pidfile_set(&cportal_proxy_process, "/var/run/tinyproxy.pid", false)) + { + LOG(ERR, "%s: Error initializing proxy pid file.", __func__); + return false; + } + + cportal_proxy_global_init = true; + } + + return true; +} + +/** + * Start the service. + */ +bool cportal_proxy_start(struct cportal *self) +{ + cportal_proxy_restart(); + self->enabled = true; + return true; +} + +/** + * Stop the tinyproxy service + */ +bool cportal_proxy_stop(struct cportal *self) +{ + if (!cportal_proxy_setup_nw_cfg(self, false)) + { + LOG(ERR, "%s: Error setting up network config.", __func__); + return false; + } + + ev_debounce_stop(EV_DEFAULT, &cportal_proxy_debounce); + + if (!daemon_stop(&cportal_proxy_process)) + { + LOG(WARN, "%s: Error stopping tinyproxy server.",__func__); + return false; + } + + cportal_proxy_global_init = true; + return true; +} + +bool cportal_proxy_set(struct cportal *self) +{ + if (!cportal_proxy_global_init) return false; + + if (!cportal_proxy_write_config(self)) + { + LOG(ERR, "%s: Error writing tinyproxy config file[%s].",__func__, + TINYPROXY_CONF_PATH); + return false; + } + + if (!cportal_proxy_setup_nw_cfg(self, true)) + { + LOG(ERR, "%s: Error setting up network config.", __func__); + return false; + } + + return true; +} diff --git a/src/cpm/unit.mk b/src/cpm/unit.mk new file mode 100644 index 00000000..8007166a --- /dev/null +++ b/src/cpm/unit.mk @@ -0,0 +1,57 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################## +# +# Captive Portal service +# +############################################################################## +UNIT_NAME := cpm + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_CAPTIVEPORTAL),n,y) + +# Template type: +UNIT_TYPE := BIN + +UNIT_SRC := src/captive_portal_main.c +UNIT_SRC += src/captive_portal_ovsdb.c +UNIT_SRC += src/captive_portal_proxy.c + +UNIT_CFLAGS := -I$(UNIT_PATH)/inc +UNIT_CFLAGS += -I$(TOP_DIR)/src/lib/common/inc/ + +UNIT_LDFLAGS := -lev + +UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS) +UNIT_EXPORT_LDFLAGS := $(UNIT_LDFLAGS) + +UNIT_DEPS += src/lib/common +UNIT_DEPS += src/lib/ovsdb +UNIT_DEPS += src/lib/evx +UNIT_DEPS += src/lib/pjs +UNIT_DEPS += src/lib/schema +UNIT_DEPS += src/lib/datapipeline +UNIT_DEPS += src/lib/json_util +UNIT_DEPS += src/lib/schema +UNIT_DEPS += src/lib/daemon diff --git a/src/dm/fut/brv_busybox_builtins.sh b/src/dm/fut/brv_busybox_builtins.sh new file mode 100755 index 00000000..917e31e0 --- /dev/null +++ b/src/dm/fut/brv_busybox_builtins.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include environment config from default shell file +source /tmp/fut-base/shell/config/default_shell.sh +[ -e "/tmp/fut_set_env.sh" ] && source /tmp/fut_set_env.sh +# Include shared libraries and library overrides +source ${FUT_TOPDIR}/shell/lib/brv_lib.sh + +tc_name="brv/$(basename $0)" +usage() +{ +cat << EOF +${tc_name} [-h] builtin_tool +where options are: + -h show this help message +input arguments: + builtin_tool=$1 -- name of the required busybox built-in tool - (string)(required) +this script is dependent on following: + - running brv_setup.sh +example of usage: + ${tc_name} "tail" +EOF +} + +while getopts h option; do + case "$option" in + h) + usage + exit 1 + ;; + esac +done + +NARGS=1 +[ $# -lt ${NARGS} ] && raise "Requires at least '${NARGS}' input argument(s)" -l "${tc_name}" -arg +builtin_tool=$1 +log_title "${tc_name}: Verify '${builtin_tool}' is built into busybox" + +is_tool_on_system "busybox" +rc=$? +if [ $rc != 0 ]; then + raise "Refusing tool search, busybox is not present on system" -l "${tc_name}" -nf +fi + +is_busybox_builtin ${builtin_tool} +rc=$? +if [ $rc == 0 ]; then + log -deb "${tc_name}: '${builtin_tool}' is built into busybox" +else + raise "'${builtin_tool}' is not built into busybox" -l "${tc_name}" -tc +fi + +pass diff --git a/src/dm/fut/brv_is_tool_on_system.sh b/src/dm/fut/brv_is_tool_on_system.sh new file mode 100755 index 00000000..48820ae5 --- /dev/null +++ b/src/dm/fut/brv_is_tool_on_system.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source ${FUT_TOPDIR}/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/brv_lib.sh + +tc_name="brv/$(basename $0)" +usage() +{ +cat << EOF +${tc_name} [-h] tool_path +where options are: + -h show this help message +input arguments: + tool_path=$1 -- name or path of the required tool - (string)(required) + If only the tool name is provided, PATH is searched. + If the absolute path is provided, that is used to confirm the presence. +this script is dependent on following: + - running brv_setup.sh +example of usage: + ${tc_name} "ls" + ${tc_name} "bc" +EOF +} + +while getopts h option; do + case "$option" in + h) + usage + exit 1 + ;; + esac +done + +NARGS=1 +[ $# -lt ${NARGS} ] && raise "Requires at least '${NARGS}' input argument(s)" -l "${tc_name}" -arg +tool_path=$1 +log_title "${tc_name}: Verify tool '${tool_path}' is present on device" + +is_tool_on_system ${tool_path} +rc=$? +if [ $rc == 0 ]; then + log -deb "${tc_name}: tool '${tool_path}' found on device" +elif [ $rc == 126 ]; then + raise "Tool '${tool_path}' found on device but could not be invoked" -l "${tc_name}" -ec ${rc} -tc +else + raise "Tool '${tool_path}' could not be found on device" -l "${tc_name}" -ec ${rc} -tc +fi + +pass diff --git a/src/dm/fut/brv_ovs_correct_version.sh b/src/dm/fut/brv_ovs_correct_version.sh new file mode 100755 index 00000000..fe46813d --- /dev/null +++ b/src/dm/fut/brv_ovs_correct_version.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include environment config from default shell file +source /tmp/fut-base/shell/config/default_shell.sh +[ -e "/tmp/fut_set_env.sh" ] && source /tmp/fut_set_env.sh +# Include shared libraries and library overrides +source ${FUT_TOPDIR}/shell/lib/brv_lib.sh + +tc_name="brv/$(basename $0)" +usage() +{ +cat << EOF +${tc_name} [-h] expected_version +where options are: + -h show this help message +input arguments: + expected_version=$1 -- expected version of the Open vSwitch - (string)(required) +this script is dependent on following: + - running brv_setup.sh +example of usage: + ${tc_name} "2.8.7" +EOF +} + +while getopts h option; do + case "$option" in + h) + usage + exit 1 + ;; + esac +done + +NARGS=1 +[ $# -ne ${NARGS} ] && raise "Requires ${NARGS} input arguments" -l "${tc_name}" -arg +expected_ovs_ver=$1 +log_title "${tc_name}: Verify OVS version is ${expected_ovs_ver}" + +check_ovs_version ${expected_ovs_ver} && + log -deb "${tc_name}: OVS version on the device is as expected: ${expected_ovs_ver}" || + raise "OVS version on the device: ${actual_ovs_ver} is NOT as expected: ${expected_ovs_ver}" -l "${tc_name}" -tc + +pass diff --git a/src/dm/fut/brv_setup.sh b/src/dm/fut/brv_setup.sh new file mode 100755 index 00000000..85ece86f --- /dev/null +++ b/src/dm/fut/brv_setup.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include environment config from default shell file +source /tmp/fut-base/shell/config/default_shell.sh +[ -e "/tmp/fut_set_env.sh" ] && source /tmp/fut_set_env.sh +# Include shared libraries and library overrides +source ${FUT_TOPDIR}/shell/lib/brv_lib.sh + +brv_setup_env && + log "brv/$(basename "$0"): brv_setup_env - Success " || + die "brv/$(basename "$0"): brv_setup_env - Failed" + +exit 0 diff --git a/src/dm/fut/dm_fetch_managers_startup.sh b/src/dm/fut/dm_fetch_managers_startup.sh new file mode 100755 index 00000000..74616a70 --- /dev/null +++ b/src/dm/fut/dm_fetch_managers_startup.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/dm_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +# fetching managers +MANAGER_NR=`ps w | grep -i plume | wc -l` +if [ "$MANAGER_NR" -lt 15 ]; then + die "Not enough managers started." +fi diff --git a/src/dm/fut/dm_setup.sh b/src/dm/fut/dm_setup.sh new file mode 100755 index 00000000..3d76b11e --- /dev/null +++ b/src/dm/fut/dm_setup.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for DM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/dm_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="dm/$(basename "$0")" + +log_title "$tc_name: DM test environment script" + +log "$tc_name: Stopping managers" +disable_managers + +log "$tc_name: Starting only DM" +start_specific_manager dm + +sleep 5 +log "$tc_name: Checking managers" +ps w | grep -i plume diff --git a/src/dm/fut/onbrd_setup.sh b/src/dm/fut/onbrd_setup.sh new file mode 100755 index 00000000..efb748ba --- /dev/null +++ b/src/dm/fut/onbrd_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for ONBRD tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="onbrd/$(basename "$0")" + +onbrd_setup_test_environment "$@" && + log "$tc_name: onbrd_setup_test_environment - Success " || + raise "onbrd_setup_test_environment - Failed" -l "$tc_name" -ds + +exit 0 diff --git a/src/dm/fut/onbrd_verify_bridge_mode.sh b/src/dm/fut/onbrd_verify_bridge_mode.sh new file mode 100755 index 00000000..4f25f391 --- /dev/null +++ b/src/dm/fut/onbrd_verify_bridge_mode.sh @@ -0,0 +1,145 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Fill variables with provided arguments or defaults. +wan_interface=${1:-br-wan} +wan_ip=${2:-192.168.200.10} +home_interface=${3:-br-home} +patch_w2h=${5:-patch-w2h} +patch_h2w=${6:-patch-h2w} + +tc_name="onbrd/$(basename "$0")" +log "$tc_name: ONBRD Verify bridge mode settings applied" + +# br-wan section +# Check if DHCP client is running on br-wan (wan bridge) +wait_for_function_response 0 "check_pid_udhcp $wan_interface" && + log "$tc_name: check_pid_udhcp - PID found, DHCP client running" || + raise "check_pid_udhcp - PID not found, DHCP client NOT running" -l "$tc_name" -tc + +update_ovsdb_entry Wifi_Inet_Config -w if_name "$wan_interface" -u NAT true && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - NAT=true" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - NAT=true" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$wan_interface" -is NAT true && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - NAT=true" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - NAT=true" -l "$tc_name" -tc + +update_ovsdb_entry Wifi_Inet_Config -w if_name "$wan_interface" -u ip_assign_scheme dhcp && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=dhcp" || + raise "update_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=dhcp" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$wan_interface" -is ip_assign_scheme dhcp && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=dhcp" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=dhcp" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$wan_interface" -is inet_addr "$wan_ip" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - inet_addr is private" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - inet_addr is NOT private" -l "$tc_name" -tc + +# br-home section +update_ovsdb_entry Wifi_Inet_Config -w if_name "$home_interface" -u NAT false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - NAT=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - NAT=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$home_interface" -is NAT false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - NAT=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - NAT=false" -l "$tc_name" -tc + +update_ovsdb_entry Wifi_Inet_Config -w if_name "$home_interface" -u ip_assign_scheme none && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=none" || + raise "update_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=none" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$home_interface" -is ip_assign_scheme none && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=none" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=none" -l "$tc_name" -tc + +update_ovsdb_entry Wifi_Inet_Config -w if_name "$home_interface" -u "dhcpd" "[\"map\",[]]" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - dhcpd=[\"map\",[]]" || + raise "update_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - dhcpd=[\"map\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$home_interface" -is "dhcpd" "[\"map\",[]]" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - dhcpd [\"map\",[]]" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - dhcpd [\"map\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$home_interface" -is "netmask" "0.0.0.0" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - netmask 0.0.0.0" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - netmask 0.0.0.0" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$home_interface" -is inet_addr "0.0.0.0" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - inet_addr is 0.0.0.0" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - inet_addr is NOT 0.0.0.0" -l "$tc_name" -tc + +# Creating patch interface +log "$tc_name: create_patch_interface - creating patch $patch_w2h $patch_h2w" +create_patch_interface "$wan_interface" "$patch_w2h" "$patch_h2w" && + log "$tc_name: check_patch_if_exists - patch interface $patch_w2h created" || + raise "check_patch_if_exists - Failed to create patch interface $patch_w2h" -l "$tc_name" -tc + +wait_for_function_response 0 "check_if_patch_exists $patch_w2h" && + log "$tc_name: check_patch_if_exists - patch interface $patch_w2h exists" || + raise "check_patch_if_exists - patch interface $patch_w2h does not exists" -l "$tc_name" -tc + +wait_for_function_response 0 "check_if_patch_exists $patch_h2w" && + log "$tc_name: check_patch_if_exists - patch interface $patch_h2w exists" || + raise "check_patch_if_exists - patch interface $patch_h2w does not exists" -l "$tc_name" -tc + +# Restart managers to tidy up config +restart_managers + +pass diff --git a/src/dm/fut/onbrd_verify_client_certificate_files.sh b/src/dm/fut/onbrd_verify_client_certificate_files.sh new file mode 100755 index 00000000..ad7d6894 --- /dev/null +++ b/src/dm/fut/onbrd_verify_client_certificate_files.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + cert_file=\$1 -- used as file to check - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") ca_cert + /tmp/fut-base/shell/onbrd/$(basename "$0") certificate + /tmp/fut-base/shell/onbrd/$(basename "$0") private_key +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -ne 1 ]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +cert_file=$1 +tc_name="onbrd/$(basename "$0")" +cert_file_path=$(get_ovsdb_entry_value SSL "$cert_file") + +log "$tc_name: ONBRD Verify file exists" +[ -e "$cert_file_path" ] && + log "$tc_name: SUCCESS: file is valid - $cert_file_path" || + raise "FAIL: file is missing - $cert_file_path" -l "$tc_name" -tc + +log "$tc_name: ONBRD Verify file is not empty" +[ -s "$cert_file_path" ] && + log "$tc_name: SUCCESS: file is not empty - $cert_file_path" || + raise "FAIL: file is empty - $cert_file_path" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/onbrd_verify_client_tls_connection.sh b/src/dm/fut/onbrd_verify_client_tls_connection.sh new file mode 100755 index 00000000..5c219274 --- /dev/null +++ b/src/dm/fut/onbrd_verify_client_tls_connection.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running DM manager + - both DUT and cloud controller (simulation service on RPI) must have correct certificates and CA files + - device time synched to real time + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify client TLS connection" + +connect_to_fut_cloud && + log "$tc_name: Device connected to FUT cloud. Start test case execution" || + raise "Failed to connect device to FUT cloud. Terminate test" -l "$tc_name" -tc + +# Check if connection is maintained for 60s +log "$tc_name: Checking if connection is maintained and stable" +for interval in $(seq 1 3); do + log "$tc_name: Sleeping for 20 seconds" + sleep 20 + + log "$tc_name: Wait for connection status in Manager table is ACTIVE, check num: $interval" + wait_for_function_response 0 "wait_cloud_state ACTIVE" && + log "$tc_name: wait_cloud_state - Connection state is ACTIVE, check num: $interval" || + raise "wait_cloud_state - FAILED: Connection state is NOT ACTIVE, check num: $interval" -l "$tc_name" -tc +done + +pass diff --git a/src/dm/fut/onbrd_verify_device_mode_awlan_node.sh b/src/dm/fut/onbrd_verify_device_mode_awlan_node.sh new file mode 100755 index 00000000..58b1bc5c --- /dev/null +++ b/src/dm/fut/onbrd_verify_device_mode_awlan_node.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") not_set + /tmp/fut-base/shell/onbrd/$(basename "$0") cloud + /tmp/fut-base/shell/onbrd/$(basename "$0") monitor + /tmp/fut-base/shell/onbrd/$(basename "$0") battery +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +device_mode=${1:-"not_set"} + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify device mode in AWLAN_Node" + +if [ "$device_mode" = "not_set" ]; then + wait_ovsdb_entry AWLAN_Node -is device_mode "[\"set\",[]]" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node device_mode equal to '[\"set\",[]]'" || + raise "wait_ovsdb_entry - AWLAN_Node device_mode NOT equal to '$device_mode'" -l "$tc_name" -tc +else + wait_ovsdb_entry AWLAN_Node -is device_mode "$device_mode" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node device_mode equal to '$device_mode'" || + raise "wait_ovsdb_entry - AWLAN_Node device_mode NOT equal to '$device_mode'" -l "$tc_name" -tc +fi + +pass diff --git a/src/dm/fut/onbrd_verify_dhcp_dry_run_success.sh b/src/dm/fut/onbrd_verify_dhcp_dry_run_success.sh new file mode 100755 index 00000000..aa47444f --- /dev/null +++ b/src/dm/fut/onbrd_verify_dhcp_dry_run_success.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") eth0 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -ne 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify DHCP dry run success" + +update_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -u has_L2 false && + log "$tc_name: update_ovsdb_entry - Connection_Manager_Uplink table updated - has_L2 false" || + raise "update_ovsdb_entry - Failed to update WifConnection_Manager_Uplinki_Inet_Config - has_L2 false" -l "$tc_name" -tc + +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L2 false && + log "$tc_name: wait_ovsdb_entry - Connection_Manager_Uplink - has_L2 is false" || + raise "wait_ovsdb_entry - Failed to reflect has_L2 to Connection_Manager_Uplink has_L2 is not false" -l "$tc_name" -tc + +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L3 false && + log "$tc_name: wait_ovsdb_entry - Connection_Manager_Uplink - has_L3 is false" || + raise "wait_ovsdb_entry - Failed to reflect has_L3 to Connection_Manager_Uplink has_L3 is not false" -l "$tc_name" -tc + + +update_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -u has_L2 true && + log "$tc_name: update_ovsdb_entry - Connection_Manager_Uplink table updated - has_L2 false" || + raise "update_ovsdb_entry - Failed to update WifConnection_Manager_Uplinki_Inet_Config - has_L2 false" -l "$tc_name" -tc + +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L2 true && + log "$tc_name: wait_ovsdb_entry - Connection_Manager_Uplink - has_L2 is true" || + raise "wait_ovsdb_entry - Failed to reflect has_L2 to Connection_Manager_Uplink has_L2 is not true" -l "$tc_name" -tc + +wait_ovsdb_entry Connection_Manager_Uplink -w if_name "$if_name" -is has_L3 true && + log "$tc_name: wait_ovsdb_entry - Connection_Manager_Uplink - has_L3 is true" || + raise "wait_ovsdb_entry - Failed to reflect has_L3 to Connection_Manager_Uplink has_L3 is not true" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/onbrd_verify_dut_system_time_accuracy.sh b/src/dm/fut/onbrd_verify_dut_system_time_accuracy.sh new file mode 100755 index 00000000..bec9b9e1 --- /dev/null +++ b/src/dm/fut/onbrd_verify_dut_system_time_accuracy.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# It is important for this particular testcase, to capture current time ASAP +time_now=$(date -u +"%s") + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message +arguments: + time_ref=\$1 -- format: seconds since epoch. Used to compare system time. (int)(required) + time_accuracy=\$2 -- format: seconds. Allowed time deviation from reference time. (int)(required) +It is important to compare timestamps to the same time zone: UTC is used internally! + +example of usage: + accuracy=2 + reference_time=\$(date --utc +\"%s\") + /tmp/fut-base/shell/onbrd/$(basename "$0") \$reference_time \$time_accuracy +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Input parameters +if [ $# -ne 2 ]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +time_ref=$1 +time_accuracy=$2 +tc_name="onbrd/$(basename "$0")" + +# Timestamps in human readable format +time_ref_str=$(date -d @"${time_ref}") +time_now_str=$(date -d @"${time_now}") + +# Calculate time difference and ensure absolute value +time_diff=$(( time_ref - time_now )) +if [ $time_diff -lt 0 ]; then + time_diff=$(( -time_diff )) +fi + +log "$tc_name: Checking time ${time_now_str} against reference ${time_ref_str}" +if [ $time_diff -le "$time_accuracy" ]; then + log "$tc_name: Time difference ${time_diff}s is within ${time_accuracy}s" +else + raise "Time difference ${time_diff}s is NOT within ${time_accuracy}s" -l "$tc_name" -tc +fi + +pass diff --git a/src/dm/fut/onbrd_verify_fw_version_awlan_node.sh b/src/dm/fut/onbrd_verify_fw_version_awlan_node.sh new file mode 100755 index 00000000..a2cb091b --- /dev/null +++ b/src/dm/fut/onbrd_verify_fw_version_awlan_node.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + firmware_version=\$1 -- used as FW version to verify running correct FW - (string)(required) + only_check_nonempty=\$2 -- used to override exact FW version match and only check if firmware_version is populated - (string)(optional) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") 2.4.3-72-g65b961c-dev-debug +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -ne 1 ]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +search_rule=${1:-"non_empty"} + +tc_name="onbrd/$(basename "$0")" + +if [ "$search_rule" = "non_empty" ]; then + log "$tc_name: ONBRD Verify FW version, waiting for $search_rule string" + wait_for_function_response 'notempty' "get_ovsdb_entry_value AWLAN_Node firmware_version" && + log "$tc_name: check_firmware_version_populated - firmware_version populated" || + raise "check_firmware_version_populated - firmware_version un-populated" -l "$tc_name" -tc +elif [ "$search_rule" = "pattern_match" ]; then + log "$tc_name: ONBRD Verify FW version, waiting for $search_rule" + wait_for_function_response 0 "onbrd_check_fw_pattern_match" && + log "$tc_name: check_fw_pattern_match - firmware_version patter match" || + raise "check_fw_pattern_match - firmware_version patter didn't match" -l "$tc_name" -tc +else + log "$tc_name: ONBRD Verify FW version, waiting for exactly '$search_rule'" + wait_ovsdb_entry AWLAN_Node -is firmware_version "$search_rule" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node firmware_version equal to '$1'" || + raise "wait_ovsdb_entry - AWLAN_Node firmware_version NOT equal to '$1'" -l "$tc_name" -tc +fi + +pass diff --git a/src/dm/fut/onbrd_verify_home_vaps_on_home_bridge.sh b/src/dm/fut/onbrd_verify_home_vaps_on_home_bridge.sh new file mode 100755 index 00000000..29af12a8 --- /dev/null +++ b/src/dm/fut/onbrd_verify_home_vaps_on_home_bridge.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + interface_name=\$1 -- used as interface name to check - (string)(required) + bridge_home_interface=\$2 -- used as bridge interface name to check - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") wl1.2 br-home + /tmp/fut-base/shell/onbrd/$(basename "$0") home-ap-l50 br-home +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -ne 2 ]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +interface_name=$1 +bridge_home_interface=$2 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify home VAPs on home bridge, check if interface $interface_name in $bridge_home_interface" + +wait_for_function_response 0 "check_ovsdb_entry Wifi_VIF_State -w if_name $interface_name" && + log "$tc_name: SUCCESS: interface $interface_name exists" || + raise "FAIL: interface $interface_name does not exist" -l "$tc_name" -tc + +log "$tc_name: ONBRD Setting Wifi_VIF_Config bridge to $bridge_home_interface" +update_ovsdb_entry Wifi_VIF_Config -u bridge "$bridge_home_interface" && + log "$tc_name: update_ovsdb_entry - Wifi_VIF_Config table updated - bridge $bridge_home_interface" || + raise "update_ovsdb_entry - Failed to update Wifi_VIF_Config table - bridge $bridge_home_interface" -l "$tc_name" -tc + +log "$tc_name: ONBRD Verify bridge, waiting for Wifi_VIF_State bridge is $bridge_home_interface" +wait_ovsdb_entry Wifi_VIF_State -w if_name "$interface_name" -is bridge "$bridge_home_interface" && + log "$tc_name: wait_ovsdb_entry - Wifi_VIF_State bridge is $bridge_home_interface" || + raise "wait_ovsdb_entry - Wifi_VIF_State bridge is NOT $bridge_home_interface" -l "$tc_name" -tc + +log "$tc_name: Clean created interfaces after test" +vif_clean + +pass diff --git a/src/dm/fut/onbrd_verify_home_vaps_on_radios.sh b/src/dm/fut/onbrd_verify_home_vaps_on_radios.sh new file mode 100755 index 00000000..f9520970 --- /dev/null +++ b/src/dm/fut/onbrd_verify_home_vaps_on_radios.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as interface name to check - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") home-ap-24 + /tmp/fut-base/shell/onbrd/$(basename "$0") home-ap-l50 + /tmp/fut-base/shell/onbrd/$(basename "$0") home-ap-u50 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -ne 1 ]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +interface_name=$1 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify home VAPs on all radios, check interface $interface_name" + +wait_for_function_response 0 "check_ovsdb_entry Wifi_VIF_State -w if_name $interface_name" && + log "SUCCESS: interface $interface_name exists" || + raise "FAIL: interface $interface_name does not exist" -l "$tc_name" -tc + +log "$tc_name: Clean created interfaces after test" +vif_clean + +pass diff --git a/src/dm/fut/onbrd_verify_id_awlan_node.sh b/src/dm/fut/onbrd_verify_id_awlan_node.sh new file mode 100755 index 00000000..2841cc45 --- /dev/null +++ b/src/dm/fut/onbrd_verify_id_awlan_node.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify id, waiting for non-empty string" + +wait_for_function_response 'notempty' "get_ovsdb_entry_value AWLAN_Node id" && + log "$tc_name: ID populated" || + raise "ID un-populated" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/onbrd_verify_manager_hostname_resolved.sh b/src/dm/fut/onbrd_verify_manager_hostname_resolved.sh new file mode 100755 index 00000000..1442ebbd --- /dev/null +++ b/src/dm/fut/onbrd_verify_manager_hostname_resolved.sh @@ -0,0 +1,105 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + manager_addr=\$1 -- used as manager address - (string)(required) + target=\$2 -- used to check manager address resolved - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") ssl:ec2-54-200-0-59.us-west-2.compute.amazonaws.com:443 ssl:54.200.0.59:443 + /tmp/fut-base/shell/onbrd/$(basename "$0") ssl:54.200.0.59:443 ssl:54.200.0.59:443 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +manager_addr=$1 + +# Restart managers to start every config resolution from the begining +restart_managers + +# Give time to managers to bring up tables +sleep 30 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: Setting AWLAN_Node manager_addr to '$manager_addr'" +update_ovsdb_entry AWLAN_Node -u manager_addr "$manager_addr" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node table updated - manager_addr '$manager_addr'" || + raise "update_ovsdb_entry - Failed to update AWLAN_Node table - manager_addr '$manager_addr'" -l "$tc_name" -tc + +log "$tc_name: ONBRD Verify manager hostname resolved, waiting for Manager is_connected true" +wait_ovsdb_entry Manager -is is_connected true && + log "$tc_name: wait_ovsdb_entry - Manager is_connected is true" || + raise "wait_ovsdb_entry - Manager is_connected is NOT true" -l "$tc_name" -tc + +shift +targets=$@ + +# shellcheck disable=SC2034 +for i in $(seq 1 $#); do + + target=$1 + shift + + wait_ovsdb_entry Manager -is target "$target" && + { log "$tc_name: wait_ovsdb_entry - Manager target is '$target'"; pass; } || + log "$tc_name: wait_ovsdb_entry - Manager target is NOT '$target'" + +done + +die "onbrd/$(basename "$0"): wait_ovsdb_entry - Manager target NOT resolved" diff --git a/src/dm/fut/onbrd_verify_model_awlan_node.sh b/src/dm/fut/onbrd_verify_model_awlan_node.sh new file mode 100755 index 00000000..765a5d08 --- /dev/null +++ b/src/dm/fut/onbrd_verify_model_awlan_node.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$@ + +where options are: + -h show this help message + +where arguments are: + model=\$@ -- used as model to verify correct model entry - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") PP213X_EX +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +expected_model=$1 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify model, waiting for '$expected_model'" +wait_for_function_response 0 "check_ovsdb_entry AWLAN_Node -w model \"'$expected_model'\"" && + log "$tc_name: SUCCESS: check_model '$expected_model'" || + raise "FAIL: check_model '$expected_model'" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/onbrd_verify_number_of_radios.sh b/src/dm/fut/onbrd_verify_number_of_radios.sh new file mode 100755 index 00000000..12da0f26 --- /dev/null +++ b/src/dm/fut/onbrd_verify_number_of_radios.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$@ + +where options are: + -h show this help message + +where arguments are: + num_of_radios=\$@ -- used as number of radios to verify correct number of radios configured - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") 2 + /tmp/fut-base/shell/onbrd/$(basename "$0") 3 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +num_of_radios=$1 + +tc_name="onbrd/$(basename "$0")" +log "$tc_name: ONBRD Verify number of radios, waiting for '$num_of_radios'" + +wait_for_function_response 0 "check_number_of_radios $num_of_radios" && + log "$tc_name: SUCCESS: number of radios $num_of_radios" || + raise "FAIL: number of radios $num_of_radios" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/onbrd_verify_onbrd_vaps_on_radios.sh b/src/dm/fut/onbrd_verify_onbrd_vaps_on_radios.sh new file mode 100755 index 00000000..d2450608 --- /dev/null +++ b/src/dm/fut/onbrd_verify_onbrd_vaps_on_radios.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as interface name to check - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") onboard-ap-24 + /tmp/fut-base/shell/onbrd/$(basename "$0") onboard-ap-l50 + /tmp/fut-base/shell/onbrd/$(basename "$0") onboard-ap-u50 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +interface_name=$1 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify onboarding VAPs on all radios, check interface $interface_name" + +wait_for_function_response 0 "check_ovsdb_entry Wifi_VIF_State -w if_name $interface_name" && + log "$tc_name: SUCCESS: interface $interface_name exists" || + raise "FAIL: interface $interface_name does not exist" -l "$tc_name" -tc + +log "$tc_name: Clean created interfaces after test" +vif_clean + +pass diff --git a/src/dm/fut/onbrd_verify_redirector_address_awlan_node.sh b/src/dm/fut/onbrd_verify_redirector_address_awlan_node.sh new file mode 100755 index 00000000..890ec58b --- /dev/null +++ b/src/dm/fut/onbrd_verify_redirector_address_awlan_node.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +where arguments are: + redirector_address=\$1 -- used as FW version to verify running correct FW - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") ssl:wildfire.plume.tech:443 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +redirector_addr=$1 +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify redirector address, waiting for '$redirector_addr'" + +wait_ovsdb_entry AWLAN_Node -is redirector_addr "$redirector_addr" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node redirector_addr equal to '$redirector_addr'" || + raise "wait_ovsdb_entry - AWLAN_Node redirector_addr NOT equal to '$redirector_addr'" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/onbrd_verify_router_mode.sh b/src/dm/fut/onbrd_verify_router_mode.sh new file mode 100755 index 00000000..192cfa77 --- /dev/null +++ b/src/dm/fut/onbrd_verify_router_mode.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") br-wan br-home 10.10.10.20 10.10.10.50 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +br_wan=${1:-br-wan} +br_home=${2:-br-home} +start_pool=${3:-10.10.10.20} +end_pool=${4:-10.10.10.50} + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify router mode settings applied" + +# br-wan section +log "$tc_name: Check if interface is UP - $br_wan" +wait_for_function_response 0 "interface_is_up $br_wan" && + log "$tc_name: Interface is UP - $br_wan" || + raise "FAILED: Interface is DOWN, should be UP - $br_wan" -l "$tc_name" -tc + +# Check if DHCP client is running on br-wan (wan bridge) +wait_for_function_response 0 "check_pid_udhcp $br_wan" && + log "lib/unit_lib: check_pid_udhcp - PID found, DHCP client running" || + raise "nit_lib: check_pid_udhcp - PID not found, , DHCP client NOT running" -l "$tc_name" -tc + +log "$tc_name: Setting NAT to true" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$br_wan" -u NAT true && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - NAT true" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - - NAT true" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$br_wan" -is NAT true && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - NAT=true" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - NAT=true" -l "$tc_name" -tc + +# br-home section +log "$tc_name: Setting DHCP range on $br_home" +enable_disable_dhcp_server "$br_home" "$start_pool" "$end_pool" || + raise "Cannot update DHCP settings inside CONFIG $br_wan" -l "$tc_name" -tc + +log "$tc_name: Setting NAT to false" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$br_home" -u NAT false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - NAT false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - - NAT false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$br_home" -is NAT false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - NAT=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - NAT=false" -l "$tc_name" -tc + +update_ovsdb_entry Wifi_Inet_Config -w if_name "$br_home" -u ip_assign_scheme static && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=static" || + raise "update_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=static" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$br_home" -is ip_assign_scheme static && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=static" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=static" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$br_home" -is "dhcpc" "[\"map\",[]]" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - dhcpc [\"map\",[]]" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - dhcpc [\"map\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$br_home" -is "netmask" 0.0.0.0 && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - netmask 0.0.0.0" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - netmask 0.0.0.0" -l "$tc_name" -tc + +# Restart managers to tidy up config +restart_managers + +pass diff --git a/src/dm/fut/onbrd_verify_wan_ip_address.sh b/src/dm/fut/onbrd_verify_wan_ip_address.sh new file mode 100755 index 00000000..c52e729e --- /dev/null +++ b/src/dm/fut/onbrd_verify_wan_ip_address.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/onbrd_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 + +where options are: + -h show this help message + + wan_interface=\$1 -- used as interface name to check WAN IP for - (string)(required) + wan_ip=\$2 -- used as WAN IP address to be checked - (string)(required) + +this script is dependent on following: + - running DM manager + +example of usage: + /tmp/fut-base/shell/onbrd/$(basename "$0") br-wan 192.168.200.10 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +wan_interface=$1 +inet_addr=$2 + +tc_name="onbrd/$(basename "$0")" + +log "$tc_name: ONBRD Verify WAN IP address '$inet_addr' for interface '$wan_interface'" + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$wan_interface" -is inet_addr "$inet_addr" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_State '$wan_interface' inet_addr is equal to '$inet_addr'" || + raise "wait_ovsdb_entry - Wifi_Inet_State '$wan_interface' inet_addr is NOT equal to '$inet_addr'" -l "$tc_name" -tc + +wait_for_function_response 0 "verify_wan_ip_l2 $wan_interface $inet_addr" && + log "$tc_name: LEVEL2 WAN IP for '$wan_interface' is equal to '$inet_addr'" || + raise "LEVEL2 WAN IP for '$wan_interface' is NOT equal to '$inet_addr'" -l "$tc_name" -tc + +pass diff --git a/src/dm/fut/unit.mk b/src/dm/fut/unit.mk new file mode 100644 index 00000000..3b9d3b34 --- /dev/null +++ b/src/dm/fut/unit.mk @@ -0,0 +1,60 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_dm + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_DM),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/dm + +# DM specific FUTs +UNIT_FILE := dm_setup.sh +UNIT_FILE += dm_fetch_managers_startup.sh +# BRV specific FUTs +UNIT_FILE += brv_setup.sh +UNIT_FILE += brv_busybox_builtins.sh +UNIT_FILE += brv_is_tool_on_system.sh +UNIT_FILE += brv_ovs_correct_version.sh +# ONBRD specific FUTs +UNIT_FILE += onbrd_setup.sh +UNIT_FILE += onbrd_verify_bridge_mode.sh +UNIT_FILE += onbrd_verify_client_certificate_files.sh +UNIT_FILE += onbrd_verify_client_tls_connection.sh +UNIT_FILE += onbrd_verify_device_mode_awlan_node.sh +UNIT_FILE += onbrd_verify_dhcp_dry_run_success.sh +UNIT_FILE += onbrd_verify_dut_system_time_accuracy.sh +UNIT_FILE += onbrd_verify_fw_version_awlan_node.sh +UNIT_FILE += onbrd_verify_home_vaps_on_home_bridge.sh +UNIT_FILE += onbrd_verify_home_vaps_on_radios.sh +UNIT_FILE += onbrd_verify_id_awlan_node.sh +UNIT_FILE += onbrd_verify_manager_hostname_resolved.sh +UNIT_FILE += onbrd_verify_model_awlan_node.sh +UNIT_FILE += onbrd_verify_number_of_radios.sh +UNIT_FILE += onbrd_verify_onbrd_vaps_on_radios.sh +UNIT_FILE += onbrd_verify_redirector_address_awlan_node.sh +UNIT_FILE += onbrd_verify_router_mode.sh +UNIT_FILE += onbrd_verify_wan_ip_address.sh diff --git a/src/dm/src/dm_cli.c b/src/dm/src/dm_cli.c index 2467a219..712cf59f 100644 --- a/src/dm/src/dm_cli.c +++ b/src/dm/src/dm_cli.c @@ -24,12 +24,11 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define _GNU_SOURCE #include #include #include -#include "target.h" +#include "osp_unit.h" #include "dm.h" @@ -39,6 +38,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define DM_CLI_SHOW_INFO_MODEL "model" #define DM_CLI_SHOW_INFO_F_VERSION "firmware_version" #define DM_CLI_SHOW_INFO_P_VERSION "platform_version" +#define DM_CLI_SHOW_INFO_SKU_NUMBER "sku_number" +#define DM_CLI_SHOW_INFO_VENDOR_NAME "vendor_name" +#define DM_CLI_SHOW_INFO_VENDOR_PART "vendor_part" +#define DM_CLI_SHOW_INFO_MANUFACTURER "manufacturer" +#define DM_CLI_SHOW_INFO_FACTORY "factory" +#define DM_CLI_SHOW_INFO_MFG_DATE "manufacturer_date" static int dm_cli_show_info(char *opt) @@ -48,23 +53,47 @@ static int dm_cli_show_info(char *opt) if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_ID)) { - printf("id=%s\n", target_id_get(buf, buflen) ? buf : "?"); + printf(DM_CLI_SHOW_INFO_ID"=%s\n", osp_unit_id_get(buf, buflen) ? buf : "?"); } if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_SERIAL)) { - printf("serial_number=%s\n", target_serial_get(buf, buflen) ? buf : "?"); + printf(DM_CLI_SHOW_INFO_SERIAL"=%s\n", osp_unit_serial_get(buf, buflen) ? buf : "?"); } if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_MODEL)) { - printf("model=%s\n", target_model_get(buf, buflen) ? buf : "?"); + printf(DM_CLI_SHOW_INFO_MODEL"=%s\n", osp_unit_model_get(buf, buflen) ? buf : "?"); } if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_F_VERSION)) { - printf("firmware_version=%s\n", target_sw_version_get(buf, buflen) ? buf : "?"); + printf(DM_CLI_SHOW_INFO_F_VERSION"=%s\n", osp_unit_sw_version_get(buf, buflen) ? buf : "?"); } if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_P_VERSION)) { - printf("platform_version=%s\n", target_platform_version_get(buf, buflen) ? buf : "?"); + printf(DM_CLI_SHOW_INFO_P_VERSION"=%s\n", osp_unit_platform_version_get(buf, buflen) ? buf : "?"); + } + if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_SKU_NUMBER)) + { + printf(DM_CLI_SHOW_INFO_SKU_NUMBER"=%s\n", osp_unit_sku_get(buf, buflen) ? buf : "?"); + } + if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_VENDOR_NAME)) + { + printf(DM_CLI_SHOW_INFO_VENDOR_NAME"=%s\n", osp_unit_vendor_name_get(buf, buflen) ? buf : "?"); + } + if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_VENDOR_PART)) + { + printf(DM_CLI_SHOW_INFO_VENDOR_PART"=%s\n", osp_unit_vendor_part_get(buf, buflen) ? buf : "?"); + } + if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_MANUFACTURER)) + { + printf(DM_CLI_SHOW_INFO_MANUFACTURER"=%s\n", osp_unit_manufacturer_get(buf, buflen) ? buf : "?"); + } + if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_FACTORY)) + { + printf(DM_CLI_SHOW_INFO_FACTORY"=%s\n", osp_unit_factory_get(buf, buflen) ? buf : "?"); + } + if (!opt || !strcmp(opt, DM_CLI_SHOW_INFO_MFG_DATE)) + { + printf(DM_CLI_SHOW_INFO_MFG_DATE"=%s\n", osp_unit_mfg_date_get(buf, buflen) ? buf : "?"); } return DM_CLI_DONE; diff --git a/src/dm/src/dm_ovsdb.c b/src/dm/src/dm_ovsdb.c index d594b36d..4163c267 100644 --- a/src/dm/src/dm_ovsdb.c +++ b/src/dm/src/dm_ovsdb.c @@ -44,6 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "os_nif.h" #include "os_types.h" #include "target.h" +#include "osp_unit.h" #include "json_util.h" #include "build_version.h" @@ -288,76 +289,59 @@ bool act_check_id (void) } -void fill_entity_data(struct schema_AWLAN_Node * s_awlan_node) +static void fill_entity_data(struct schema_AWLAN_Node *s_awlan_node) { char buff[TARGET_BUFF_SZ]; - if (NULL == s_awlan_node) - { - return; - } memset(s_awlan_node, 0, sizeof(struct schema_AWLAN_Node)); - if (true == target_serial_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->serial_number, buff); - } - else - { - /* get some dummy value in this case */ - STRSCPY(s_awlan_node->serial_number,"1234567890"); - } - s_awlan_node->serial_number_exists = true; + /* serial */ + if (osp_unit_serial_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->serial_number, buff); - if (true == target_id_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->id, buff); - } - else - { - /* get some dummy value in this case */ - STRSCPY(s_awlan_node->id,"1234567890"); - } - s_awlan_node->id_exists = true; + /* id */ + if (osp_unit_id_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->id, buff); - if (true == target_sku_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->sku_number, buff); - s_awlan_node->sku_number_exists = true; - } + /* sku number */ + if (osp_unit_sku_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->sku_number, buff); - if (true == target_hw_revision_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->revision, buff); - } - else - { - STRSCPY(s_awlan_node->revision, "1"); - } + /* revision */ + if (osp_unit_hw_revision_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->revision, buff); - if (true == target_sw_version_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->firmware_version, buff); - } - else - { - STRSCPY(s_awlan_node->firmware_version, app_build_ver_get()); - } + /* firmware version */ + if (osp_unit_sw_version_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->firmware_version, buff); - if (true == target_platform_version_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->platform_version, buff); - } + /* platform version */ + if (osp_unit_platform_version_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->platform_version, buff); - if (true == target_model_get(buff, sizeof(buff))) - { - STRSCPY(s_awlan_node->model, buff); - } - else - { - STRSCPY(s_awlan_node->model, TARGET_NAME); - } - s_awlan_node->model_exists = true; + /* model */ + if (osp_unit_model_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->model, buff); + + /* vendor name */ + if (osp_unit_vendor_name_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->vendor_name, buff); + + /* vendor part number */ + if (osp_unit_vendor_part_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->vendor_part_number, buff); + + /* vendor manufacturer */ + if (osp_unit_manufacturer_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->vendor_manufacturer, buff); + + /* vendor factory */ + if (osp_unit_factory_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->vendor_factory, buff); + + /* vendor manufacturer date */ + if (osp_unit_mfg_date_get(buff, sizeof(buff)) == true) + SCHEMA_SET_STR(s_awlan_node->vendor_mfg_date, buff); LOG(NOTICE, "Device entity {serial=%s id=%s version=%s platform=%s sku=%s}", s_awlan_node->serial_number, @@ -422,6 +406,11 @@ bool act_update_entity (void) "sku_number", "upgrade_status", "upgrade_timer", + "vendor_name", + "vendor_part_number", + "vendor_manufacturer", + "vendor_factory", + "vendor_mfg_date", NULL) ); diff --git a/src/dm/src/dm_reboot.c b/src/dm/src/dm_reboot.c index e8fb17ec..122de059 100644 --- a/src/dm/src/dm_reboot.c +++ b/src/dm/src/dm_reboot.c @@ -34,7 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "module.h" #include "log.h" -#include "osp.h" +#include "osp_reboot.h" #include "osp_ps.h" #include "const.h" #include "util.h" diff --git a/src/fcm/inc/fcm.h b/src/fcm/inc/fcm.h index 115294a3..401743ea 100644 --- a/src/fcm/inc/fcm.h +++ b/src/fcm/inc/fcm.h @@ -56,6 +56,7 @@ typedef struct fcm_collect_plugin_ int sample_interval; int report_interval; void (*collect_periodic)(struct fcm_collect_plugin_ *); + void (*periodic)(struct fcm_collect_plugin_ *); void (*send_report)(struct fcm_collect_plugin_ *); void (*close_plugin)(struct fcm_collect_plugin_ *); char * (*get_mqtt_hdr_node_id)(void); diff --git a/src/fcm/inc/fcm_mgr.h b/src/fcm/inc/fcm_mgr.h index d3661f74..95062fe7 100644 --- a/src/fcm/inc/fcm_mgr.h +++ b/src/fcm/inc/fcm_mgr.h @@ -28,9 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define FCM_MGR_H_INCLUDED #include // libev routines +#include #include "ds_tree.h" #include "fcm.h" +#include "schema.h" typedef struct fcm_mgr_ { @@ -38,6 +40,10 @@ typedef struct fcm_mgr_ char *mqtt_headers[FCM_NUM_HEADER_IDS]; ds_tree_t collect_tree; // Holds fcm_collector_t ds_tree_t report_conf_tree; // Holds fcm_report_conf_t + ev_timer timer; // manager's event timer + time_t periodic_ts; // periodic timestamp + char pid[16]; // manager's pid + int64_t neigh_cache_ttl; // neighbour table cache ttl } fcm_mgr_t; bool fcm_init_mgr(struct ev_loop *loop); diff --git a/src/fcm/inc/fcm_priv.h b/src/fcm/inc/fcm_priv.h index 2ca3f43c..166c7a36 100644 --- a/src/fcm/inc/fcm_priv.h +++ b/src/fcm/inc/fcm_priv.h @@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef FCM_PRIV_H_INCLUDED #define FCM_PRIV_H_INCLUDED -#include "ds_list.h" +#include "ds_dlist.h" #include "ds_tree.h" #include "fcm.h" @@ -49,7 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define FCM_MQTT_TOPIC_LEN (257) #define FCM_OTHER_CONFIG_KEY_LEN (65) #define FCM_OTHER_CONFIG_VAL_LEN FCM_OTHER_CONFIG_KEY_LEN - +#define FCM_MGR_INTERVAL 120 typedef enum { FCM_NO_HEADER = -1, @@ -121,6 +121,21 @@ typedef struct fcm_collector_ ds_tree_node_t node; } fcm_collector_t; +/** + * @brief manager's memory usage counters + */ +struct mem_usage +{ + int curr_real_mem; + char curr_real_mem_unit[8]; + int peak_real_mem; + int curr_virt_mem; + char curr_virt_mem_unit[8]; + int peak_virt_mem; +}; + +void fcm_get_memory(struct mem_usage *mem); int fcm_ovsdb_init(void); +void fcm_event_init(void); #endif /* FCM_PRIV_H_INCLUDED */ diff --git a/src/fcm/src/fcm_event.c b/src/fcm/src/fcm_event.c new file mode 100644 index 00000000..e31e2c49 --- /dev/null +++ b/src/fcm/src/fcm_event.c @@ -0,0 +1,173 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fcm_priv.h" +#include "fcm_mgr.h" +#include "log.h" + +// Intervals and timeouts in seconds +#define FCM_MGR_INTERVAL 120 + + +/** + * @brief periodic routine. + */ +static void +fcm_event_cb(struct ev_loop *loop, ev_timer *watcher, int revents) +{ + fcm_collect_plugin_t *plugin; + fcm_collector_t *collector; + ds_tree_t *collectors; + struct mem_usage mem; + fcm_mgr_t *mgr; + time_t now; + + (void)loop; + (void)watcher; + (void)revents; + + mgr = fcm_get_mgr(); + + now = time(NULL); + mgr->periodic_ts = now; + + fcm_get_memory(&mem); + LOGI("%s: pid %s: mem usage: real mem: %u, virt mem %u", __func__, + mgr->pid, mem.curr_real_mem, mem.curr_virt_mem); + + collectors = &mgr->collect_tree; + collector = ds_tree_head(collectors); + while (collector != NULL) + { + plugin = &collector->plugin; + if (plugin->periodic != NULL) plugin->periodic(plugin); + collector = ds_tree_next(collectors, collector); + } +} + + +/** + * @brief periodic timer initialization + */ +void +fcm_event_init(void) +{ + fcm_mgr_t *mgr = fcm_get_mgr(); + + LOGI("Initializing FCM event"); + ev_timer_init(&mgr->timer, fcm_event_cb, + FCM_MGR_INTERVAL, FCM_MGR_INTERVAL); + mgr->timer.data = NULL; + mgr->periodic_ts = time(NULL); + ev_timer_start(mgr->loop, &mgr->timer); +} + + +/** + * @brief place holder + */ + +void fcm_event_close(void) {}; + + +/** + * @brief compute mem usage in kB + * + * @param file the source of system mem usage counters + * @param counter a mem usage counter + * @param the system mem usage unit for the counter + */ +void +fcm_mem_adjust_counter(FILE *file, int counter, char *unit) +{ + int rc; + + rc = strcmp(unit, "kB"); + if (rc != 0) + { + LOGE("%s: expected kB units, got %s", __func__, + unit); + return; + } +} + + +/** + * @brief gather process memory usage + * + * @param mem memory usage counters container + */ +void +fcm_get_memory(struct mem_usage *mem) +{ + fcm_mgr_t *mgr = fcm_get_mgr(); + char buffer[1024] = ""; + char fname[128]; + + mgr = fcm_get_mgr(); + + snprintf(fname, sizeof(fname), "/proc/%s/status", mgr->pid); + FILE* file = fopen(fname, "r"); + + if (file == NULL) return; + + memset(mem, 0, sizeof(*mem)); + + // read the entire file + while (fscanf(file, " %1023s", buffer) == 1) + { + if (strcmp(buffer, "VmRSS:") == 0) + { + fscanf(file, " %d %s", &mem->curr_real_mem, mem->curr_real_mem_unit); + fcm_mem_adjust_counter(file, mem->curr_real_mem, + mem->curr_real_mem_unit); + } + else if (strcmp(buffer, "VmHWM:") == 0) + { + fscanf(file, " %d", &mem->peak_real_mem); + } + else if (strcmp(buffer, "VmSize:") == 0) + { + fscanf(file, " %d %s", &mem->curr_virt_mem, mem->curr_virt_mem_unit); + fcm_mem_adjust_counter(file, mem->curr_virt_mem, + mem->curr_virt_mem_unit); + } + else if (strcmp(buffer, "VmPeak:") == 0) + { + fscanf(file, " %d", &mem->peak_virt_mem); + } + } + fclose(file); +} diff --git a/src/fcm/src/fcm_main.c b/src/fcm/src/fcm_main.c index f28b1f3f..38712dc3 100644 --- a/src/fcm/src/fcm_main.c +++ b/src/fcm/src/fcm_main.c @@ -94,6 +94,8 @@ int main(int argc, char ** argv) return -1; } + fcm_event_init(); + // Connect to OVSDB if (!ovsdb_init_loop(loop, "FCM")) { diff --git a/src/fcm/src/fcm_ovsdb.c b/src/fcm/src/fcm_ovsdb.c index 019ac2d8..786a40b0 100644 --- a/src/fcm/src/fcm_ovsdb.c +++ b/src/fcm/src/fcm_ovsdb.c @@ -24,11 +24,19 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include +#include +#include +#include + #include "ovsdb_update.h" #include "ovsdb_sync.h" #include "ovsdb_table.h" #include "schema.h" #include "log.h" +#include "os.h" #include "qm_conn.h" #include "dppline.h" #include "network_metadata.h" @@ -43,7 +51,6 @@ ovsdb_table_t table_AWLAN_Node; ovsdb_table_t table_FCM_Collector_Config; ovsdb_table_t table_FCM_Report_Config; - /** * fcm_get_awlan_header_id: maps key to header_id * @key: key @@ -174,6 +181,7 @@ void callback_FCM_Report_Config( } } + int fcm_ovsdb_init(void) { LOGD("Initializing FCM tables"); diff --git a/src/fcm/unit.mk b/src/fcm/unit.mk index ac588e93..1870727d 100644 --- a/src/fcm/unit.mk +++ b/src/fcm/unit.mk @@ -35,7 +35,7 @@ UNIT_TYPE := BIN UNIT_SRC := src/fcm_main.c UNIT_SRC += src/fcm_ovsdb.c UNIT_SRC += src/fcm_mgr.c - +UNIT_SRC += src/fcm_event.c UNIT_CFLAGS := -I$(UNIT_PATH)/inc diff --git a/src/fcm/ut/test_fcm_mgr.c b/src/fcm/ut/test_fcm_mgr.c index 036d69da..e0d4c1fa 100644 --- a/src/fcm/ut/test_fcm_mgr.c +++ b/src/fcm/ut/test_fcm_mgr.c @@ -71,6 +71,9 @@ static struct schema_FCM_Report_Config test_report[] = } }; +void setUp() {} +void tearDown() {} + void fcm_test_init(void) { struct ev_loop *loop = EV_DEFAULT; diff --git a/src/fsm/inc/fsm.h b/src/fsm/inc/fsm.h index 9855a26f..c94993dd 100644 --- a/src/fsm/inc/fsm.h +++ b/src/fsm/inc/fsm.h @@ -41,6 +41,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct fsm_session; +struct fsm_object +{ + char *object; + char *version; + int state; +}; + + /** * @brief session operations @@ -65,8 +73,21 @@ struct fsm_session_ops /* other_config parser. Provided to the plugin */ char * (*get_config)(struct fsm_session *, char *key); + + /* object update notification callback. provided by the plugin */ + void (*object_cb)(struct fsm_session *, struct fsm_object *, int); + + /* object state notification callback. provided to the plugin */ + void (*state_cb)(struct fsm_session *, struct fsm_object *); + + /* object version comparison. provided by the plugin */ + int (*version_cmp_cb)(char *, char *, char *); + + /* Get latest object version. Provided to the plugin */ + struct fsm_object * (*latest_obj_cb)(struct fsm_session *, char *, char *); }; + /** * @brief parser plugin specific operations * @@ -188,6 +209,16 @@ enum fsm_dpi_state FSM_DPI_DROP = 3, }; + +enum fsm_object_state +{ + FSM_OBJ_ACTIVE = 0, + FSM_OBJ_ERROR, + FSM_OBJ_OBSOLETE, + FSM_OBJ_LOAD_FAILED, +}; + + /** * @brief dpi dispatcher specifics */ @@ -262,6 +293,10 @@ struct fsm_session char bridge[64]; /* underlying bridge name */ char tx_intf[64]; /* plugin's TX interface */ union fsm_dpi_context *dpi; /* fsm dpi context */ + char *provider; + struct fsm_policy_client policy_client; + struct fsm_session *provider_plugin; + struct fsm_web_cat_ops *provider_ops; }; @@ -686,6 +721,7 @@ fsm_plugin_has_intf(struct fsm_session *session) void fsm_set_node_state(const char *module, const char *key, const char *value); + /** * @brief set a fsm policy provider * @@ -696,7 +732,17 @@ fsm_set_node_state(const char *module, const char *key, const char *value); void fsm_process_provider(struct fsm_session *session); + bool fsm_pcap_update(struct fsm_session *session); +/** + * @brief update the OMS_State table with the given object state + * + * @param session the fsm session triggering the call + * @param object the object advertizing its state + */ +void +fsm_set_object_state(struct fsm_session *session, struct fsm_object *object); + #endif /* FSM_H_INCLUDED */ diff --git a/src/fsm/inc/fsm_oms.h b/src/fsm/inc/fsm_oms.h new file mode 100644 index 00000000..7c01de63 --- /dev/null +++ b/src/fsm/inc/fsm_oms.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FSM_OMS_H_INCLUDED +#define FSM_OMS_H_INCLUDED + +#include "fsm.h" + +/** + * @brief notifies a plugin of available objects + * + * @param session the session to notify + */ +void +fsm_oms_notify_session(struct fsm_session *session); + + +/** + * @brief return the highest version of an object + * + * @param session the querying fsm session + * @param object the object name + * @param max_version the version cap, excluded + * @return the object with the highest version + * + * If @param max_version is provided, the return shall be lesser than it or NULL + * The caller is responsible for freeing the returned object + */ +struct fsm_object * +fsm_oms_get_highest_version(struct fsm_session *session, char *name, + char *max_version); + + +/** + * @brief initializes the oms library + */ +void +fsm_oms_init(void); + + +#endif /* FSM_OMS_H_INCLUDED */ diff --git a/src/fsm/src/fsm_dpi.c b/src/fsm/src/fsm_dpi.c index 6eb4c036..5604b486 100644 --- a/src/fsm/src/fsm_dpi.c +++ b/src/fsm/src/fsm_dpi.c @@ -333,7 +333,7 @@ fsm_dpi_add_plugin_to_dispatcher(struct fsm_session *session) if (dispatcher->type != FSM_DPI_DISPATCH) return false; if (dispatcher->dpi == NULL) return false; - LOGT("%s: adding dpi plugin %s to %s", + LOGI("%s: adding dpi plugin %s to %s", __func__, session->name, dispatcher->name); /* Add the dpi plugin to the dispatcher */ diff --git a/src/fsm/src/fsm_main.c b/src/fsm/src/fsm_main.c index bd16ac17..b4c7448b 100644 --- a/src/fsm/src/fsm_main.c +++ b/src/fsm/src/fsm_main.c @@ -49,6 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "json_util.h" #include "target.h" #include "fsm.h" +#include "fsm_oms.h" #include "nf_utils.h" #include "neigh_table.h" @@ -130,6 +131,9 @@ int main(int argc, char ** argv) LOGE("Eror initializing conntrack\n"); return -1; } + + fsm_oms_init(); + ev_run(loop, 0); target_close(TARGET_INIT_MGR_FSM, loop); diff --git a/src/fsm/src/fsm_oms.c b/src/fsm/src/fsm_oms.c new file mode 100644 index 00000000..aeb4f3cb --- /dev/null +++ b/src/fsm/src/fsm_oms.c @@ -0,0 +1,262 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "fsm.h" +#include "oms.h" +#include "ovsdb_update.h" + + +/** + * @brief: int object state id, state string record + */ +struct fsm_oms_state +{ + int fsm_oms_state_id; + char *fsm_oms_state_str; +}; + +/** + * @brief: object state id to state string mapping + */ +static struct fsm_oms_state +fsm_oms_states[] = +{ + { + .fsm_oms_state_id = FSM_OBJ_ACTIVE, + .fsm_oms_state_str = "active", + }, + { + .fsm_oms_state_id = FSM_OBJ_ERROR, + .fsm_oms_state_str = "error", + }, + { + .fsm_oms_state_id = FSM_OBJ_OBSOLETE, + .fsm_oms_state_str = "obsolete", + }, + { + .fsm_oms_state_id = FSM_OBJ_LOAD_FAILED, + .fsm_oms_state_str = "load-failed", + } +}; + + +/** + * @brief returns the object state as a string when provided that state id + * + * @param the state id + * @return the maching string if found, NULL otherwise + */ +static char * +fsm_state_id_to_str(int state_id) +{ + size_t len; + size_t i; + int id; + + len = sizeof(fsm_oms_states) / sizeof(fsm_oms_states[0]); + for (i = 0; i < len; i++) + { + id = fsm_oms_states[i].fsm_oms_state_id; + if (id == state_id) return fsm_oms_states[i].fsm_oms_state_str; + } + + return NULL; +} + + +/** + * @brief update the OMS_State table with the given object state + * + * @param session the fsm session triggering the call + * @param object the object advertizing its state + */ +void +fsm_set_object_state(struct fsm_session *session, struct fsm_object *object) +{ + struct oms_state_entry state; + + memset(&state, 0, sizeof(state)); + state.object = object->object; + state.version = object->version; + state.state = fsm_state_id_to_str(object->state); + oms_add_state_entry(&state); +} + + +/** + * @brief notify plugins of object updates + * + * @param entry the object getiing updated + * @param ovsdb_event the object update event + */ +static void +fsm_oms_notify_plugins(struct oms_config_entry *entry, int ovsdb_event) +{ + struct fsm_object fsm_object; + struct fsm_session *session; + ds_tree_t *sessions; + + memset(&fsm_object, 0, sizeof(fsm_object)); + fsm_object.object = entry->object; + fsm_object.version = entry->version; + sessions = fsm_get_sessions(); + + session = ds_tree_head(sessions); + while (session != NULL) + { + if (session->ops.object_cb) + { + session->ops.object_cb(session, &fsm_object, ovsdb_event); + } + session = ds_tree_next(sessions, session); + } +} + + +/** + * @brief callback to the oms library for object updates + * + * @param entry the object getiing updated + * @param ovsdb_event the object update event + */ +static void +fsm_oms_config_cb(struct oms_config_entry *entry, int ovsdb_event) +{ + switch(ovsdb_event) + { + case OVSDB_UPDATE_NEW: + LOGD("%s: new entry %s version %s", __func__, + entry->object, entry->version); + fsm_oms_notify_plugins(entry, ovsdb_event); + break; + + case OVSDB_UPDATE_DEL: + LOGD("%s: delete entry %s version %s", __func__, + entry->object, entry->version); + break; + + case OVSDB_UPDATE_MODIFY: + LOGD("%s: update entry %s version %s", __func__, + entry->object, entry->version); + break; + + default: + return; + } + + return; +} + +/** + * @brief notifies a plugin of available objects + * + * @param session the session to notify + */ +void +fsm_oms_notify_session(struct fsm_session *session) +{ + struct oms_config_entry *entry; + struct fsm_object fsm_object; + struct oms_mgr *mgr; + ds_tree_t *tree; + + if (session->ops.object_cb == NULL) return; + + memset(&fsm_object, 0, sizeof(fsm_object)); + mgr = oms_get_mgr(); + tree = &mgr->config; + entry = ds_tree_head(tree); + + while (entry != NULL) + { + + fsm_object.object = entry->object; + fsm_object.version = entry->version; + session->ops.object_cb(session, &fsm_object, OVSDB_UPDATE_NEW); + + entry = ds_tree_next(tree, entry); + } +} + + +/** + * @brief return the highest version of an object + * + * @param session the querying fsm session + * @param object the object name + * @param max_version the version cap, excluded + * @return the object with the highest version + * + * If @param max_version is provided, the return shall be lesser than it or NULL + * The caller is responsible for freeing the returned object + */ +struct fsm_object * +fsm_oms_get_highest_version(struct fsm_session *session, char *name, + char *max_version) +{ + struct oms_config_entry *entry; + struct fsm_object *object; + + entry = oms_get_highest_version(name, max_version, + session->ops.version_cmp_cb); + if (entry == NULL) return NULL; + + object = calloc(1, sizeof(*object)); + if (object == NULL) return NULL; + + object->object = name; + object->version = entry->version; + + return object; +} + + +static bool +fsm_oms_accept_id(const char *object_id) +{ + return true; +} + + +void +fsm_oms_init(void) +{ + struct oms_ovsdb_set oms_set; + + oms_init_manager(); + + memset(&oms_set, 0, sizeof(oms_set)); + oms_set.monitor_config = true; + oms_set.monitor_state = false; + oms_set.monitor_awlan = false; + oms_set.accept_id = fsm_oms_accept_id; + oms_set.config_cb = fsm_oms_config_cb; + oms_set.state_cb = NULL; + oms_set.report_cb = NULL; + + oms_ovsdb_init(&oms_set); + return; +} diff --git a/src/fsm/src/fsm_ovsdb.c b/src/fsm/src/fsm_ovsdb.c index 0e850a7f..9cc53b97 100644 --- a/src/fsm/src/fsm_ovsdb.c +++ b/src/fsm/src/fsm_ovsdb.c @@ -51,6 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "target.h" #include "target_common.h" #include "fsm.h" +#include "fsm_oms.h" #include "policy_tags.h" #include "qm_conn.h" #include "dppline.h" @@ -58,12 +59,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define MODULE_ID LOG_MODULE_ID_OVSDB -ovsdb_table_t table_AWLAN_Node; -ovsdb_table_t table_Flow_Service_Manager_Config; -ovsdb_table_t table_Openflow_Tag; -ovsdb_table_t table_Openflow_Tag_Group; -ovsdb_table_t table_Node_Config; -ovsdb_table_t table_Node_State; +static ovsdb_table_t table_AWLAN_Node; +static ovsdb_table_t table_Flow_Service_Manager_Config; +static ovsdb_table_t table_Openflow_Tag; +static ovsdb_table_t table_Openflow_Local_Tag; +static ovsdb_table_t table_Openflow_Tag_Group; +static ovsdb_table_t table_Node_Config; +static ovsdb_table_t table_Node_State; /** * This file manages the OVSDB updates for fsm. @@ -354,6 +356,80 @@ fsm_set_tx_intf(struct fsm_session *session) } +void +fsm_process_provider(struct fsm_session *session) +{ + struct fsm_session *service; + bool reset; + + if (session->type == FSM_WEB_CAT) return; + + /* If no provider plugin yet, attempt update */ + if (session->provider_plugin == NULL) + { + service = session->service; + session->provider_plugin = service; + if (service != NULL) + { + session->provider = strdup(service->name); + session->provider_ops = &service->p_ops->web_cat_ops; + } + return; + } + + LOGI("%s: original provider %s, new provider %s", __func__, + session->provider, session->service ? session->service->name : "none"); + + /* Provider was set, check if it changed */ + reset = (session->provider_plugin != session->service); + + if (reset) + { + sleep(2); + LOGEM("%s: provider change detected. Restarting", __func__); + exit(EXIT_SUCCESS); + } +} + + +void +fsm_update_client(struct fsm_session *session, + struct policy_table *table) +{ + struct fsm_policy_client *client; + + if (session == NULL) return; + + client = &session->policy_client; + client->table = table; + if (session->ops.update != NULL) session->ops.update(session); +} + + +void +fsm_update_client_table(struct fsm_session *session, char *table_name) +{ + struct policy_table *table; + int cmp; + + table = fsm_policy_find_table(table_name); + + /* Handle the case with no previous table set */ + if (session->policy_client.name == NULL) goto update; + + /* Handle the case with a table reset */ + if (table_name == NULL) goto update; + + /* No update */ + cmp = strcmp(session->policy_client.name, table_name); + if (cmp == 0) return; + +update: + session->policy_client.name = table_name; + fsm_update_client(session, table); +} + + /** * @brief update the ovsdb configuration of the session * @@ -368,6 +444,7 @@ fsm_session_update(struct fsm_session *session, struct fsm_session_conf *fconf; ds_tree_t *other_config; struct fsm_mgr *mgr; + char *policy_table; char *flood; bool check; bool ret; @@ -465,6 +542,10 @@ fsm_session_update(struct fsm_session *session, goto err_free_fconf; } + policy_table = fsm_get_other_config_val(session, "policy_table"); + fsm_update_client_table(session, policy_table); + + fsm_process_provider(session); fsm_set_tx_intf(session); ret = fsm_is_dpi(session); @@ -695,6 +776,8 @@ fsm_alloc_session(struct schema_Flow_Service_Manager_Config *conf) session->ops.send_report = fsm_send_report; session->ops.send_pb_report = fsm_send_pb_report; session->ops.get_config = fsm_get_other_config_val; + session->ops.state_cb = fsm_set_object_state; + session->ops.latest_obj_cb = fsm_oms_get_highest_version; pcaps = NULL; bpf = NULL; @@ -784,6 +867,9 @@ fsm_free_session(struct fsm_session *session) /* Free the session name */ free(session->name); + /* Free the session provider */ + free(session->provider); + /* Finally free the session */ free(session); } @@ -797,6 +883,7 @@ fsm_free_session(struct fsm_session *session) void fsm_add_session(struct schema_Flow_Service_Manager_Config *conf) { + struct fsm_policy_client *client; struct fsm_session *session; struct fsm_mgr *mgr; ds_tree_t *sessions; @@ -832,6 +919,11 @@ fsm_add_session(struct schema_Flow_Service_Manager_Config *conf) fsm_web_cat_service_update(session, FSM_SERVICE_ADD); } + client = &session->policy_client; + client->session = session; + client->update_client = fsm_update_client; + fsm_policy_register_client(&session->policy_client); + fsm_walk_sessions_tree(); return; @@ -865,6 +957,7 @@ fsm_delete_session(struct schema_Flow_Service_Manager_Config *conf) fsm_web_cat_service_update(session, FSM_SERVICE_DELETE); } + fsm_policy_deregister_client(&session->policy_client); ds_tree_remove(sessions, session); fsm_free_session(session); fsm_walk_sessions_tree(); @@ -895,7 +988,7 @@ fsm_modify_session(struct schema_Flow_Service_Manager_Config *conf) /** * @brief registered callback for OVSDB Flow_Service_Manager_Config events */ -void +static void callback_Flow_Service_Manager_Config(ovsdb_update_monitor_t *mon, struct schema_Flow_Service_Manager_Config *old_rec, struct schema_Flow_Service_Manager_Config *conf) @@ -1015,7 +1108,7 @@ fsm_rm_awlan_headers(void) /** * @brief registered callback for AWLAN_Node events */ -void +static void callback_AWLAN_Node(ovsdb_update_monitor_t *mon, struct schema_AWLAN_Node *old_rec, struct schema_AWLAN_Node *awlan) @@ -1026,10 +1119,33 @@ callback_AWLAN_Node(ovsdb_update_monitor_t *mon, } +/** + * @brief registered callback for Openflow_Local_Tag events + */ +static void +callback_Openflow_Local_Tag(ovsdb_update_monitor_t *mon, + struct schema_Openflow_Local_Tag *old_rec, + struct schema_Openflow_Local_Tag *tag) +{ + if (mon->mon_type == OVSDB_UPDATE_NEW) { + om_local_tag_add_from_schema(tag); + } + + if (mon->mon_type == OVSDB_UPDATE_DEL) { + om_local_tag_remove_from_schema(tag); + } + + if (mon->mon_type == OVSDB_UPDATE_MODIFY) { + om_local_tag_update_from_schema(tag); + } +} + + + /** * @brief registered callback for Openflow_Tag events */ -void +static void callback_Openflow_Tag(ovsdb_update_monitor_t *mon, struct schema_Openflow_Tag *old_rec, struct schema_Openflow_Tag *tag) @@ -1051,7 +1167,7 @@ callback_Openflow_Tag(ovsdb_update_monitor_t *mon, /** * @brief registered callback for Openflow_Tag_Group events */ -void +static void callback_Openflow_Tag_Group(ovsdb_update_monitor_t *mon, struct schema_Openflow_Tag_Group *old_rec, struct schema_Openflow_Tag_Group *tag) @@ -1193,7 +1309,7 @@ fsm_update_node_config(struct schema_Node_Config *node_cfg) /** * @brief registered callback for Node_Config events */ -void +static void callback_Node_Config(ovsdb_update_monitor_t *mon, struct schema_Node_Config *old_rec, struct schema_Node_Config *node_cfg) @@ -1229,6 +1345,7 @@ fsm_ovsdb_init(void) OVSDB_TABLE_INIT_NO_KEY(AWLAN_Node); OVSDB_TABLE_INIT_NO_KEY(Flow_Service_Manager_Config); OVSDB_TABLE_INIT_NO_KEY(Openflow_Tag); + OVSDB_TABLE_INIT_NO_KEY(Openflow_Local_Tag); OVSDB_TABLE_INIT_NO_KEY(Openflow_Tag_Group); OVSDB_TABLE_INIT_NO_KEY(Node_Config); OVSDB_TABLE_INIT_NO_KEY(Node_State); @@ -1237,6 +1354,7 @@ fsm_ovsdb_init(void) OVSDB_TABLE_MONITOR(AWLAN_Node, false); OVSDB_TABLE_MONITOR(Flow_Service_Manager_Config, false); OVSDB_TABLE_MONITOR(Openflow_Tag, false); + OVSDB_TABLE_MONITOR(Openflow_Local_Tag, false); OVSDB_TABLE_MONITOR(Openflow_Tag_Group, false); OVSDB_TABLE_MONITOR(Node_Config, false); @@ -1246,6 +1364,7 @@ fsm_ovsdb_init(void) mgr->flood_mod = fsm_trigger_flood_mod; mgr->get_br = get_home_bridge; mgr->set_dpi_state = fsm_set_dpi_state; + fsm_policy_init(); // Advertize default memory limit usage snprintf(str_value, sizeof(str_value), "%" PRIu64 " kB", mgr->max_mem); diff --git a/src/fsm/src/fsm_service.c b/src/fsm/src/fsm_service.c index ecdd3501..f0a09df7 100644 --- a/src/fsm/src/fsm_service.c +++ b/src/fsm/src/fsm_service.c @@ -258,14 +258,14 @@ fsm_get_web_cat_service(struct fsm_session *session) ds_tree_t *sessions; char *service_name; - if (session->type != FSM_PARSER) return true; + if (session->type == FSM_WEB_CAT) return true; sessions = fsm_get_sessions(); /* * If the parser plugin advertizes a provider_plugin, assume an ovsdb entry * dedicated to this provider. It might not be there yet. In this case, the - * parser seession will be updated later on. + * parser session will be updated later on. */ provider_plugin = session->ops.get_config(session, "provider_plugin"); if (provider_plugin != NULL) @@ -320,6 +320,8 @@ fsm_web_cat_service_update(struct fsm_session *session, int op) /* Set the service, call the parser update */ if (op == FSM_SERVICE_ADD) parser->service = session; if (op == FSM_SERVICE_DELETE) parser->service = NULL; + + fsm_process_provider(parser); if (parser->ops.update != NULL) parser->ops.update(parser); } } diff --git a/src/fsm/unit.mk b/src/fsm/unit.mk index 5cd4e8cf..37362822 100644 --- a/src/fsm/unit.mk +++ b/src/fsm/unit.mk @@ -38,9 +38,11 @@ UNIT_SRC += src/fsm_pcap.c UNIT_SRC += src/fsm_event.c UNIT_SRC += src/fsm_service.c UNIT_SRC += src/fsm_dpi.c +UNIT_SRC += src/fsm_oms.c UNIT_CFLAGS := -I$(UNIT_PATH)/inc UNIT_CFLAGS += -Isrc/lib/imc/inc +UNIT_CFLAGS += -Isrc/lib/oms/inc UNIT_LDFLAGS := -lev -ljansson -lpcap -lmnl @@ -64,4 +66,4 @@ UNIT_DEPS += src/lib/json_mqtt UNIT_DEPS += src/lib/network_telemetry UNIT_DEPS += src/lib/network_metadata UNIT_DEPS += src/lib/neigh_table - +UNIT_DEPS += src/lib/oms diff --git a/src/fsm/ut/test_fsm_core.c b/src/fsm/ut/test_fsm_core.c index f909acb7..a15f6a6a 100644 --- a/src/fsm/ut/test_fsm_core.c +++ b/src/fsm/ut/test_fsm_core.c @@ -98,7 +98,7 @@ void create_hex_dump(const char *fname, const uint8_t *buf, size_t len) */ struct schema_Flow_Service_Manager_Config g_confs[] = { - /* parser plugin, no type provided */ + /* parser plugin, no type provided, idx: 0 */ { .handler = "fsm_session_test_0", .plugin = "plugin_0", @@ -118,7 +118,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 3, }, - /* parser plugin, type provided */ + /* parser plugin, type provided, idx: 1 */ { .handler = "fsm_session_test_1", .plugin = "plugin_1", @@ -141,7 +141,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 4, }, - /* web categorization plugin */ + /* web categorization plugin, idx: 2 */ { .handler = "fsm_session_test_2", .plugin = "plugin_2", @@ -159,7 +159,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 2, }, - /* dpi plugin */ + /* dpi plugin, idx: 3 */ { .handler = "fsm_session_test_3", .plugin = "plugin_3", @@ -177,7 +177,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 2, }, - /* bogus plugin */ + /* bogus plugin, , idx: 4 */ { .handler = "fsm_bogus_plugin", .plugin = "bogus", @@ -185,6 +185,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 0, }, + /* idx: 5 */ { .handler = "fsm_session_test_5", .plugin = "plugin_5", @@ -206,7 +207,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 4, }, - /* dpi dispatch plugin */ + /* dpi dispatch plugin, idx: 6 */ { .handler = "fsm_session_test_6", .plugin = "plugin_6", @@ -222,7 +223,7 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 1, }, - /* dpi plugin */ + /* dpi plugin, idx: 7 */ { .handler = "fsm_session_test_7", .plugin = "plugin_7", @@ -242,6 +243,46 @@ struct schema_Flow_Service_Manager_Config g_confs[] = .other_config_len = 3, }, + /* parser plugin, type provided, idx: 8 */ + { + .handler = "fsm_session_test_8", + .plugin = "plugin_8", + .pkt_capt_filter = "bpf_filter_8", + .type = "parser", + .other_config_keys = + { + "mqtt_v", /* topic */ + "dso_init", /* plugin init routine */ + "provider_plugin", /* service provider */ + "policy_table", /* FSM policy entry */ + }, + .other_config = + { + "dev-test/fsm_core_ut/topic_8", /* topic */ + "test_dso_init", /* plugin init routine */ + "fsm_session_provider_plugin", /* service provider */ + "fsm_test_policy", /* FSM policy entry */ + }, + .other_config_len = 4, + }, + + /* web categorization plugin, idx: 9 */ + { + .handler = "fsm_session_provider_plugin", + .plugin = "plugin_9", + .type = "web_cat_provider", + .other_config_keys = + { + "mqtt_v", /* topic */ + "dso_init", /* plugin init routine */ + }, + .other_config = + { + "dev-test/fsm_core_ut/topic_2", /* topic */ + "test_dso_init", /* plugin init routine */ + }, + .other_config_len = 2, + }, }; /** @@ -278,6 +319,30 @@ struct schema_AWLAN_Node g_awlan_nodes[] = }; +struct schema_FSM_Policy g_spolicies[] = +{ + { /* entry 1. Always matching, action is set. */ + .policy_exists = true, + .policy = "fsm_test_policy", + .name = "block_facebook", + .idx = 1, + .mac_op_exists = false, + .fqdn_op_exists = true, + .fqdn_op = "in", + .fqdns_len = 1, + .fqdns = + { + "facebook", + }, + .fqdncat_op_exists = false, + .action_exists = true, + .action = "block", + .log_exists = true, + .log = "all", + } +}; + + const char *test_name = "fsm_core_tests"; struct fsm_mgr *g_mgr; @@ -337,6 +402,7 @@ test_send_report(struct net_md_aggregator *aggr, char *mqtt_topic) void setUp(void) { + struct fsm_policy_session *policy_mgr; size_t nelems; size_t i; @@ -356,6 +422,9 @@ setUp(void) } fsm_get_awlan_headers(&g_awlan_nodes[0]); + policy_mgr = fsm_policy_get_mgr(); + if (!policy_mgr->initialized) fsm_init_manager(); + return; } @@ -363,6 +432,30 @@ setUp(void) void tearDown(void) { + struct fsm_policy_session *policy_mgr = fsm_policy_get_mgr(); + struct policy_table *table, *t_to_remove; + struct fsm_policy *fpolicy, *p_to_remove; + ds_tree_t *tables_tree, *policies_tree; + + /* Clean up policies */ + tables_tree = &policy_mgr->policy_tables; + table = ds_tree_head(tables_tree); + while (table != NULL) + { + policies_tree = &table->policies; + fpolicy = ds_tree_head(policies_tree); + while (fpolicy != NULL) + { + p_to_remove = fpolicy; + fpolicy = ds_tree_next(policies_tree, fpolicy); + fsm_free_policy(p_to_remove); + } + t_to_remove = table; + table = ds_tree_next(tables_tree, table); + ds_tree_remove(tables_tree, t_to_remove); + free(t_to_remove); + } + fsm_reset_mgr(); g_mgr->init_plugin = NULL; @@ -1095,6 +1188,58 @@ test_5_dpi_dispatcher_and_plugin(void) } +/** + * @brief validates the sequence policy table/parser/web cat service + */ +void +test_6_service_plugin(void) +{ + struct schema_Flow_Service_Manager_Config *conf; + struct fsm_web_cat_ops *provider_ops; + struct fsm_session *web_cat_plugin; + struct fsm_session *parser_plugin; + struct schema_FSM_Policy *spolicy; + struct fsm_policy_client *client; + struct policy_table *table; + struct fsm_policy *fpolicy; + ds_tree_t *sessions; + + /* Add the parser plugin */ + conf = &g_confs[8]; + fsm_add_session(conf); + sessions = fsm_get_sessions(); + parser_plugin = ds_tree_find(sessions, conf->handler); + TEST_ASSERT_NOT_NULL(parser_plugin); + TEST_ASSERT_NULL(parser_plugin->service); + TEST_ASSERT_NULL(parser_plugin->provider_plugin); + + /* Add web cat plugin */ + conf = &g_confs[9]; + fsm_add_session(conf); + sessions = fsm_get_sessions(); + web_cat_plugin = ds_tree_find(sessions, conf->handler); + TEST_ASSERT_NOT_NULL(web_cat_plugin); + + /* Validate the service provider settings */ + TEST_ASSERT_NOT_NULL(parser_plugin->service); + TEST_ASSERT_TRUE(parser_plugin->service == web_cat_plugin); + TEST_ASSERT_NOT_NULL(parser_plugin->provider_plugin); + TEST_ASSERT_TRUE(parser_plugin->provider_plugin == web_cat_plugin); + provider_ops = &web_cat_plugin->p_ops->web_cat_ops; + TEST_ASSERT_TRUE(parser_plugin->provider_ops == provider_ops); + + /* Add policy */ + spolicy = &g_spolicies[0]; + fsm_add_policy(spolicy); + fpolicy = fsm_policy_lookup(spolicy); + TEST_ASSERT_NOT_NULL(fpolicy); + + client = &parser_plugin->policy_client; + table = fpolicy->table; + TEST_ASSERT_TRUE(client->table == table); +} + + int main(int argc, char *argv[]) { @@ -1123,6 +1268,7 @@ main(int argc, char *argv[]) RUN_TEST(test_3_dpi_dispatcher_and_plugin); RUN_TEST(test_4_dpi_dispatcher_and_plugin); RUN_TEST(test_5_dpi_dispatcher_and_plugin); + RUN_TEST(test_6_service_plugin); return UNITY_END(); } diff --git a/src/fsm/ut/unit.mk b/src/fsm/ut/unit.mk index 86c981b3..484b927c 100644 --- a/src/fsm/ut/unit.mk +++ b/src/fsm/ut/unit.mk @@ -34,6 +34,7 @@ UNIT_SRC += ../src/fsm_pcap.c UNIT_SRC += ../src/fsm_event.c UNIT_SRC += ../src/fsm_service.c UNIT_SRC += ../src/fsm_dpi.c +UNIT_SRC += ../src/fsm_oms.c UNIT_CFLAGS := -I$(UNIT_PATH)/../inc UNIT_CFLAGS += -Isrc/lib/imc/inc @@ -50,3 +51,4 @@ UNIT_DEPS += src/lib/unity UNIT_DEPS += src/lib/fsm_utils UNIT_DEPS += src/lib/fsm_policy UNIT_DEPS += src/lib/network_metadata +UNIT_DEPS += src/lib/oms diff --git a/src/fut/shell/config/default_shell.sh b/src/fut/shell/config/default_shell.sh new file mode 100755 index 00000000..204aae14 --- /dev/null +++ b/src/fut/shell/config/default_shell.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +if [ -z "$FUT_TOPDIR" ]; then + export FUT_TOPDIR="/tmp/fut-base" +fi + +if [ -z "$OPENSYNC_ROOTDIR" ]; then + export OPENSYNC_ROOTDIR="/usr/opensync" +fi + +if [ -z "$LOGREAD" ]; then + export LOGREAD="cat /var/log/messages" +fi + +if [ -z "$DEFAULT_WAIT_TIME" ]; then + export DEFAULT_WAIT_TIME=30 +fi + +if [ -z "$OVSH" ]; then + export OVSH="${OPENSYNC_ROOTDIR}/tools/ovsh --quiet --timeout=180000" +fi + +if [ -z "$OVSH_FAST" ]; then + export OVSH_FAST="${OPENSYNC_ROOTDIR}/tools/ovsh --quiet --timeout=10000" +fi + +if [ -z "$OVSH_SLOW" ]; then + export OVSH_SLOW="${OPENSYNC_ROOTDIR}/tools/ovsh --quiet --timeout=50000" +fi + +if [ -z "$LIB_OVERRIDE_FILE" ]; then + export LIB_OVERRIDE_FILE="/tmp/fut-base/shell/config/empty.sh" +fi + +if [ -z "$PATH" ]; then + export PATH="/bin:/sbin:/usr/bin:/usr/sbin:${OPENSYNC_ROOTDIR}/tools:${OPENSYNC_ROOTDIR}/bin" +fi diff --git a/src/fut/shell/config/empty.sh b/src/fut/shell/config/empty.sh new file mode 100755 index 00000000..db942ae4 --- /dev/null +++ b/src/fut/shell/config/empty.sh @@ -0,0 +1,26 @@ +#!/bin/sh -e + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/src/fut/shell/config/unit.mk b/src/fut/shell/config/unit.mk new file mode 100644 index 00000000..6329d584 --- /dev/null +++ b/src/fut/shell/config/unit.mk @@ -0,0 +1,35 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_config + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/config + +UNIT_FILE := default_shell.sh +UNIT_FILE += empty.sh diff --git a/src/fut/shell/lib/base_lib.sh b/src/fut/shell/lib/base_lib.sh new file mode 100755 index 00000000..d838dd5a --- /dev/null +++ b/src/fut/shell/lib/base_lib.sh @@ -0,0 +1,177 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# +# Base library of shared functions with minimal prerequisites: +# [ +# basename +# date +# echo +# printf +# + +raise() +{ + # The function has 5 parameters for the user to customize and 2 modes: + # Parameters: + # exception_msg: Message to be displayed in terminal + # exception_location: Where did the error happen + # exception_name: Error name to report to framework: + # "FunctionCall" + # "DeviceSetup" + # "OvsdbWait" + # "OvsdbException" + # "NativeFunction" + # "TestFailure" + # "InvalidOrMissingArgument" + # exception_type: Type of error to report to framework: ERROR|BROKEN + # exit_code: actual process exit code to return to calling function + # Modes: + # is_skip=true: propagate skip condition to framework (exit_code=3) + # is_skip=false: an error occurred + exception_msg=${1:-"Unknown error"} + shift 1 + exception_location=$(basename "$0") + exception_name="CommonShellException" + exception_type="BROKEN" + is_skip=false + exit_code=1 + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + # Use for generic failures + -f) + exception_type="FAIL" + ;; + # Use to define custom exit code + -ec) + exit_code=${1} + shift + ;; + # Use to propagate "skip" condition to framework + -s) + exit_code=3 + is_skip=true + ;; + # Customize location of error, instead of this library + -l) + exception_location=${1} + shift + ;; + # Use when error occurred during function call + -fc) + exception_name="FunctionCall" + ;; + # Use when error occurred during device setup + -ds) + exception_name="DeviceSetup" + exception_type="FAIL" + ;; + # Use when error occurred during ovsdb-wait + -ow) + exception_name="OvsdbWait" + exception_type="FAIL" + ;; + # Use when error occurred due to ovsdb issue + -oe) + exception_name="OvsdbException" + ;; + # Use when error occurred due to native function issue + -nf) + exception_name="NativeFunction" + exception_type="FAIL" + ;; + # Use for testcase failures + -tc) + exception_name="TestFailure" + exception_type="FAIL" + ;; + # Use when error occurred due to invalid or missing argument + -arg) + exception_name="InvalidOrMissingArgument" + ;; + esac + done + echo "$(date +%T) [ERROR] ${exception_location} - ${exception_msg}" + if [ "$is_skip" = 'false' ]; then + echo "FutShellException|FES|${exception_type}|FES|${exception_name}|FES|${exception_msg} AT ${exception_location}" + else + echo "${exception_msg} AT ${exception_location}" + fi + exit "$exit_code" +} + +die() +{ + log -deb "[DEPRECATED] - Function die() deprecated, use raise() instead!" + raise "$*" +} + +die_with_code() +{ + code=$1 + shift + log -deb "[DEPRECATED] - Function die_with_code() deprecated, use raise() instead!" + raise "$*" -ec "$code" +} + +pass() +{ + if [ $# -ge 1 ]; then + echo -e "\n$(date +%T) [SHELL] $*" + else + echo -e "\n$(date +%T) [SHELL] TEST PASSED" + fi + exit 0 +} + +log_title() +{ + c=${2:-"*"} + v=$(printf "%0.s$c" $(seq 1 $((${#1}+2)))) + echo -ne "${v}\n ${1} \n${v}\n" +} + +log() +{ + msg_type="[SHELL]" + exit_code=0 + if [ "$1" = "-deb" ]; then + msg_type="[DEBUG]" + shift + elif [ "$1" = "-err" ]; then + msg_type="[ERROR]" + exit_code=1 + shift + fi + + echo -e "$(date +%T) $msg_type $*" + + return $exit_code +} diff --git a/src/fut/shell/lib/brv_lib.sh b/src/fut/shell/lib/brv_lib.sh new file mode 100755 index 00000000..59733c81 --- /dev/null +++ b/src/fut/shell/lib/brv_lib.sh @@ -0,0 +1,124 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Library of functions for EPV test cases. Keep prerequisites to minimum +# Prerequisites: +# [ +# basename +# busybox +# command +# echo +# egrep +# getopts +# grep +# lib/base_lib.sh +# source +# which + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source ${FUT_TOPDIR}/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/base_lib.sh + +file_name="$(basename $0)" + +brv_setup_env() +{ + local fn_name="${file_name}:brv_setup_env" + log -deb "${fn_name} - Running BRV setup" + # There are currently no setup steps + return 0 +} + +_get_ovs_version() +{ + local fn_name="${file_name}:_get_ovs_version" + local OVS_NAME="ovs-vswitchd" + local OVS_CMD=$(command -v $OVS_NAME) + # try which if command utility is not available + [ -z ${OVS_CMD} ] && OVS_CMD=$(which $OVS_NAME) + [ -z ${OVS_CMD} ] && raise "Can not call ${OVS_NAME}" -l "${fn_name}" -nf + + OVS_ACTUAL_VER=$(${OVS_CMD} -V | cut -d' ' -f4) + ec=$? + [ ${ec} -ne 0 ] && raise "Error calling ${OVS_CMD}" -l "${fn_name}" -ec ${ec} -fc + [ -z ${OVS_ACTUAL_VER} ] && raise "Failed to get ovs version" -l "${fn_name}" -f + + echo "${OVS_ACTUAL_VER}" +} + +check_ovs_version() +{ + local fn_name="${file_name}:check_ovs_version" + log -deb "${fn_name} - Getting device ovs version" + local NARGS=1 + [ $# -ne ${NARGS} ] && raise "Requires ${NARGS} input arguments" -l "${fn_name}" -arg + + local OVS_EXPECTED_VER=$1 + OVS_ACTUAL_VER="$(_get_ovs_version)" + ec=$? + [ ${ec} -ne 0 ] && raise "Failed to get ovs version" -l "${fn_name}" -ec ${ec} -arg + + if [ "${OVS_ACTUAL_VER}" != "${OVS_EXPECTED_VER}" ]; then + raise "Failed to get ovs version" -l "${fn_name}" -arg + fi + return 0 +} + +is_tool_on_system() +{ + local fn_name="${file_name}:is_tool_on_system" + log -deb "${fn_name} - Checking tool presence on system" + local NARGS=1 + [ $# -ne ${NARGS} ] && raise "Requires ${NARGS} input arguments" -l "${fn_name}" -arg + + command -v $1 + rc=$? + # "command [-vV] command_name" builtin utility exit codes: + # 0: Successful completion. + # 126: The utility specified by command_name was found but could not be invoked. + # >0: The command_name could not be found or an error occurred. + if [ $rc -gt 0 -a $rc -ne 126 ]; then + which $1 + rc=$? + fi + return ${rc} +} + +is_busybox_builtin() +{ + local fn_name="${file_name}:is_busybox_builtin" + log -deb "${fn_name} - Checking if tool is built into busybox" + local NARGS=1 + [ $# -ne ${NARGS} ] && raise "Requires '${NARGS}' input arguments" -l "${fn_name}" -arg + + busybox --list | grep -wF $1 + return $? +} diff --git a/src/fut/shell/lib/cm2_lib.sh b/src/fut/shell/lib/cm2_lib.sh new file mode 100755 index 00000000..1c06c936 --- /dev/null +++ b/src/fut/shell/lib/cm2_lib.sh @@ -0,0 +1,242 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source ${FUT_TOPDIR}/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Connection Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ + +############################################ SETUP SECTION - START ##################################################### + +cm_setup_test_environment() +{ + cm2_if_name=${1:-eth0} + [ "$2" == "true" ] && cm2_wait_payload=true || cm2_wait_payload=false + [ "$3" == "gw" ] && cm2_is_gw=true || cm2_is_gw=false + fn_name="cm2_lib:cm_setup_test_environment" + + log -deb "$fn_name - Running CM2 setup" + + device_init || + raise "device_init" -l "$fn_name" -fc + cm_disable_fatal_state || + raise "cm_disable_fatal_state" -l "$fn_name" -fc + start_openswitch || + raise "start_openswitch" -l "$fn_name" -fc + manipulate_iptables_protocol unblock DNS || + raise "manipulate_iptables_protocol unblock DNS" -l "$fn_name" -fc + manipulate_iptables_protocol unblock SSL || + raise "manipulate_iptables_protocol unblock SSL" -l "$fn_name" -fc + + # This needs to execute before we start the managers. Flow is essential. + if [ "$cm2_is_gw" == "true" ]; then + add_bridge_interface br-wan "$cm2_if_name" || + raise "add_bridge_interface $cm2_if_name" -l "$fn_name" -fc + fi + + start_specific_manager cm -v || + raise "start_specific_manager cm" -l "$fn_name" -fc + start_specific_manager nm || + raise "start_specific_manager nm" -l "$fn_name" -fc + empty_ovsdb_table AW_Debug || + raise "empty_ovsdb_table AW_Debug" -l "$fn_name" -fc + set_manager_log CM TRACE || + raise "set_manager_log CM TRACE" -l "$fn_name" -fc + set_manager_log NM TRACE || + raise "set_manager_log NM TRACE" -l "$fn_name" -fc + + if [ "$cm2_is_gw" == "true" ]; then + wait_for_function_response 0 "check_default_route_gw" || + raise "Default GW not added to routes" -l "$fn_name" -ds + fi + + if [ "$cm2_wait_payload" == "true" ]; then + wait_ovsdb_entry AW_Bluetooth_Config -is payload 75:00:00:00:00:00 && + log -deb "$fn_name AW_Bluetooth_Config changed {payload:=75:00:00:00:00:00}" || + raise "AW_Bluetooth_Config - {payload:=75:00:00:00:00:00}" -l "$fn_name" -ow + fi + + return 0 +} + +cm2_teardown() +{ + fn_name="cm2_lib:cm2_teardown" + log -deb "$fn_name - Running CM2 teardown" + remove_bridge_interface br-wan && + log -deb "$fn_name - Success: remove_bridge_interface br-wan" || + log -deb "$fn_name - Failed remove_bridge_interface br-wan" + + log -deb "$fn_name - Killing CM pid" + cm_pids=$(pgrep "cm") + kill $cm_pids && + log -deb "$fn_name - CM pids killed" || + log -deb "$fn_name - Failed to kill CM pids" +} + +############################################ SETUP SECTION - STOP ##################################################### + +############################################ CLOUD SECTION - START ##################################################### + +wait_cloud_state() +{ + wait_for_cloud_state=$1 + fn_name="cm2_lib:wait_cloud_state" + log -deb "$fn_name - Waiting for cloud state $wait_for_cloud_state" + wait_for_function_response 0 "${OVSH} s Manager status -r | grep -q \"$wait_for_cloud_state\"" && + log -deb "$fn_name - Cloud state is $wait_for_cloud_state" || + raise "Manager - {status:=$wait_for_cloud_state}" -l "$fn_name" -ow + print_tables Manager +} + + +wait_cloud_state_not() +{ + wait_for_cloud_state_not=$1 + fn_name="cm2_lib:wait_cloud_state_not" + + log -deb "$fn_name - Waiting for cloud state not to be $wait_for_cloud_state_not" + wait_for_function_response 0 "${OVSH} s Manager status -r | grep -q \"$wait_for_cloud_state_not\"" && + raise "Manager - {status:=$wait_for_cloud_state_not}" -l "$fn_name" -ow || + log -deb "$fn_name - Cloud state is $wait_for_cloud_state_not" + + print_tables Manager +} + +############################################ CLOUD SECTION - STOP ###################################################### + +############################################ ROUTE SECTION - START ##################################################### + +check_default_route_gw() +{ + default_gw=$(route -n | tr -s ' ' | grep -i UG | awk '{printf $2}';) + if [ -z "$default_gw" ]; then + return 1 + else + return 0 + fi +} + +############################################ ROUTE SECTION - STOP ###################################################### + + +############################################ LINKS SECTION - START ##################################################### + +############################################ LINKS SECTION - STOP ###################################################### + + +############################################ TEST CASE SECTION - START ################################################# + +# Adds (inserts) or removes (deletes) rules to iptable. +# Supports DNS and SSL rules. +# Can block traffic by inserting rule (-I option) +# Can unblock traffic by deleting rule (-D option) +manipulate_iptables_protocol() +{ + option=$1 + traffic_type=$2 + fn_name="cm2_lib:manipulate_iptables_protocol" + + log -deb "$fn_name - $option $traffic_type traffic" + + if [ "$option" == "block" ]; then + iptable_option='I' + exit_code=0 + elif [ "$option" == "unblock" ]; then + iptable_option='D' + # Waiting for exit code 1 if multiple iptables rules are inserted - safer way + exit_code=1 + else + raise "option -> {given:$option, supported: block, unblock}" -l "$fn_name" -arg + fi + + if [ "$traffic_type" == "DNS" ]; then + traffic_port="53" + traffic_port_type="udp" + elif [ "$traffic_type" == "SSL" ]; then + traffic_port="443" + traffic_port_type="tcp" + else + raise "traffic_type -> {given:$option, supported: DNS, SSL}" -l "$fn_name" -arg + fi + + $(iptables -S | grep -q "OUTPUT -p $traffic_port_type -m $traffic_port_type --dport $traffic_port -j DROP") + # Add rule if not already an identical one in table, but unblock always + if [ "$?" -ne 0 ] || [ "$option" == "unblock" ]; then + wait_for_function_response $exit_code "iptables -$iptable_option OUTPUT -p $traffic_port_type --dport $traffic_port -j DROP" && + log -deb "$fn_name - $traffic_type traffic ${option}ed" || + raise "Failed to $option $traffic_type traffic" -l "$fn_name" -nf + else + log "lib/$fn_name - Add failure: Rule already in chain" + fi +} + +# Adds (inserts) or removes (deletes) rules to iptables for OUTPUT chain. +# Can block OUTPUT traffic by inserting rule (-I option) for provided source address +# Can unblock OUTPUT traffic by deleting rule (-D option) for provided source address +manipulate_iptables_address() +{ + option=$1 + address=$2 + fn_name="cm2_lib:manipulate_iptables_address" + + log -deb "$fn_name - $option $address internet" + + if [ "$option" == "block" ]; then + iptable_option='I' + exit_code=0 + elif [ "$option" == "unblock" ]; then + iptable_option='D' + # Waiting for exit code 1 if multiple iptables rules are inserted - safer way + exit_code=1 + else + raise "option -> {given:$option, supported: block, unblock}" -l "$fn_name" -arg + fi + + $(iptables -S | grep -q "OUTPUT -s $address -j DROP") + # Add rule if not already an identical one in table, but unblock always + if [ "$?" -ne 0 ] || [ "$option" == "unblock" ]; then + wait_for_function_response $exit_code "iptables -$iptable_option OUTPUT -s $address -j DROP" && + log -deb "$fn_name - internet ${option}ed" || + raise "Failed to $option internet" -l "$fn_name" -nf + else + log "lib/$fn_name - Add failure: Rule already in chain" + fi +} + +############################################ TEST CASE SECTION - STOP ################################################## diff --git a/src/fut/shell/lib/dm_lib.sh b/src/fut/shell/lib/dm_lib.sh new file mode 100755 index 00000000..f4d09702 --- /dev/null +++ b/src/fut/shell/lib/dm_lib.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source "${FUT_TOPDIR}/shell/config/default_shell.sh" +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Diagnostic Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ diff --git a/src/fut/shell/lib/ledm_lib.sh b/src/fut/shell/lib/ledm_lib.sh new file mode 100755 index 00000000..9fb7b093 --- /dev/null +++ b/src/fut/shell/lib/ledm_lib.sh @@ -0,0 +1,92 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source ${FUT_TOPDIR}/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common LED Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ + +test_ledm_led_config() +{ + fn_name="ledm_lib:test_ledm_led_config" + log -deb "$fn_name - Turning on WHITE LED" + led_config_ovsdb on || + raise "led_config_ovsdb on" -l "$fn_name" -fc + check_led_gpio_state on || + raise "check_led_gpio_state on" -l "$fn_name" -fc + sleep 1 + + log -deb "$fn_name - Turning LED off" + led_config_ovsdb off || + raise "led_config_ovsdb off" -l "$fn_name" -fc + check_led_gpio_state off || + raise "check_led_gpio_state off" -l "$fn_name" -fc + sleep 1 + + log -deb "$fn_name - LED mode blink" + led_config_ovsdb blink || + raise "led_config_ovsdb blink" -l "$fn_name" -fc + sleep 5 + + log -deb "$fn_name - LED mode breathe" + led_config_ovsdb breathe || + raise "led_config_ovsdb breathe" -l "$fn_name" -fc + sleep 5 + + log -deb "$fn_name - LED mode pattern" + led_config_ovsdb pattern || + raise "led_config_ovsdb pattern" -l "$fn_name" -fc + sleep 5 + + led_config_ovsdb off || + raise "led_config_ovsdb off" -l "$fn_name" -fc + check_led_gpio_state off || + raise "check_led_gpio_state off" -l "$fn_name" -fc +} + +led_config_ovsdb() +{ + log -deb "This device is not supported! Passing!" + return 0 +} + +check_led_gpio_state() +{ + log -deb "This device is not supported! Passing!" + return 0 +} diff --git a/src/fut/shell/lib/nm2_lib.sh b/src/fut/shell/lib/nm2_lib.sh new file mode 100755 index 00000000..0164f205 --- /dev/null +++ b/src/fut/shell/lib/nm2_lib.sh @@ -0,0 +1,535 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Network Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ + +nm_setup_test_environment() +{ + fn_name="nm2_lib:nm_setup_test_environment" + log -deb "$fn_name - Running NM2 setup" + + device_init || + raise "device_init" -l "$fn_name" -fc + + start_openswitch || + raise "start_openswitch" -l "$fn_name" -fc + + start_wireless_driver || + raise "start_wireless_driver" -l "$fn_name" -fc + + start_specific_manager wm || + raise "start_specific_manager wm" -l "$fn_name" -fc + + for if_name in "$@" + do + wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is if_name "$if_name" || + raise "Wifi_Radio_State - {if_name==$if_name}, {if_name:=$if_name}" -l "$fn_name" -ow + done + + start_specific_manager nm || + raise "start_specific_manager nm" -l "$fn_name" -fc + + empty_ovsdb_table AW_Debug || + raise "empty_ovsdb_table AW_Debug" -l "$fn_name" -fc + + set_manager_log WM TRACE || + raise "set_manager_log WM TRACE" -l "$fn_name" -fc + + set_manager_log NM TRACE || + raise "set_manager_log NM TRACE" -l "$fn_name" -fc + + log -deb "$fn_name - NM2 setup - end" +} + +create_inet_entry2() +{ + args="" + replace="func_arg" + fn_name="nm2_lib:create_inet_entry2" + while [ -n "$1" ]; do + option=${1} + shift + case "${option}" in + -if_name) + nm2_if_name="${1}" + args="${args} ${replace} ${option#?} ${1}" + shift + ;; + -enabled | \ + -network | \ + -if_type | \ + -inet_addr | \ + -netmask | \ + -dns | \ + -gateway | \ + -broadcast | \ + -ip_assign_scheme | \ + -mtu | \ + -NAT | \ + -upnp_mode | \ + -dhcpd | \ + -gre_ifname | \ + -gre_remote_inet_addr | \ + -gre_local_inet_addr) + args="${args} ${replace} ${option#?} ${1}" + shift + ;; + esac + done + + [ -z ${nm2_if_name} ] && raise "Interface name argument empty" -l "${fn_name}" -arg + check_ovsdb_entry Wifi_Inet_Config -w if_name "${nm2_if_name}" + if [ $? -eq 0 ]; then + log -deb "$fn_name - Updating existing inet interface" + function_to_call="update_ovsdb_entry" + function_arg="-u" + else + log -deb "$fn_name - Creating inet interface" + function_to_call="insert_ovsdb_entry" + function_arg="-i" + fi + + # Perform action insert/update + func_params=${args//$replace/$function_arg} + $function_to_call Wifi_Inet_Config -w if_name "$nm2_if_name" $func_params && + log -deb "$fn_name - Success $function_to_call Wifi_Inet_Config -w if_name $nm2_if_name $func_params" || + raise "Failure $function_to_call Wifi_Inet_Config -w if_name $nm2_if_name $func_params" -l "$fn_name" -oe + + # Validate action insert/update + func_params=${args//$replace/-is} + wait_ovsdb_entry Wifi_Inet_State -w if_name "$nm2_if_name" $func_params && + log -deb "$fn_name - Success wait_ovsdb_entry Wifi_Inet_State -w if_name $nm2_if_name $func_params" || + raise "Failure wait_ovsdb_entry Wifi_Inet_State -w if_name $nm2_if_name $func_params" -l "$fn_name" -ow +} + +create_inet_entry() +{ + args="" + nm2_if_name=false + replace="func_arg" + fn_name="nm2_lib:create_inet_entry" + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -if_name) + args="$args $replace if_name $1" + nm2_if_name=$1 + shift + ;; + -enabled) + args="$args $replace enabled $1" + shift + ;; + -network) + args="$args $replace network $1" + shift + ;; + -if_type) + args="$args $replace if_type $1" + shift + ;; + -inet_addr) + args="$args $replace inet_addr $1" + shift + ;; + -netmask) + args="$args $replace netmask $1" + shift + ;; + -dns) + args="$args $replace dns $1" + shift + ;; + -gateway) + args="$args $replace gateway $1" + shift + ;; + -broadcast) + args="$args $replace broadcast $1" + shift + ;; + -ip_assign_scheme) + args="$args $replace ip_assign_scheme $1" + shift + ;; + -mtu) + args="$args $replace mtu $1" + shift + ;; + -NAT) + args="$args $replace NAT $1" + shift + ;; + -upnp_mode) + args="$args $replace upnp_mode $1" + shift + ;; + -dhcpd) + args="$args $replace dhcpd $1" + shift + ;; + -gre_ifname) + args="$args $replace gre_ifname $1" + shift + ;; + -gre_remote_inet_addr) + args="$args $replace gre_remote_inet_addr $1" + shift + ;; + -gre_local_inet_addr) + args="$args $replace gre_local_inet_addr $1" + shift + ;; + esac + done + + log -deb "$fn_name - Creating Inet interface" + + function_to_call="insert_ovsdb_entry" + function_arg="-i" + + ${OVSH} s Wifi_Inet_Config -w if_name=="$nm2_if_name" && update=0 || update=1 + if [ "$update" -eq 0 ]; then + log -deb "$fn_name - Inet entry exists, updating instead" + function_to_call="update_ovsdb_entry" + function_arg="-u" + fi + + func_params=${args//$replace/$function_arg} + + $function_to_call Wifi_Inet_Config -w if_name "$nm2_if_name" $func_params && + log -deb "$fn_name - Success $function_to_call Wifi_Inet_Config -w if_name $nm2_if_name $func_params" || + raise "{Wifi_Inet_Config -> $function_to_call}" -l "$fn_name" -oe + + func_params=${args//$replace/-is} + + wait_ovsdb_entry Wifi_Inet_State -w if_name "$nm2_if_name" $func_params && + log -deb "$fn_name - Success wait_ovsdb_entry Wifi_Inet_State -w if_name $nm2_if_name $func_params" || + raise "Wifi_Inet_State" -l "$fn_name" -ow + + log -deb "$fn_name - Inet interface created" +} + +reset_inet_entry() +{ + nm2_if_name=$1 + fn_name="nm2_lib:reset_inet_entry" + log -deb "$fn_name - Setting Inet_Config for $nm2_if_name to default values" + + update_ovsdb_entry Wifi_Inet_Config -w if_name "$nm2_if_name" \ + -u NAT "false" \ + -u broadcast "[\"set\",[]]" \ + -u dhcpd "[\"map\",[]]" \ + -u dns "[\"map\",[]]" \ + -u enabled "true" \ + -u gateway "[\"set\",[]]" \ + -u gre_ifname "[\"set\",[]]" \ + -u gre_local_inet_addr "[\"set\",[]]" \ + -u gre_remote_inet_addr "[\"set\",[]]" \ + -u inet_addr "[\"set\",[]]" \ + -u ip_assign_scheme "none" \ + -u mtu "[\"set\",[]]" \ + -u netmask "[\"set\",[]]" \ + -u network "true" \ + -u parent_ifname "[\"set\",[]]" \ + -u softwds_mac_addr "[\"set\",[]]" \ + -u softwds_wrap "[\"set\",[]]" \ + -u upnp_mode "[\"set\",[]]" \ + -u vlan_id "[\"set\",[]]" && + log -deb "$fn_name - Wifi_Inet_Config updated" || + raise "Failed to update Wifi_Inet_Config" -l "$fn_name" -oe +} + +delete_inet_interface() +{ + nm2_if_name=$1 + fn_name="nm2_lib:delete_inet_interface" + + log -deb "$fn_name - Removing interface '$nm2_if_name'" + + remove_ovsdb_entry Wifi_Inet_Config -w if_name "$nm2_if_name" || + raise "{Wifi_Inet_Config -> remove}" -l "$fn_name" -oe + + wait_ovsdb_entry_remove Wifi_Inet_State -w if_name "$nm2_if_name" || + raise "{Wifi_Inet_State -> wait}" -l "$fn_name" -ow + + wait_for_function_response 1 "ip link show $nm2_if_name" && + log "$fn_name - LEVEL2: Interface $nm2_if_name removed" || + interface_force_purge_die $nm2_if_name + + log -deb "$fn_name - Interface '$nm2_if_name' deleted" +} + +interface_force_purge_die() +{ + nm2_if_name=$1 + fn_name="nm2_lib:interface_force_purge_die" + + log -deb "$fn_name - Interface force removal" + ip link delete "$nm2_if_name" || true + wait_for_function_response 1 "ip link show $nm2_if_name" && + raise "Interface removed $nm2_if_name forcefully" -l "$fn_name" -tc || + raise "Interface still present, couldn't delete interface $nm2_if_name" -l "$fn_name" -tc +} + +enable_disable_dhcp_server() +{ + nm2_if_name=$1 + nm2_start_pool=$2 + nm2_end_pool=$3 + fn_name="nm2_lib:enable_disable_dhcp_server" + + nm2_dhcpd='["start","'$nm2_start_pool'"],["stop","'$nm2_end_pool'"]' + + if [ -z $nm2_start_pool ] && [ -z $nm2_end_pool ]; then + nm2_dhcpd='' + fi + + log -deb "$fn_name - Creating DHCP on $nm2_if_name" + + update_ovsdb_entry Wifi_Inet_Config -w if_name "$nm2_if_name" \ + -u enabled true \ + -u network true \ + -u dhcpd '["map",['$nm2_dhcpd']]' || + raise "{Wifi_Inet_Config -> update}" -l "$fn_name" -oe + + wait_ovsdb_entry Wifi_Inet_State -w if_name "$nm2_if_name" \ + -is enabled true \ + -is network true \ + -is dhcpd '["map",['$nm2_dhcpd']]' || + raise "Wifi_Inet_State" -l "$fn_name" -ow + + log -deb "$fn_name - DHCP created on $nm2_if_name" +} + +enable_disable_custom_dns() +{ + nm2_if_name=$1 + nm2_primary_dns=$2 + nm2_secondary_dns=$3 + fn_name="nm2_lib:nm_setup_test_environment" + + nm2_dns='["map",[["primary","'$nm2_primary_dns'"],["secondary","'$nm2_secondary_dns'"]]]' + if [ -z $nm2_primary_dns ] && [ -z $nm2_secondary_dns ]; then + nm2_dns='' + fi + + log -deb "$fn_name - Creating DNS on $nm2_if_name" + + update_ovsdb_entry Wifi_Inet_Config -w if_name $nm2_if_name \ + -u enabled true \ + -u network true \ + -u ip_assign_scheme static \ + -u dns $nm2_dns || + raise "{Wifi_Inet_Config -> update}" -l "$fn_name" -oe + + wait_ovsdb_entry Wifi_Inet_State -w if_name $nm2_if_name \ + -is enabled true \ + -is network true \ + -is dns $nm2_dns || + raise "Wifi_Inet_State" -l "$fn_name" -ow + + log -deb "$fn_name - DNS created on $nm2_if_name" +} + +set_ip_forward() +{ + nm2_src_ifname=$1 + nm2_src_port=$2 + nm2_dst_ipaddr=$3 + nm2_dst_port=$4 + nm2_protocol=$5 + fn_name="nm2_lib:nm_setup_test_environment" + + log -deb "$fn_name - Creating port forward on $nm2_src_ifname" + + insert_ovsdb_entry IP_Port_Forward \ + -i dst_ipaddr "$nm2_dst_ipaddr" \ + -i dst_port "$nm2_dst_port" \ + -i src_port "$nm2_src_port" \ + -i protocol "$nm2_protocol" \ + -i src_ifname "$nm2_src_ifname" || + raise "{IP_Port_Forward -> insert}" -l "$fn_name" -oe + + log -deb "$fn_name - Port forward created on $nm2_src_ifname" +} + +force_delete_ip_port_forward_die() +{ + nm2_if_name=$1 + nm2_ip_table_type=$2 + nm2_ip_port_forward_ip=$3 + nm2_port_forward_line_number=$(iptables -t nat --list -v --line-number | tr -s ' ' | grep $nm2_ip_table_type | grep $nm2_if_name | grep $nm2_ip_port_forward_ip | cut -d ' ' -f1) + fn_name="nm2_lib:force_delete_ip_port_forward_die" + + log -deb "$fn_name - iptables not empty. Force delete" + + if [ -z "$nm2_port_forward_line_number" ]; then + log -deb "$fn_name - Couldn't get iptable line number, skipping..." + return 0 + fi + + wait_for_function_response 0 "iptables -t nat -D $nm2_ip_table_type $nm2_port_forward_line_number" && + raise "Ip port forward forcefully removed from iptables" -l "$fn_name" -tc || + raise "Failed to remove ip port forward from iptables" -l "$fn_name" -tc +} + +check_upnp_conf() +{ + nm2_internal_if=$1 + nm2_external_if=$2 + fn_name="nm2_lib:check_upnp_conf" + + log "$fn_name - LEVEL 2 - Checking if '$nm2_internal_if' set as internal interface" + $(cat /var/miniupnpd/miniupnpd.conf | grep -q "listening_ip=$nm2_internal_if") + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - UPnP configuration VALID for internal interface" + else + raise "UPnP configuration NOT VALID for internal interface" -l "$fn_name" -tc + fi + + log -deb "$fn_name - LEVEL 2 - Checking if '$nm2_external_if' set as external interface" + $(cat /var/miniupnpd/miniupnpd.conf | grep -q "ext_ifname=$nm2_external_if") + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - UPnP configuration VALID for external interface" + else + raise "UPnP configuration NOT VALID for external interface" -l "$fn_name" -tc + fi + + return 0 +} + +interface_nat_enabled() +{ + iptables -t nat --list -v | tr -s ' ' / | grep '/MASQUERADE/' | grep -q "$1" +} + +ip_port_forward() +{ + iptables -t nat --list -v | tr -s ' ' / | grep '/DNAT/' | grep -q "$1" +} + +interface_broadcast() +{ + ifconfig "$1" | tr -s ' :' '@' | grep -e '^@inet@' | cut -d '@' -f 6 +} + +interface_netmask() +{ + ifconfig "$1" | tr -s ' :' '@' | grep -e '^@inet@' | cut -d '@' -f 8 +} + +interface_mtu() +{ + ifconfig "$1" | tr -s ' ' | grep "MTU" | cut -d ":" -f2 | awk '{print $1}' +} + +wait_for_dnsmasq() +{ + if_name=$1 + start_pool=$2 + end_pool=$3 + + $(grep -q "dhcp-range=$if_name,$start_pool,$end_pool" /var/etc/dnsmasq.conf) || $(return 1) + + return $? +} + +check_resolv_conf() +{ + nm2_primary_dns=$1 + + $(cat /tmp/resolv.conf | grep -q "nameserver $nm2_primary_dns") || $(return 1) + + return $? +} + +# Check if interface exists on system +check_interface_exists() +{ + fn_name="nm2_lib:check_interface_exists" + log -deb "[DEPRECATED] - Function ${fn_name} deprecated in favor of check_interface_exists2" + if_name=$1 + + log "lib/nm2_lib: check_interface_exists - LEVEL 2 - Checking if interface '$if_name' exists on system" + + $(ifconfig | grep $if_name) + if [ "$?" -eq 0 ]; then + log -deb "lib/nm2_lib: check_interface_exists - interface '$if_name' exists on system." + return 0 + else + log "lib/nm2_lib: check_interface_exists - interface '$if_name' does NOT exist on system." + return 1 + fi +} + +check_interface_exists2() +{ + local fn_name="nm2_lib:check_interface_exists2" + local if_name=$1 + + log -deb "${fn_name} - Checking if interface ${if_name} exists on system" + $(ifconfig | grep -qwE $if_name) + if [ "$?" -eq 0 ]; then + log -deb "${fn_name} - interface ${if_name} exists on system" + return 0 + else + log -deb "${fn_name} - interface ${if_name} does NOT exist on system" + return 1 + fi +} + +# Check if manager is running by checking if its PID exists +# Return 0 if exists +# Return 1 if does not exist +check_manager_alive() +{ + manager_pid_file=$1 + pid_of_manager=$(get_pid "$manager_pid_file") + if [ -z "$pid_of_manager" ]; then + log "nm2/$(basename "$0"): $manager_pid_file PID NOT found" + return 1 + else + log "nm2/$(basename "$0"): $manager_pid_file PID found" + return 0 + fi +} diff --git a/src/fut/shell/lib/onbrd_lib.sh b/src/fut/shell/lib/onbrd_lib.sh new file mode 100755 index 00000000..4bfd9f95 --- /dev/null +++ b/src/fut/shell/lib/onbrd_lib.sh @@ -0,0 +1,215 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source "${FUT_TOPDIR}/shell/config/default_shell.sh" +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common On-boarding functions +# +############################################ INFORMATION SECTION - STOP ################################################ + +############################################ SETUP SECTION - START ##################################################### + +onbrd_setup_test_environment() +{ + fn_name="onbrd_lib:onbrd_setup_test_environment" + log -deb "$fn_name - Running ONBRD setup" + + device_init || + raise "device_init" -l "$fn_name" -fc + + cm_disable_fatal_state || + raise "cm_disable_fatal_state" -l "$fn_name" -fc + + start_openswitch || + raise "start_openswitch" -l "$fn_name" -fc + + restart_managers + log "${fn_name}: Executed restart_managers, exit code: $?" + + # Check if all radio interfaces are created + for if_name in "$@" + do + wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is if_name "$if_name" || + raise "Wifi_Radio_State" -l "$fn_name" -ow + done + + return 0 +} + +############################################ SETUP SECTION - STOP ###################################################### + +############################################ TEST CASE SECTION - START ################################################# + +# Returns number of radios in Wifi_Radio_State +# if_name must be unique for each radio interface +get_number_of_radios() +{ + num=$(${OVSH} s Wifi_Radio_State if_name -r | wc -l) + echo "$num" +} + + +# Checks if number of radios is the same as in provided parameter. +# Returns 0 if equal +# Returns 1 if not equal +# Usage example(s): +# check_number_of_radios 2 +# check_number_of_radios 3 +check_number_of_radios() +{ + fn_name="onbrd_lib:check_number_of_radios" + num_of_radios_1=$1 + num_of_radios_2=$(get_number_of_radios) + + log -deb "$fn_name - number of radios is $num_of_radios_2" + + if [ "$num_of_radios_1" = "$num_of_radios_2" ]; then + return 0 + else + return 1 + fi +} + +# Function checks if LEVEL2 inet_addr is the same as in test case config. +# Returns 0 if equal. +verify_wan_ip_l2() +{ + fn_name="onbrd_lib:verify_wan_ip_l2" + br_wan=$1 + + # LEVEL2 + inet_addr=$(ifconfig "$br_wan" | grep 'inet addr' | awk '/t addr:/{gsub(/.*:/,"",$2); print $2}') + + if [ -z "$inet_addr" ]; then + log -deb "$fn_name - inet_addr is empty string" + return 1 + fi + + if [ "$2" = "$inet_addr" ]; then + log -deb "$fn_name - SUCCESS: OVSDB inet_addr '$2' equals LEVEL2 inet_addr '$inet_addr'" + return 0 + else + log -deb "$fn_name - FAIL: OVSDB inet_addr '$2' not equal to LEVEL2 inet_addr '$inet_addr'" + fi +} + + +create_patch_interface() +{ + fn_name="onbrd_lib:create_patch_interface" + + num1=$(ovs-vsctl show | grep "$2" | grep Interface | awk '{print $2}' | wc -l) + if [ "$num1" -gt 0 ]; then + # Add WAN-to-HOME patch port + log -deb "$fn_name - '$2' patch exists" + else + # Add WAN-to-HOME patch port + log -deb "$fn_name - adding '$2' to patch port" + add_bridge_port "$1" "$2" + set_interface_patch "$1" "$2" "$3" + fi + + num2=$(ovs-vsctl show | grep "$3" | grep Interface | awk '{print $2}' | wc -l) + if [ "$num2" -gt 0 ]; then + # Add WAN-to-HOME patch port + log -deb "$fn_name - '$3' patch exists" + else + # Add WAN-to-HOME patch port + log -deb "$fn_name - adding $3 to patch port" + add_bridge_port "$1" "$3" + set_interface_patch "$1" "$3" "$2" + fi + + ovs-vsctl show +} + + +check_if_patch_exists() +{ + fn_name="onbrd_lib:check_if_patch_exists" + + num=$(ovs-vsctl show | grep "$1" | grep Interface | awk '{print $2}' | wc -l) + if [ "$num" -gt 0 ]; then + log -deb "$fn_name - '$1' interface exists" + return 0 + else + log -deb "$fn_name - '$1' interface does NOT exist" + return 1 + fi +} + +# Checks if target equals any resolution +# takes variable number of arguments, provide at least 1 +# Return 0 if resolution equals target +# Return 1 if no resolution equals target +onbrd_check_hostname_resolved() +{ + fn_name="onbrd_lib:onbrd_check_hostname_resolved" + + target=$(get_ovsdb_entry_value Manager target -r) + + for resolution in $@ + do + if [ "$target" = "$resolution" ]; then + log -deb "$fn_name - target '$target' equals resolution '$resolution'" + return 0 + else + log -deb "fn_name - target '$target' NOT equal to resolution '$resolution'" + fi + done + + return 1 +} + +onbrd_check_fw_pattern_match() +{ + fn_name="onbrd_lib:onbrd_check_fw_pattern_match" + + fw=$(get_ovsdb_entry_value AWLAN_Node firmware_version -r) + + echo "$fw" | grep -q ^[0-9][.][0-9] + + if [ "$?" = "0" ]; then + log -deb "$fn_name - Pattern match" + return 0 + else + log -deb "$fn_name - Pattern didn't match" + return 1 + fi +} + +############################################ TEST CASE SECTION - STOP ################################################## diff --git a/src/fut/shell/lib/qm_lib.sh b/src/fut/shell/lib/qm_lib.sh new file mode 100755 index 00000000..b86c1042 --- /dev/null +++ b/src/fut/shell/lib/qm_lib.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source "${FUT_TOPDIR}/shell/config/default_shell.sh" +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Queue Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ diff --git a/src/fut/shell/lib/rpi_lib.sh b/src/fut/shell/lib/rpi_lib.sh new file mode 100755 index 00000000..895cf526 --- /dev/null +++ b/src/fut/shell/lib/rpi_lib.sh @@ -0,0 +1,400 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +lib_dir=$(dirname "$(realpath "$BASH_SOURCE")") +FUT_TOPDIR="$(realpath "$lib_dir"/../..)" + +source "$lib_dir/unit_lib.sh" + +file_name="$(basename "$0")" + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common OpenSync functions used globally +# +############################################ INFORMATION SECTION - STOP ################################################ + +# RPI server "iptables" defaults to "xtables-nft-multi" +iptables_cmd="iptables-legacy" +iptables_chain="FORWARD" + +############################################ UTILITY SECTION - START ################################################### + +dpkg_is_package_installed() +{ + package=$1 + dpkg -l | grep -w ${package} | egrep -q ^ii + return $? +} + +start_cloud_simulation() +{ + local fn_name="${file_name}:brv_setup_env" + log "Check if haproxy package is installed" + dpkg_is_package_installed "haproxy" || + raise "haproxy not installed" -l "$fn_name" -ds + + sudo mkdir -p /etc/haproxy/certs/ + + log "Copy haproxy configuration file and certificates" + sudo cp "${FUT_TOPDIR}/shell/tools/rpi/files"/haproxy.cfg /etc/haproxy/haproxy.cfg || + raise "Config file not present!" -l "$fn_name" -ds + sudo cp "${FUT_TOPDIR}/shell/tools/rpi/files"/{fut_controller.pem,plume_ca_chain.pem} /etc/haproxy/certs/ || + raise "Certificates not present!" -l "$fn_name" -ds + + log "Restart haproxy service" + sudo service haproxy restart || + raise "haproxy not started" -l "$fn_name" -ds + log "haproxy service running" + + log "Starting Cloud listener - logging path /tmp/cloud_listener.log" + "${FUT_TOPDIR}"/framework/tools/cloud_listener.py -v > /dev/null 2>&1 & + log "Cloud listener started" && exit 0 +} + +stop_cloud_simulation() +{ + log "Stop haproxy service" + sudo service haproxy stop + sudo systemctl is-active --quiet haproxy && die "haproxy not stopped" + log "haproxy service stopped" + log "Stop Cloud listener" + kill $(pgrep cloud_listener) > /dev/null 2>&1 & + log "Cloud listener stopped" +} + +############################################ UTILITY SECTION - STOP #################################################### + + +############################################ NETWORK SECTION - START ################################################### + +network_connect_to_wpa2() +{ + interface=$1 + network_ssid=$2 + network_bssid=$3 + network_pass=$4 + network_key_mgmt=$5 + enable_dhcp=$6 + msg_prefix=${7:-"network_connect_to_wpa2 -"} + network_bssid_upper=$(echo "$network_bssid" | tr a-z A-Z) + + if [[ "$EUID" -ne 0 ]]; then + die "$msg_prefix Please run this function as root - sudo" + fi + + if [[ -z "$network_ssid" ]]; then + die "$msg_prefix Empty network_ssid" + elif [[ -z "$network_pass" ]]; then + die "$msg_prefix Empty network_pass" + fi + + log "$msg_prefix Bringing $interface down" + ifdown $interface + + if [ "$?" -ne 0 ]; then + die "$msg_prefix Failed while bringing interface $interface down" + fi + + sleep 3 + + rm /etc/wpa_supplicant/wpa_supplicant.conf + touch /etc/wpa_supplicant/wpa_supplicant.conf + + log "$msg_prefix Creating wpa_supplicant.conf file" + + echo 'ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev' >> /etc/wpa_supplicant/wpa_supplicant.conf + echo 'update_config=1' >> /etc/wpa_supplicant/wpa_supplicant.conf + + echo " +network={ + ssid=\"$network_ssid\" + proto=RSN + key_mgmt=$network_key_mgmt + scan_ssid=1 + psk=\"$network_pass\" + priority=1 + bssid=$network_bssid +}" >> /etc/wpa_supplicant/wpa_supplicant.conf + + log "$msg_prefix wpa_supplicant.conf file:" + + cat /etc/wpa_supplicant/wpa_supplicant.conf + + log "$msg_prefix Bringing $interface up" + + if [[ "$enable_dhcp" == "on" ]]; then + log "Using DHCP" + ifup $interface + else + log "Not using dhcp - killing dhclient after 10 seconds - workaround... " + timeout 10 ifup $interface + kill $(pidof dhclient) + fi + + log "$msg_prefix Checking if connected to network - $network_ssid" + + ssid_connected=$(iwconfig $interface | grep "$network_ssid") + + if [ $? -ne 0 ]; then + iwconfig && die "$msg_prefix Interface $interface not connected to $network_ssid" + fi + + bssid_connected=$(iwconfig $interface | grep "$network_bssid_upper") + + if [[ $? -ne 0 ]]; then + iwconfig && die "$msg_prefix Interface $interface not connected to $network_bssid_upper" + fi + + pass "$msg_prefix Interface $interface is connected to the network $network_ssid" +} + +############################################ NETWORK SECTION - STOP #################################################### + +########################################## FW IMAGE SECTION - START #################################################### + +um_create_fw_key_file() +{ + um_fw_path=$1 + um_fw_key=$2 + + log "Creating fw key $um_fw_key at $um_fw_path" + echo "$um_fw_key" > "$um_fw_path.key" && + log "Created $um_fw_path.key" || + die "Failed to create $um_fw_path.key" +} + +um_encrypt_image() +{ + um_fw_unc_path=$1 + um_fw_key_path=$2 + um_fw_name=${um_fw_unc_path##*/} + um_fw_pure_name=${um_fw_name//".img"/""} + um_file_cd_path=${um_fw_unc_path//"$um_fw_name"/""} + um_fw_enc_path="$um_file_cd_path/${um_fw_pure_name}.eim" + + [ -f "$um_fw_enc_path" ] && rm "$um_fw_enc_path" + + log "Encypring image $um_fw_path with key $um_fw_key_path" + openssl enc -aes-256-cbc -pass pass:"$(cat "$um_fw_key_path")" -md sha256 -nosalt -in "$um_fw_unc_path" -out "$um_fw_enc_path" && + log "Image encrypted" || + die "Faield to encrypt image" +} + +um_create_md5_file() +{ + um_file_path=$1 + um_fw_name=${um_file_path##*/} + um_file_cd_path=${um_file_path//"$um_fw_name"/""} + + log "Creating md5 sum file of file $um_file_path" + cd "$um_file_cd_path" && md5sum "$um_fw_name" > "$um_fw_name.md5" && + log "md5 sum file created" || + die "Failed to create md5 sum file" +} + +um_create_corrupt_md5_file() +{ + um_fw_path=$1 + um_fw_name=${um_fw_path##*/} + um_file_cd_path=${um_file_path//"$um_fw_name"/""} + um_md5_name="$um_file_cd_path/${um_fw_name}.md5" + um_hash_only="$(cd "$um_file_cd_path" && md5sum "$um_fw_name" | cut -d' ' -f1)" + + log "Creating $um_fw_path.md5" + echo "${um_hash_only:16:16}${um_hash_only:0:16} ${um_fw_name}" > "$um_md5_name" && + log "Created $um_md5_name" || + die "Failed to create $um_md5_name" +} + +um_create_corrupt_image() +{ + um_fw_path=$1 + um_fw_name=${um_fw_path##*/} + um_file_cd_path=${um_fw_path//"$um_fw_name"/""} + um_corrupt_fw_path="$um_file_cd_path/corrupt_${um_fw_name}" + um_corrupt_size=$(("$(stat --printf="%s" "$um_fw_path")" - "1")) + + [ -f "$um_corrupt_fw_path" ] && rm "$um_corrupt_fw_path" + + log "Corrupting image $um_fw_path" + dd if="$um_fw_path" of="$um_corrupt_fw_path" bs=1 count="$um_corrupt_size" && + log "Image corrupted Step #1" || + die "Failed to corruput image Step #1" + + dd if=/dev/urandom of="$um_corrupt_fw_path" bs=1 count=100 seek=1000 conv=notrunc && + log "Image corrupted Step #2" || + die "Failed to corruput image Step #2" + +} + +########################################## FW IMAGE SECTION - STOP ##################################################### + + +############################################ CM SECTION - START ######################################################## + +# Manipulates internet access for selected IP. +# Internet can be blocked or unblocked by adding or removing DROP rule. +address_internet_manipulation() +{ + local ip_address=${1} + local type=${2} + local sudo_cmd=${3:-"sudo"} + + # Select command and exit code according to options. + [[ $type == "block" ]] && type_arg="-I" || type_arg="-D" + [[ $type == "block" ]] && type_ec=0 || type_ec=1 + + log -deb "Manipulating internet for ip address $ip_address" + address_internet_check "$ip_address" "$type" + + wait_for_function_response "$type_ec" "${sudo_cmd} ${iptables_cmd} $type_arg FORWARD -s $ip_address -o eth0 -j DROP" && + log -deb "Internet ${type}ed for address $ip_address" || + die "Failed to $type internet for address $ip_address" + + return 0 +} + +address_internet_check() +{ + local ip_address=${1} + local type=${2} + local sudo_cmd=${3:-"sudo"} + + if [[ "$type" == 'block' ]]; then + exit_code=0 + else + exit_code=1 + fi + + check_ec=$(${sudo_cmd} ${iptables_cmd} -C FORWARD -s "$ip_address" -o eth0 -j DROP) + + if [ "$?" -eq "$exit_code" ]; then + die_with_code 0 "Internet already $type for address $ip_address" + else + return 1 + fi +} + +interface_internet_check() +{ + local if_name=${1} + local type=${2} + local sudo_cmd=${3:-"sudo"} + local fn_sleep=3 + + if [[ "$type" == 'block' ]]; then + exit_code=0 + else + exit_code=1 + fi + + wait_for_function_response "$exit_code" "${sudo_cmd} ${iptables_cmd} -C INPUT -i $if_name -j DROP" "${fn_sleep}" && + die_with_code 0 "Internet already ${type}ed for interface $if_name" || + return 1 + + return 0 +} + +# Manipulates internet access for selected IP. +# Internet can be blocked or unblocked by adding or removing DROP rule. +address_dns_manipulation() +{ + ip_address=${1} + type=${2} + fn_name="rpi_lib:address_dns_manipulation" + log -deb "[DEPRECATED] - Function ${fn_name} is deprecated in favor of address_dns_manipulation2" + # Select command and exit code according to options. + [ "$type" == "block" ] && type_arg="-I" || type_arg="-D" + [ "$type" == "block" ] && type_ec=0 || type_ec=1 + + log -deb "$fn_name - Manipulating DNS traffic for ip address $ip_address" + address_dns_check "$ip_address" "$type" + + wait_for_function_response "$type_ec" "iptables $type_arg OUTPUT -s $ip_address --dport 53 -j DROP" && + log -deb "$fn_name - DNS traffic ${type}ed for address $ip_address" || + raise "Failed to $type DNS traffic for address $ip_address" -l "$fn_name" -ds + + return 0 +} + +# Manipulates DNS traffic for source IP by adding or removing DROP rule +address_dns_manipulation2() +{ + local fn_name="rpi_lib:address_dns_manipulation2" + local ip_address=${1} + local type=${2} + local sudo_cmd=${3:-"sudo"} + local retry_cnt=3 + [ $# -ne 2 ] && raise "Requires 2 input arguments" -l "${fn_name}" -arg + [ -z $1 -o -z $2 ] && raise "Empty input argument(s)" -l "${fn_name}" -arg + log -deb "${fn_name} Manipulate DNS traffic: ${type} ${ip_address}" + + local iptables_args="${iptables_chain} -p udp -s ${ip_address} --dport 53 -j DROP" + if [ "${type}" == "block" ]; then + address_dns_check "${ip_address}" "${type}" && return 0 + local cmd="${sudo_cmd} ${iptables_cmd} -I ${iptables_args}" + elif [ "${type}" == "unblock" ]; then + address_dns_check "${ip_address}" "${type}" && return 0 + local cmd="${sudo_cmd} ${iptables_cmd} -D ${iptables_args}" + else + raise "Invalid input argument type ${type}" -l "${fn_name}" -arg + fi + + wait_for_function_exitcode "0" "${cmd}" "${retry_cnt}" && + log -deb "${fn_name} - DNS traffic ${type}ed for ${ip_address}" || + raise "Failed to ${type} DNS traffic for ${ip_address}" -l "${fn_name}" -ds + + address_dns_check "${ip_address}" "${type}" && + log -deb "${fn_name} - Command ${cmd} success" || + raise "Command ${cmd} incorrectly reported success, check system" -l "${fn_name}" -ds +} + +address_dns_check() +{ + local ip_address=${1} + local type=${2} + local sudo_cmd=${3:-"sudo"} + fn_name="rpi_lib:address_dns_check" + + if [ "$type" == 'block' ]; then + exit_code=0 + else + exit_code=1 + fi + + check_ec=$(${sudo_cmd} ${iptables_cmd} -C ${iptables_chain} -p udp -s "$ip_address" --dport 53 -j DROP) + + if [ "$?" -eq "$exit_code" ]; then + log -deb "$fn_name - DNS traffic already ${type}ed for address $ip_address" + return 0 + else + return 1 + fi +} + +############################################ CM SECTION - STOP ######################################################### diff --git a/src/fut/shell/lib/sm_lib.sh b/src/fut/shell/lib/sm_lib.sh new file mode 100755 index 00000000..c30f7829 --- /dev/null +++ b/src/fut/shell/lib/sm_lib.sh @@ -0,0 +1,366 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source "${FUT_TOPDIR}/shell/config/default_shell.sh" +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Stats Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ + +############################################ SETUP SECTION - START ##################################################### + +sm_log_test_pass_msg="---------------------------------- OK ----------------------------------" + +sm_setup_test_environment() +{ + fn_name="sm_lib:sm_setup_test_environment" + wm_setup_test_environment "$@" && + log -deb "$fn_name - wm_setup_test_environment - Success" || + raise "- wm_setup_test_environment - Failed" -l "$fn_name" -ds + + # Check if LM can be started, if not try starting PM. + # If it fails raise an exception. + start_specific_manager lm + if [ $? -eq 0 ]; then + log -deb "$fn_name - start_specific_manager lm - Success" + else + log -deb "$fn_name - start_specific_manager lm - Failed. Trying to start pm instead" + start_specific_manager pm + if [ $? -eq 0 ]; then + log -deb "$fn_name - start_specific_manager pm - Success" + else + raise "Both start_specific_manager lm, start_specific_manager pm - Failed" -l "$fn_name" -ds + fi + fi + + # QM start for report queue handling + start_specific_manager qm && + log -deb "$fn_name - start_specific_manager qm - Success" || + raise "start_specific_manager qm - Failed" -l "$fn_name" -ds + + start_specific_manager sm && + log -deb "$fn_name - start_specific_manager sm - Success" || + raise "start_specific_manager sm - Failed" -l "$fn_name" -ds + + empty_ovsdb_table AW_Debug + set_manager_log SM TRACE +} + +insert_ws_config() +{ + fn_name="sm_lib:insert_ws_config" + sm_radio_type=$1 + sm_channel_list=$2 + sm_stats_type=$3 + sm_survey_type=$4 + sm_reporting_interval=$5 + sm_sampling_interval=$6 + sm_report_type=$7 + + log -deb "$fn_name - Inserting Wifi_Stats_Config config" + + if [ -z "$sm_survey_type" ]; then + sm_survey_type="[\"set\",[]]" + fi + + insert_ovsdb_entry Wifi_Stats_Config \ + -i radio_type "$sm_radio_type" \ + -i channel_list "$sm_channel_list" \ + -i stats_type "$sm_stats_type" \ + -i survey_type "$sm_survey_type" \ + -i reporting_interval "$sm_reporting_interval" \ + -i sampling_interval "$sm_sampling_interval" \ + -i report_type "$sm_report_type" || + raise "Failed insert_ovsdb_entry" -l "$fn_name" -oe + + log -deb "$fn_name - Wifi_Stats_Config config Inserted" +} + +############################################ SETUP SECTION - STOP ##################################################### + + +############################################ TEST CASE SECTION - START ################################################# + +check_survey_report_log() +{ + fn_name="sm_lib:check_survey_report_log" + sm_radio_type=$1 + sm_channel=$2 + sm_survey_type=$3 + sm_log_type=$4 + + case $sm_log_type in + *processing_survey*) + sm_log_msg="Checking logs for survey $sm_radio_type channel $sm_channel reporting processing survey" + sm_die_msg="No survey processing done on $sm_radio_type $sm_survey_type-chan on channel $sm_channel" + match_pattern_for_log_inspecting="Processing $sm_radio_type .* $sm_survey_type $sm_channel" + ;; + *scheduled_scan*) + sm_log_msg="Checking logs for survey $sm_radio_type channel $sm_channel reporting scheduling survey" + sm_die_msg="No survey scheduling done on $sm_radio_type $sm_survey_type on channel $sm_channel" + match_pattern_for_log_inspecting="Scheduled $sm_radio_type $sm_survey_type $sm_channel scan" + ;; + *fetched_survey*) + sm_log_msg="Checking logs for survey $sm_radio_type channel $sm_channel reporting fetched survey" + sm_die_msg="No survey fetching done on $sm_radio_type $sm_survey_type on channel $sm_channel" + match_pattern_for_log_inspecting="Fetched $sm_radio_type $sm_survey_type $sm_channel survey" + ;; + *sending_survey_report*) + sm_log_msg="Checking logs for survey $sm_radio_type channel $sm_channel reporting sending survey" + sm_die_msg="No survey sending done on $sm_radio_type $sm_survey_type on channel $sm_channel" + match_pattern_for_log_inspecting="Sending $sm_radio_type .* $sm_survey_type $sm_channel survey report" + ;; + *) + raise "Incorrect sm_log_type provided" -l "$fn_name" -arg + esac + + log "$fn_name - $sm_log_msg" + wait_for_function_response 0 "$LOGREAD | tail -250 | grep -q \"$match_pattern_for_log_inspecting\"" && + log -deb "$fn_name - $sm_log_test_pass_msg" || + raise "$sm_die_msg" -l "$fn_name" -tc +} + +inspect_survey_report() +{ + fn_name="sm_lib:inspect_survey_report" + sm_radio_type=$1 + sm_channel=$2 + sm_survey_type=$3 + sm_reporting_interval=$4 + sm_sampling_interval=$5 + sm_report_type=$6 + sm_stats_type="survey" + + sm_channel_list="[\"set\",[$sm_channel]]" + + empty_ovsdb_table Wifi_Stats_Config || + raise "Failed empty_ovsdb_table Wifi_Stats_Config" -l "$fn_name" -tc + + insert_ws_config \ + "$sm_radio_type" \ + "$sm_channel_list" \ + "$sm_stats_type" \ + "$sm_survey_type" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" + + check_survey_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" processing_survey + check_survey_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" scheduled_scan + check_survey_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" fetched_survey + check_survey_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" sending_survey_report + + empty_ovsdb_table Wifi_Stats_Config || + raise "Failed empty_ovsdb_table Wifi_Stats_Config" -l "$fn_name" -tc + + return 0 +} + +check_neighbor_report_log() +{ + fn_name="sm_lib:check_neighbor_report_log" + sm_radio_type=$1 + sm_channel=$2 + sm_survey_type=$3 + sm_log_type=$4 + sm_neighbor_mac=$5 + sm_neighbor_ssid=$6 + + case $sm_log_type in + *add_neighbor*) + sm_log_msg="Checking for $sm_radio_type neighbor adding for $sm_neighbor_mac" + sm_die_msg="No neighbor $sm_neighbor_mac was added" + match_pattern_for_log_inspecting="Adding $sm_radio_type .* $sm_survey_type neighbor {bssid='$sm_neighbor_mac' ssid='$sm_neighbor_ssid' .* chan=$sm_channel}" + ;; + *parsed_neighbor_bssid*) + sm_log_msg="Checking for $sm_radio_type neighbor parsing of bssid $sm_neighbor_mac" + sm_die_msg="No neighbor $sm_neighbor_mac was parsed" + match_pattern_for_log_inspecting="Parsed $sm_radio_type BSSID $sm_neighbor_mac" + ;; + *parsed_neighbor_ssid*) + sm_log_msg="Checking for $sm_radio_type neighbor parsing of ssid $sm_neighbor_ssid" + sm_die_msg="No neighbor $sm_neighbor_ssid was parsed" + match_pattern_for_log_inspecting="Parsed $sm_radio_type SSID $sm_neighbor_ssid" + ;; + *sending_neighbor*) + sm_log_msg="Checking for $sm_radio_type neighbor sending of $sm_neighbor_mac" + sm_die_msg="No neighbor $sm_neighbor_mac was added" + match_pattern_for_log_inspecting="Sending $sm_radio_type .* $sm_survey_type neighbors {bssid='$sm_neighbor_mac' ssid='$sm_neighbor_ssid' .* chan=$sm_channel}" + ;; + *) + raise "Incorrect sm_log_type provided" -l "$fn_name" -arg + esac + + log "$fn_name - $sm_log_msg" + wait_for_function_response 0 "$LOGREAD | tail -250 | grep -q \"$match_pattern_for_log_inspecting\"" && + log -deb "$fn_name - $sm_log_test_pass_msg" || + raise "$sm_die_msg" -l "$fn_name" -tc +} + +inspect_neighbor_report() +{ + fn_name="sm_lib:inspect_neighbor_report" + sm_radio_type=$1 + sm_channel=$2 + sm_survey_type=$3 + sm_reporting_interval=$4 + sm_sampling_interval=$5 + sm_report_type=$6 + sm_neighbor_ssid=$7 + sm_neighbor_mac=$(echo "$8" | tr a-z A-Z) + + if [ -z "$sm_neighbor_mac" ] || [ -z "$sm_neighbor_ssid" ]; then + raise "Empty neighbor MAC address, or neighbor ssid" -l "$fn_name" -arg + fi + + sm_channel_list="[\"set\",[$sm_channel]]" + + empty_ovsdb_table Wifi_Stats_Config || + raise "Failed empty_ovsdb_table Wifi_Stats_Config" -l "$fn_name" -tc + + insert_ws_config \ + "$sm_radio_type" \ + "$sm_channel_list" \ + "survey" \ + "$sm_survey_type" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" + + insert_ws_config \ + "$sm_radio_type" \ + "$sm_channel_list" \ + "neighbor" \ + "$sm_survey_type" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" + + check_neighbor_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" add_neighbor "$sm_neighbor_mac" "$sm_neighbor_ssid" + check_neighbor_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" parsed_neighbor_bssid "$sm_neighbor_mac" "$sm_neighbor_ssid" + check_neighbor_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" parsed_neighbor_ssid "$sm_neighbor_mac" "$sm_neighbor_ssid" + check_neighbor_report_log "$sm_radio_type" "$sm_channel" "$sm_survey_type" sending_neighbor "$sm_neighbor_mac" "$sm_neighbor_ssid" + + empty_ovsdb_table Wifi_Stats_Config || + raise "Failed empty_ovsdb_table Wifi_Stats_Config" -l "$fn_name" -tc + return 0 +} + +check_leaf_report_log() +{ + fn_name="sm_lib:check_leaf_report_log" + sm_radio_type=$1 + sm_client_mac_address=$(echo "$2" | tr a-z A-Z) + sm_log_type=$3 + + case $sm_log_type in + *connected*) + sm_log_msg="Checking logs for leaf reporting radio $sm_radio_type connection established" + sm_die_msg="No client $sm_client_mac_address connected for reporting" + match_pattern_for_log_inspecting="Marked $sm_radio_type .* client $sm_client_mac_address connected" + ;; + *client_parsing*) + sm_log_msg="Checking logs for leaf parsing $sm_client_mac_address" + sm_die_msg="No client $sm_client_mac_address parsed" + match_pattern_for_log_inspecting="Parsed $sm_radio_type client MAC $sm_client_mac_address" + ;; + *client_update*) + sm_log_msg="Checking logs for leaf entry update $sm_client_mac_address" + sm_die_msg="No client $sm_client_mac_address updated" + match_pattern_for_log_inspecting="Updating $sm_radio_type .* client $sm_client_mac_address entry" + ;; + *sending*) + sm_log_msg="Checking logs for leaf $sm_client_mac_address $sm_radio_type sample sending" + sm_die_msg="No client $sm_client_mac_address $sm_radio_type sample sending initiated" + match_pattern_for_log_inspecting="Sending $sm_radio_type .* client $sm_client_mac_address stats" + ;; + *) + raise "Incorrect sm_log_type provided" -l "$fn_name" -arg + esac + log -deb "$fn_name - $sm_log_msg" + + wait_for_function_response 0 "$LOGREAD | tail -250 | grep -q \"$match_pattern_for_log_inspecting\"" && + log -deb "$fn_name - $sm_log_test_pass_msg" || + raise "$sm_die_msg" -l "$fn_name" -tc +} + +inspect_leaf_report() +{ + fn_name="sm_lib:inspect_leaf_report" + sm_radio_type=$1 + sm_reporting_interval=$2 + sm_sampling_interval=$3 + sm_report_type=$4 + sm_leaf_mac=$5 + + if [ -z "$sm_leaf_mac" ]; then + raise "Empty leaf MAC address" -l "$fn_name" -arg + fi + + empty_ovsdb_table Wifi_Stats_Config || + raise "Failed empty_ovsdb_table Wifi_Stats_Config" -l "$fn_name" -oe + + insert_ws_config \ + "$sm_radio_type" \ + "[\"set\",[]]" \ + "survey" \ + "[\"set\",[]]" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" + + insert_ws_config \ + "$sm_radio_type" \ + "[\"set\",[]]" \ + "client" \ + "[\"set\",[]]" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" + + check_leaf_report_log "$sm_radio_type" "$sm_leaf_mac" connected + check_leaf_report_log "$sm_radio_type" "$sm_leaf_mac" client_parsing + check_leaf_report_log "$sm_radio_type" "$sm_leaf_mac" client_update + check_leaf_report_log "$sm_radio_type" "$sm_leaf_mac" sending + + empty_ovsdb_table Wifi_Stats_Config || + raise "Failed empty_ovsdb_table Wifi_Stats_Config" -l "$fn_name" -oe + + return 0 +} + +############################################ TEST CASE SECTION - STOP ################################################## diff --git a/src/fut/shell/lib/um_lib.sh b/src/fut/shell/lib/um_lib.sh new file mode 100755 index 00000000..4a837a68 --- /dev/null +++ b/src/fut/shell/lib/um_lib.sh @@ -0,0 +1,191 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source ${FUT_TOPDIR}/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Upgrade Manager functions (Plume specific) +# +############################################ INFORMATION SECTION - STOP ################################################ + + +############################################ SETUP SECTION - START ##################################################### + +um_setup_test_environment() +{ + fw_path=$1 + fn_name="um_lib:um_setup_test_environment" + + log -deb "UM SETUP" + + device_init || + raise "device_init" -l "$fn_name" -fc + + start_openswitch || + raise "start_openswitch" -l "$fn_name" -fc + + start_udhcpc eth0 true || + raise "start_udhcpc" -l "$fn_name" -fc + + log -deb "lib/um_lib: um_setup_environment - Erasing $fw_path" + rm -rf "$fw_path" || true + + start_specific_manager um -d || + raise "start_specific_manager um" -l "$fn_name" -fc + + log -deb "$fn_name - UM setup - end" +} + +reset_um_triggers() +{ + fw_path=$1 + fn_name="um_lib:reset_um_triggers" + + log -deb "$fn_name - Erasing $fw_path" + rm -rf "$fw_path" || true + + log -deb "$fn_name - Reseting AWLAN_Node UM fields" + update_ovsdb_entry AWLAN_Node \ + -u firmware_pass '' \ + -u firmware_url '' \ + -u upgrade_dl_timer '0' \ + -u upgrade_status '0' \ + -u upgrade_timer '0' && + log -deb "$fn_name - AWLAN_Node UM fields reset" || + raise "{AWLAN_Node -> update}" -l "$fn_name" -oe +} + +############################################ SETUP SECTION - STOP ###################################################### + +get_um_code() +{ + upgrade_identifier=$1 + fn_name="um_lib:get_um_code" + + case "$upgrade_identifier" in + "UPG_ERR_ARGS") + echo "-1" + ;; + "UPG_ERR_URL") + echo "-3" + ;; + "UPG_ERR_DL_FW") + echo "-4" + ;; + "UPG_ERR_DL_MD5") + echo "-5" + ;; + "UPG_ERR_MD5_FAIL") + echo "-6" + ;; + "UPG_ERR_IMG_FAIL") + echo "-7" + ;; + "UPG_ERR_FL_ERASE") + echo "-8" + ;; + "UPG_ERR_FL_WRITE") + echo "-9" + ;; + "UPG_ERR_FL_CHECK") + echo "-10" + ;; + "UPG_ERR_BC_SET") + echo "-11" + ;; + "UPG_ERR_APPLY") + echo "-12" + ;; + "UPG_ERR_BC_ERASE") + echo "-14" + ;; + "UPG_ERR_SU_RUN ") + echo "-15" + ;; + "UPG_ERR_DL_NOFREE") + echo "-16" + ;; + "UPG_STS_FW_DL_START") + echo "10" + ;; + "UPG_STS_FW_DL_END") + echo "11" + ;; + "UPG_STS_FW_WR_START") + echo "20" + ;; + "UPG_STS_FW_WR_END") + echo "21" + ;; + "UPG_STS_FW_BC_START") + echo "30" + ;; + "UPG_STS_FW_BC_END") + echo "31" + ;; + *) + raise "upgrade_identifier {given:=$upgrade_identifier}" -l "$fn_name" -arg + ;; + esac +} + +fw_dl_timer_result() +{ + exit_code=$1 + start_time=$2 + fn_name="um_lib:fw_dl_timer_result" + + end_time=$(date -D "%H:%M:%S" +"%Y.%m.%d-%H:%M:%S") + t1=$(date -u -d "$start_time" +"%s") + t2=$(date -u -d "$end_time" +"%s") + + download_time=$(( t2 - t1 )) + + if [ "$exit_code" -eq 0 ]; then + log -deb "$fn_name - FW downloaded in given download_timer - downloaded in $download_time" + else + + ${OVSH} s AWLAN_Node -w upgrade_status=="$(get_um_code "UPG_ERR_DL_FW")" + + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - FW downloaded was aborted after upgrade_dl_timer" + else + ${OVSH} s AWLAN_Node + raise "FW download was not aborted after upgrade_dl_timer" -l "$fn_name" -tc + fi + fi + + return 0 +} diff --git a/src/fut/shell/lib/unit.mk b/src/fut/shell/lib/unit.mk new file mode 100644 index 00000000..9f35582e --- /dev/null +++ b/src/fut/shell/lib/unit.mk @@ -0,0 +1,47 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_lib + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/lib + +UNIT_FILE := base_lib.sh +UNIT_FILE += brv_lib.sh +UNIT_FILE += cm2_lib.sh +UNIT_FILE += dm_lib.sh +UNIT_FILE += ledm_lib.sh +UNIT_FILE += nm2_lib.sh +UNIT_FILE += onbrd_lib.sh +UNIT_FILE += qm_lib.sh +UNIT_FILE += rpi_lib.sh +UNIT_FILE += sm_lib.sh +UNIT_FILE += um_lib.sh +UNIT_FILE += unit_lib.sh +UNIT_FILE += ut_lib.sh +UNIT_FILE += wm2_lib.sh diff --git a/src/fut/shell/lib/unit_lib.sh b/src/fut/shell/lib/unit_lib.sh new file mode 100755 index 00000000..2b618c57 --- /dev/null +++ b/src/fut/shell/lib/unit_lib.sh @@ -0,0 +1,1255 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source "${FUT_TOPDIR}/shell/config/default_shell.sh" +fi +source "${FUT_TOPDIR}/shell/lib/base_lib.sh" + +############################################ INFORMATION SECTION - START ############################################### +# +# Common library of shared functions, used globally +# +############################################ INFORMATION SECTION - STOP ################################################ +lib_name="unit_lib" + +############################################ UTILITY SECTION - START ################################################### + +# Returns the filename of the script manipulating OpenSync managers +get_managers_script() +{ + echo "/etc/init.d/opensync" +} + +# Get the MAC address of an interface +mac_get() +{ + ifconfig "$1" | grep -o -E '([A-F0-9]{2}:){5}[A-F0-9]{2}' +} + +get_radio_mac_from_ovsdb() +{ + # Examples of use: + # get_radio_mac_from_ovsdb "freq_band==5GL" + # get_radio_mac_from_ovsdb "if_name==wifi1" + # get_radio_mac_from_ovsdb "channel==44" + local where_clause=$1 + # No logging, this function echoes the requested value to caller! + ${OVSH} s Wifi_Radio_State -w ${where_clause} mac -r + return $? +} + +tail_logs_for_match() +{ + match=$(timeout -t "$DEFAULT_WAIT_TIME" -s SIGKILL tail -n150 -f /var/log/messages | tr -s ' ' | { sed "/$match_pattern_for_log_inspecting/ q"; } | tail -1 | grep "$match_pattern_for_log_inspecting") + echo $match +} + +start_udhcpc() +{ + fn_name="unit_lib:start_udhcpc" + if_name=$1 + should_get_address=${2:-false} + + log -deb "$fn_name - Starting udhcpc on $if_name" + + ps_out=$(pgrep "/sbin/udhcpc.*$if_name") + if [ $? -eq 0 ]; then + kill $ps_out && log -deb "$fn_name - Old udhcpc pid killed for $if_name" + fi + + /sbin/udhcpc -i "$if_name" -f -p /var/run/udhcpc-"$if_name".pid -s ${OPENSYNC_ROOTDIR}/bin/udhcpc.sh -t 60 -T 1 -S --no-default-options &>/dev/null & + + if [ "$should_get_address" = "true" ]; then + wait_for_function_response 'notempty' "interface_ip_address $if_name" && + log "$fn_name - DHCPC provided address to $if_name" || + raise "DHCPC didn't provide address to $if_name" -l "$fn_name" -ds + fi + + return 0 +} + +############################################ UTILITY SECTION - STOP #################################################### + + +############################################ PROCESS SECTION - START ################################################### + +# deprecated in favor of "get_pids", which provides all pids matching expression +get_pid() +{ + PID=$(ps -w | grep -e "$1" | grep -v 'grep' | awk '{ print $1 }') + echo "$PID" +} + +get_pids() +{ + PID="$(ps -w | grep -e ${1} | grep -v 'grep' | awk '{ print $1 }')" + echo "${PID}" +} + +get_pid_mem() +{ + PID_MEM=$(ps -w | grep -e "$1" | grep -v 'grep' | awk '{ printf $3 }') + echo "$PID_MEM" +} + +check_pid_file() +{ + fn_name="unit_lib:check_pid_file" + type=$1 + file=$2 + + if [ "$type" = "dead" ] && [ ! -f "$file" ]; then + log -deb "$fn_name - Process $file is dead" + return 0 + elif [ "$type" = "alive" ] && [ -f "$file" ]; then + log -deb "$fn_name - Process $file is alive" + return 0 + elif [ "$type" = "dead" ] && [ -f "$file" ]; then + log -deb "$fn_name - Process is alive" + return 1 + else + log -deb "$fn_name - Process is dead" + return 1 + fi +} + +check_pid_udhcp() +{ + local fn_name="unit_lib:check_pid_udhcp" + local if_name="${1}" + PID=$(ps -w | grep -e udhcpc | grep -e ${if_name} | grep -v 'grep' | awk '{ print $1 }') + if [ -z "$PID" ]; then + log -deb "${fn_name} - DHCP client not running on ${if_name}" + return 1 + else + log -deb "${fn_name} - DHCP client running on ${if_name}, PID=${PID}" + return 0 + fi +} + +# requires binary "pidof" +killall_process_by_name () +{ + local PROCESS_PID="$(pidof ${1})" + if [ -n "$PROCESS_PID" ]; then + # In case of several returned values + for P in $PROCESS_PID; do + for S in SIGTERM SIGINT SIGHUP SIGKILL; do + kill -s "${S}" "${P}" + kill -0 "${P}" + if [ $? -ne 0 ]; then + break + fi + done + if [ $? -eq 0 ]; then + log -deb "lib/unit_lib: killall_process_by_name - killed process:${P} with signal:${S}" + else + log -deb "lib/unit_lib: killall_process_by_name - could not kill process:${P}" + fi + done + fi +} + +############################################ PROCESS SECTION - STOP #################################################### + + +############################################ SETUP SECTION - START ################################################## + +device_init() +{ + disable_watchdog + stop_managers + stop_healthcheck + return $? +} + +############################################ SETUP SECTION - START ################################################## + + +############################################ WATCHDOG SECTION - START ################################################## + +disable_watchdog() +{ + local fn_name="unit_lib:disable_watchdog" + log -deb "$fn_name - Disabling watchdog." + log -deb "$fn_name - This is a stub function. Override implementation needed for each model." + return 0 +} + +############################################ WATCHDOG SECTION - STOP ################################################### + + +############################################ OpenSwitch SECTION - START ################################################ + +start_openswitch() +{ + fn_name="unit_lib:start_openswitch" + log -deb "$fn_name - Starting Open vSwitch" + + ovs_run=$(ps -w | grep -v "grep" | grep "ovs-vswitchd") + + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - Open vSwitch already running" + return 0 + fi + + /etc/init.d/openvswitch start || raise "Issue during Open vSwitch start" -l "$fn_name" -ds + + wait_for_function_response 0 "pidof ovs-vswitchd" && + log -deb "$fn_name - ovs-vswitchd running" || + raise "Couldn't start ovs-vswitchd" -l "$fn_name" -ds + + wait_for_function_response 0 "pidof ovsdb-server" && + log -deb "$fn_name - ovsdb-server running" || + raise "Couldn't start ovsdb-server" -l "$fn_name" -ds + + sleep 1 +} + +stop_healthcheck() +{ + fn_name="unit_lib:stop_healthcheck" + if [ -n "$(get_pid "healthcheck")" ]; then + log -deb "$fn_name - Disabling healthcheck." + /etc/init.d/healthcheck stop || true + + log -deb "$fn_name - Check if healthcheck is disabled" + wait_for_function_response 1 "ps -w | grep -e 'healthcheck' | grep -v 'grep'" + if [ "$?" -ne 0 ]; then + log -deb "$fn_name - Healthcheck is NOT disabled ! PID: $(get_pid "healthcheck")" + return 1 + else + log -deb "$fn_name - Healthcheck is disabled." + fi + else + log -deb "$fn_name - Healthcheck is already disabled." + fi + return 0 +} + +############################################ OpenSwitch SECTION - STOP ################################################# + + +############################################ RESOURCE SECTION - START ################################################## + +############################################ RESOURCE SECTION - STOP ################################################### + + +############################################ MANAGERS SECTION - START ################################################## + +start_managers() +{ + fn_name="unit_lib:start_managers" + log -deb "$fn_name Starting OpenSync managers" + MANAGER_SCRIPT=$(get_managers_script) + ret=$($MANAGER_SCRIPT start) + # Make sure to define return value on success or failure + if [ $? -ne 1 ]; then + raise "Issue during OpenSync manager start" -l "$fn_name" -ds + else + log "$fn_name OpenSync managers started" + fi + + # Check dm slave PID + PID=$(ps -w | grep -e ${OPENSYNC_ROOTDIR}/bin/dm | grep -v 'grep' | grep -v slave | awk '{ print $1 }') + if [ -z "$PID" ]; then + raise "Issue during manager start, dm slave not running" -l "$fn_name" -ds + else + log "$fn_name dm slave PID = $PID" + fi + + # Check dm master PID + PID=$(ps -w | grep -e ${OPENSYNC_ROOTDIR}/bin/dm | grep -v 'grep' | grep -v master | awk '{ print $1 }') + if [ -z "$PID" ]; then + raise "Issue during manager start, dm master not running" -l "$fn_name" -ds + else + log "$fn_name dm master PID = $PID" + fi + + return 0 +} + +restart_managers() +{ + fn_name="unit_lib:restart_managers" + log -deb "$fn_name - Restarting OpenSync managers" + MANAGER_SCRIPT=$(get_managers_script) + ret=$($MANAGER_SCRIPT restart) + ec=$? + log -deb "$fn_name - manager restart exit code ${ec}" + return $ec +} + +stop_managers() +{ + fn_name="unit_lib:stop_managers" + log -deb "$fn_name - Stopping OpenSync managers" + MANAGER_SCRIPT=$(get_managers_script) + $MANAGER_SCRIPT stop || + raise "Issue during OpenSync manager stop" -l "$fn_name" -ds +} + +disable_managers() +{ + fn_name="unit_lib:disable_managers" + log -deb "$fn_name - Stopping OpenSync managers" + MANAGER_SCRIPT=$(get_managers_script) + $MANAGER_SCRIPT stop || + raise "Issue during OpenSync manager stop" -l "$fn_name" -ds + + sleep 1 + PID=$(pidof dm) && raise "dm not running" -l "$fn_name" -ds +} + +start_specific_manager() +{ + fn_name="unit_lib:start_specific_manager" + option=$2 + + manager="${OPENSYNC_ROOTDIR}/bin/$1" + + # Check if executable + if [ ! -x "$manager" ]; then + log -deb "$fn_name - Manager $manager does not exist or is not executable" + return 1 + fi + + # Start manager + log -deb "$fn_name - Starting $manager $option" | tr a-z A-Z + $manager $option >/dev/null 2>&1 & + sleep 1 +} + +restart_specific_manager() +{ + fn_name="unit_lib:restart_specific_manager" + # Sanitize input + if [ $# -eq 1 ]; then + manager="${OPENSYNC_ROOTDIR}/bin/$1" + else + log -deb "$fn_name - Provide exactly one input argument" + return 1 + fi + + # Check if executable + if [ ! -x "$manager" ]; then + log -deb "$fn_name - Manager $manager does not exist or is not executable" + return 1 + fi + + # Start manager + log -deb "$fn_name - Starting $manager" | tr a-z A-Z + killall "$1" + sleep 1 + $manager >/dev/null 2>&1 & + sleep 1 +} + +set_manager_log() +{ + fn_name="unit_lib:set_manager_log" + log -deb "$fn_name - Adding $1 to AW_Debug with severity $2" + insert_ovsdb_entry AW_Debug -i name "$1" -i log_severity "$2" || + raise "{AW_Debug -> insert}" -l "$fn_name" -oe +} + +run_setup_if_crashed() +{ + fn_name="unit_lib:run_setup_if_crashed" + for manager in "$@" + do + manager_pid_file="${OPENSYNC_ROOTDIR}/bin/$manager" + pid_of_manager=$(get_pid "$manager_pid_file") + if [ -z "$pid_of_manager" ]; then + log -deb "$fn_name - Manager $manager crashed. Executing module environment setup" + eval "${manager}_setup_test_environment" && + log -deb "$fn_name - Test environment for $manager success" || + raise "Test environment for $manager failed" -l "$fn_name" -tc + fi + done +} + +# Prevent CM fatal state: prevent restarting managers +cm_disable_fatal_state() +{ + fn_name="unit_lib:cm_disable_fatal_state" + log -deb "$fn_name - Disabling CM manager restart procedure" + if [ ! -d /opt/tb ]; then + mkdir -p /opt/tb/ + fi + touch /opt/tb/cm-disable-fatal +} + +cm_enable_fatal_state() +{ + fn_name="unit_lib:cm_enable_fatal_state" + log -deb "$fn_name - Enabling CM manager restart procedure" + rm -f /opt/tb/cm-disable-fatal +} + +############################################ MANAGERS SECTION - STOP ################################################### + + +############################################ OVSDB SECTION - START ##################################################### + +get_ovsdb_entry_value() +{ + fn_name="unit_lib:get_ovsdb_entry_value" + ovsdb_table=$1 + ovsdb_field=$2 + shift 2 + conditions_string="" + raw=false + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -w) + conditions_string="$conditions_string -w $1==$2" + shift 2 + ;; + -raw) + raw=true + shift + ;; + esac + done + + raw_field_value=$(${OVSH} s "$ovsdb_table" $conditions_string "$ovsdb_field" -r) || return 1 + + echo "$raw_field_value" | grep -q '"uuid"' + if [ "$raw" = "false" ] && [ "$?" -eq 0 ]; then + value=$(echo "$raw_field_value" | cut -d ',' -f 2 | cut -d '"' -f 2) + else + value="$raw_field_value" + fi + + echo "$value" +} + +check_ovsdb_entry() +{ + fn_name="unit_lib:check_ovsdb_entry" + ovsdb_table=$1 + shift 1 + conditions_string="" + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -w) + conditions_string="$conditions_string -w $1==$2" + shift 2 + ;; + esac + done + + check_cmd="${OVSH} s $ovsdb_table $conditions_string" + + log "$fn_name - Checking if entry exists \n$check_cmd" + eval "$check_cmd" && return 0 || return 1 +} + +empty_ovsdb_table() +{ + fn_name="unit_lib:empty_ovsdb_table" + log -deb "$fn_name - Clearing $1 table" + ${OVSH} d "$1" || raise "{$1 -> delete}" -l "$fn_name" -oe +} + +wait_for_empty_ovsdb_table() +{ + fn_name="unit_lib:wait_for_empty_ovsdb_table" + ovsdb_table=$1 + wait_time=0 + + log -deb "$fn_name - Waiting for table $1 deletion" + + while true ; do + log -deb "$fn_name - Select $ovsdb_table try $wait_time" + table_select=$(${OVSH} s "$ovsdb_table") || true + + if [ -z "$table_select" ]; then + log -deb "$fn_name - Table $ovsdb_table is empty!" + break + fi + + if [ $wait_time -gt $DEFAULT_WAIT_TIME ]; then + raise "{$1 -> delete}" -l "$fn_name" -oe + fi + + wait_time=$((wait_time+1)) + sleep 1 + done + + log -deb "$fn_name - Table $ovsdb_table successfully deleted!" +} + +wait_ovsdb_entry_remove() +{ + fn_name="unit_lib:wait_ovsdb_entry_remove" + ovsdb_table=$1 + shift + conditions_string="" + info_string="$fn_name - Waiting for entry removal:\n" + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -w) + conditions_string="$conditions_string -w $1==$2" + info_string="$info_string where $1 is $2\n" + shift 2 + ;; + esac + done + + log -deb "$info_string" + + select_entry_command="$ovsdb_table $conditions_string" + wait_time=0 + + while true ; do + entry_select=$(${OVSH} s $select_entry_command) || true + + if [ -z "$entry_select" ]; then + log -deb "$fn_name - Entry deleted" + break + fi + + if [ $wait_time -gt $DEFAULT_WAIT_TIME ]; then + $select_entry_command + raise "{$ovsdb_table -> entry_remove}" -l "$fn_name" -ow + fi + + wait_time=$((wait_time+1)) + sleep 1 + done + + return 0 +} + +update_ovsdb_entry() +{ + fn_name="unit_lib:update_ovsdb_entry" + ovsdb_table=$1 + shift + conditions_string="" + update_string="" + update_method=":=" + force_insert=1 + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -m) + update_method="$1" + shift + ;; + -w) + conditions_string="$conditions_string -w $1==$2" + shift 2 + ;; + -u) + update_string="$update_string $1$update_method$2" + shift 2 + update_method=":=" + ;; + -force) + force_insert=0 + ;; + esac + done + + entry_command="${OVSH} u $ovsdb_table $conditions_string $update_string" + log -deb "$fn_name - Executing update command\n$entry_command" + + $($entry_command) || $(return 1) + + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - Entry updated" + log -deb "${OVSH} s $ovsdb_table $conditions_string" + ${OVSH} s "$ovsdb_table" $conditions_string || log -deb "$fn_name - Failed to print entry" + else + ${OVSH} s "$ovsdb_table" || log -deb "$fn_name - Failed to print table $ovsdb_table" + + if [ $force_insert -eq 0 ]; then + log -deb "$fn_name - Force entry, not failing!" + else + raise "{$ovsdb_table -> update}" -l "$fn_name" -oe + fi + fi + + return 0 +} + +remove_ovsdb_entry() +{ + fn_name="unit_lib:remove_ovsdb_entry" + ovsdb_table=$1 + shift + conditions_string="" + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -w) + conditions_string="$conditions_string -w $1==$2" + shift 2 + ;; + esac + done + + remove_command="${OVSH} d $ovsdb_table $conditions_string $update_string" + log -deb "$fn_name - $remove_command" + + $($remove_command) || $(return 1) + + if [ "$?" -eq 0 ]; then + log -deb "$fn_name Entry removed" + else + print_tables "$ovsdb_table" || + log -deb "$fn_name - Failed to print table $ovsdb_table" + raise "{$ovsdb_table -> entry_remove}" -l "$fn_name" -oe + fi + + return 0 +} + +insert_ovsdb_entry() +{ + fn_name="unit_lib:insert_ovsdb_entry" + ovsdb_table=$1 + shift + conditions_string="" + insert_string="" + insert_method=":=" + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -m) + insert_method="$1" + shift + ;; + -i) + insert_string="$insert_string $1$insert_method$2" + shift 2 + insert_method=":=" + ;; + esac + done + + entry_command="${OVSH} i $ovsdb_table $insert_string" + + log -deb "$fn_name - Executing insert command\n$entry_command" + + $($entry_command) || $(return 1) + + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - Entry inserted" + ${OVSH} s "$ovsdb_table" + else + ${OVSH} s "$ovsdb_table" + raise "{$ovsdb_table -> insert}" -l "$fn_name" -oe + fi + + return 0 +} + +insert_ovsdb_entry2() +{ + local fn_name="unit_lib:insert_ovsdb_entry2" + local ovsdb_table=$1 + shift + local insert_string="" + + while [ -n "${1}" ]; do + option=${1} + shift + case "$option" in + -i) + insert_string="${insert_string} "${1}":="${2} + shift 2 + ;; + esac + done + + entry_command="${OVSH} i $ovsdb_table "$insert_string + log -deb "$fn_name - Executing ${entry_command}" + ${entry_command} + if [ $? -eq 0 ]; then + log -deb "$fn_name - Success: entry inserted" + ${OVSH} s "$ovsdb_table" + return 0 + else + ${OVSH} s "$ovsdb_table" + raise "Failure: entry not inserted" -l "$fn_name" -oe + fi +} + +wait_ovsdb_entry() +{ + fn_name="unit_lib:wait_ovsdb_entry" + ovsdb_table=$1 + shift + conditions_string="" + where_is_string="" + exit_code=0 + ovsh_cmd=${OVSH} + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -w) + conditions_string="$conditions_string -w $1==$2" + shift 2 + ;; + -wn) + conditions_string="$conditions_string -w $1!=$2" + shift 2 + ;; + -is) + where_is_string="$where_is_string $1:=$2" + shift 2 + ;; + -is_not) + where_is_string="$where_is_string -n $1:=$2" + shift 2 + ;; + -ec) + exit_code=1 + ;; + -f) + ovsh_cmd=${OVSH_FAST} + ;; + -s) + ovsh_cmd=${OVSH_SLOW} + esac + done + + wait_entry_command="$ovsh_cmd wait $ovsdb_table $conditions_string $where_is_string" + wait_time=0 + + log -deb "$fn_name - Waiting for entry: \n$wait_entry_command" + + $($wait_entry_command) || $(return 1) + + if [ "$?" -eq "$exit_code" ]; then + log -deb "$fn_name - SUCCESS: $wait_entry_command" + ${OVSH} s "$ovsdb_table" $conditions_string + return 0 + else + log -deb "$fn_name - FAIL: Table $ovsdb_table" + ${OVSH} s "$ovsdb_table" || true + log -deb "$fn_name - FAIL: $wait_entry_command" + return 1 + fi +} + +wait_for_function_response() +{ + fn_name="unit_lib:wait_for_function_response" + wait_for_value="$1" + function_to_wait_for="$2" + wait_time=${3:-$DEFAULT_WAIT_TIME} + return_val=1 + fuc_exec_time=0 + is_get_ovsdb_entry_value=1 + + if [ "$wait_for_value" = 'empty' ]; then + log -deb "$fn_name - Waiting for function $function_to_wait_for empty response" + elif [ "$wait_for_value" = 'notempty' ]; then + log -deb "$fn_name - Waiting for function $function_to_wait_for not empty response" + echo "$function_to_wait_for" | grep -q "get_ovsdb_entry_value" && is_get_ovsdb_entry_value=0 + else + log -deb "$fn_name - Waiting for function $function_to_wait_for exit code $wait_for_value" + fi + + while true ; do + log -deb "$fn_name - Executing: $function_to_wait_for" + if [ "$wait_for_value" = 'empty' ] || [ "$wait_for_value" = 'notempty' ]; then + res=$(eval "$function_to_wait_for" || echo 1) + if [ -n "$res" ]; then + if [ "$is_get_ovsdb_entry_value" -eq 0 ]; then + if [ "$res" = '["set",[]]' ] || [ "$res" = '["map",[]]' ]; then + function_res='empty' + else + function_res='notempty' + fi + else + function_res='notempty' + fi + else + function_res='empty' + fi + else + eval "$function_to_wait_for" && function_res=0 || function_res=1 + fi + + log -deb "$fn_name - Function response/code is $function_res" + + if [ "$function_res" = "$wait_for_value" ]; then + return_val=0 + break + fi + + if [ $fuc_exec_time -gt $wait_time ]; then + log -deb "$fn_name - Function $function_to_wait_for timed out" + break + fi + + fuc_exec_time=$((fuc_exec_time+1)) + sleep 1 + done + + return "$return_val" +} + +wait_for_function_output() +{ + # Waits for expected output of function, not exit code + # Possible input arguments: + # wait_for_value: "empty", "notempty", custom (required) + # function_to_wait_for: string with the function to wait for (required) + # retry_count: after how many iterations we stop checking? (optional, default=30) + # retry_sleep: time in seconds between function checks (optional, default=1) + local fn_name="unit_lib:wait_for_function_output" + local wait_for_value=$1 + local function_to_wait_for=$2 + local retry_count=${3:-$DEFAULT_WAIT_TIME} + local retry_sleep=${4:-1} + local fn_exec_cnt=0 + local is_get_ovsdb_entry_value=0 + [ $(echo "$function_to_wait_for" | grep -qwF "get_ovsdb_entry_value") ] && is_get_ovsdb_entry_value=1 + + log -deb "$fn_name - Executing $function_to_wait_for, waiting for $wait_for_value response" + while true ; do + res=$($function_to_wait_for) + if [ "$wait_for_value" = 'notempty' ]; then + if [ $is_get_ovsdb_entry_value ]; then + [ -n "$res" -a "$res" != '["set",[]]' -a "$res" != '["map",[]]' ] && return 0 + else + [ -n "$res" ] && return 0 + fi + elif [ "$wait_for_value" = 'empty' ]; then + if [ $is_get_ovsdb_entry_value ]; then + [ -z "$res" -o "$res" = '["set",[]]' -o "$res" = '["map",[]]' ] && return 0 + else + [ -z "$res" ] && return 0 + fi + else + [ "$res" = "$wait_for_value" ] && return 0 + fi + + fn_exec_cnt=$(( $fn_exec_cnt + 1 )) + log -deb "$fn_name - Function retry ${fn_exec_cnt} output: ${res}" + if [ $fn_exec_cnt -ge $retry_count ]; then + raise "Function $function_to_wait_for timed out" -l "${fn_name}" + fi + sleep ${retry_sleep} + done + return 1 +} + +wait_for_function_exitcode() +{ + # Waits for expected exit code, not stdout/stderr + # Possible input arguments: + # exp_ec: expected exit code (required) + # function_to_wait_for: string with the function to wait for (required) + # retry_count: after how many iterations we stop checking? (optional, default=30) + # retry_sleep: time in seconds between function checks (optional, default=1) + local fn_name="unit_lib:wait_for_function_exitcode" + local exp_ec=$1 + local function_to_wait_for=$2 + local retry_count=${3:-$DEFAULT_WAIT_TIME} + local retry_sleep=${4:-1} + local fn_exec_cnt=1 + + log -deb "${fn_name} - Executing $function_to_wait_for, waiting for exit code ${exp_ec}" + res=$($function_to_wait_for) + local act_ec=$? + while [ ${act_ec} -ne ${exp_ec} ]; do + log -deb "${fn_name} - Retry ${fn_exec_cnt}, exit code: ${act_ec}, expecting: ${exp_ec}" + if [ ${fn_exec_cnt} -ge ${retry_count} ]; then + raise "Function ${function_to_wait_for} timed out" -l "${fn_name}" + fi + sleep ${retry_sleep} + res=$($function_to_wait_for) + act_ec=$? + fn_exec_cnt=$(( $fn_exec_cnt + 1 )) + done + log -deb "${fn_name} - Exit code: ${act_ec} equal to expected: ${exp_ec}" + return 0 +} + +monitor_ovsdb_field_for_changes() +{ + fn_name="unit_lib:monitor_ovsdb_field_for_changes" + ovsdb_table=$1 + shift + info_string="$fn_name - Monitoring table $ovsdb_table Column -" + conditions_string="" + field_to_monitor="" + timer=0 + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -w) + conditions_string="$conditions_string -w $1==$2" + shift 2 + ;; + -m) + field_to_monitor="$1" + info_string="$info_string $1" + shift 1 + ;; + esac + done + + log -deb "$info_string" + + echo "${OVSH} s $ovsdb_table $conditions_string $field_to_monitor -r" + field_to_monitor_value=$(${OVSH} s "$ovsdb_table" $conditions_string "$field_to_monitor" -r) + + log -deb "$fn_name - Field $field_to_monitor value is $field_to_monitor_value" + + while [ "$timer" -lt "$DEFAULT_WAIT_TIME" ]; do + (${OVSH} wait "$ovsdb_table" $conditions_string -n "$field_to_monitor":="$field_to_monitor_value" 2>&1) + if [ "$?" -eq 0 ]; then + field_value=$(${OVSH} s "$ovsdb_table" $conditions_string "$field_to_monitor" -r) + log -deb "$fn_name - Field $field_to_monitor changed from $field_to_monitor_value to $field_value" + field_to_monitor_value=$field_value + fi + done +} + +interface_is_up() +{ + ifconfig "$1" 2>/dev/null | grep Metric | grep -q UP + return $? +} + +interface_ip_address() +{ + ifconfig "$1" | tr -s ' :' '@' | grep -e '^@inet@' | cut -d '@' -f 4 +} + +check_restore_management_access() +{ + fn_name="unit_lib:check_restore_managment_access" + log -deb "$fn_name - Checking and restoring if needed management access" + interface_is_up eth0 + if [ "$?" = 0 ]; then + log -deb "$fn_name - Interface eth0 is UP" + else + log -deb "$fn_name - Interface eth0 is DOWN, bringing it UP" + wait_for_function_response 0 "ifconfig eth0 up" && + log -deb "$fn_name - Interface eth0 brought UP" || + raise "Failed to bring up interface eth0" -l "$fn_name" -ds + fi + + interface_is_up eth0.4 + if [ "$?" = 0 ]; then + log -deb "$fn_name - Interface eth0.4 is UP" + else + log -deb "$fn_name - Interface eth0.4 is DOWN, bringing it UP" + ifconfig eth0.4 up && + log -deb "$fn_name - Interface eth0.4 brought UP" || + log -deb "$fn_name - Failed to bring up interface eth0.4, checking udhcpc" + fi + + eth_04_address=$(interface_ip_address eth0.4) + if [ -z "$eth_04_address" ]; then + log -deb "$fn_name - Interface eth0.4 has no address, setting udhcpc" + log -deb "$fn_name - Running force address renew for eth0.4" + no_address=1 + while [ "$no_address" = 1 ]; do + log -deb "$fn_name - Killing old eth0.4 udhcpc pids" + dhcpcd_pids=$(pgrep -f "/sbin/udhcpc .* eth0.4") + kill $dhcpcd_pids && + log -deb "$fn_name - eth0.4 udhcpc pids killed" || + log -deb "$fn_name - No eth0.4 udhcpc pid to kill" + log -deb "$fn_name - Starting udhcpc on eth0.4" + /sbin/udhcpc -f -S -i eth0.4 -C -o -O subnet &>/dev/null & + log -deb "$fn_name - Waiting for eth0.4 address" + wait_for_function_response notempty 'interface_ip_address eth0.4' && + log -deb "$fn_name - eth0.4 address valid" && break || + log -deb "$fn_name - Failed to set eth0.4 address, repeating" + done + else + log -deb "$fn_name - Interface eth0.4 address is $eth_04_address" + fi +} + + +print_tables() +{ + fn_name="unit_lib:print_tables" + for table in "$@" + do + log -deb "$fn_name - OVSDB table - $table" + ${OVSH} s "$table" + done + return 0 +} + +############################################ OVSDB SECTION - STOP ###################################################### + +add_ovs_bridge() +{ + fn_name="${lib_name}:add_ovs_bridge" + [ $# -ge 1 -a $# -le 3 ] || raise "${fn_name} requires 1-3 input arguments" -arg + bridge_name=$1 + hwaddr=$2 + bridge_mtu=$3 + + if [ -z "${bridge_name}" ]; then + raise "Empty first input argument: bridge_name" -l "${fn_name}" -arg + fi + log -deb "${fn_name} - Add bridge ${bridge_name}" + ovs-vsctl br-exists ${bridge_name} + if [ $? = 2 ]; then + ovs-vsctl add-br ${bridge_name} && + log -deb "${fn_name} - Success: ovs-vsctl add-br ${bridge_name}" || + raise "Failed: ovs-vsctl add-br ${bridge_name}" -l "${fn_name}" -ds + else + log -deb "${fn_name} - Bridge ${bridge_name} already exists" + fi + + # Set hwaddr if provided + if [ -z "${hwaddr}" ]; then + return 0 + else + log -deb "${fn_name} - Set bridge hwaddr ${hwaddr}" + ovs-vsctl set bridge ${bridge_name} other-config:hwaddr="${hwaddr}" && + log -deb "${fn_name} - Success: set bridge hwaddr" || + raise "Failed: set bridge hwaddr" -l "${fn_name}" -ds + fi + + # Set mtu if provided + if [ -z "${bridge_mtu}" ]; then + return 0 + else + log -deb "${fn_name} - Set bridge mtu ${bridge_mtu}" + ovs-vsctl set int ${bridge_name} mtu_request=${bridge_mtu} && + log -deb "${fn_name} - Success: set bridge mtu" || + raise "Failed: set bridge mtu" -l "${fn_name}" -ds + fi + + return 0 +} + +add_bridge_interface() +{ + fn_name="unit_lib:add_bridge_interface" + br_name=$1 + br_if_name=$2 + + log -deb "$fn_name - Adding $br_name - $br_if_name" + + ovs-vsctl br-exists "$br_name" + + if [ "$?" = 2 ]; then + ovs-vsctl add-br "$br_name" && + log -deb "$fn_name - Success: ovs-vsctl add-br $br_name" || + raise "Failed: ovs-vsctl add-br $br_name" -l "$fn_name" -ds + else + log -deb "$fn_name - Bridge $br_name already exists" + return 0 + fi + + # If only bridge is specified, stop here + if [ -z "$br_if_name" ]; then + return 0 + fi + + # If also interface is specified, add it to bridge + log -deb "$fn_name - Linking $br_name - $br_if_name - $br_mac" + mac_if=$(mac_get "$br_if_name") && + log -deb "$fn_name - Success: mac_get $br_if_name" || + raise "Failed to get interface $br_if_name MAC address" -l "$fn_name" -ds + + if [ "$br_name" = "br-home" ]; then + br_mac=$(printf "%02X:%s" $(( 0x${mac_if%%:*} | 0x2 )) "${mac_if#*:}") + else + br_mac=$mac_if + fi + + ovs-vsctl set bridge "$br_name" other-config:hwaddr="$br_mac" && + log -deb "$fn_name - Success: ovs-vsctl set bridge $br_name other-config:hwaddr=$br_mac" || + raise "Failed: ovs-vsctl set bridge $br_name other-config:hwaddr=$br_mac" -l "$fn_name" -ds + + ovs-vsctl set int "$br_name" mtu_request=1500 && + log -deb "$fn_name - Success: ovs-vsctl set int $br_name mtu_request=1500" || + raise "Failed: ovs-vsctl set int $br_name mtu_request=1500" -l "$fn_name" -ds +} + +add_bridge_port() +{ + fn_name="unit_lib:add_bridge_port" + [ $# -ne 2 ] && raise "${fn_name} requires 2 input arguments" -arg + bridge_name=$1 + port_name=$2 + + [ -z "${bridge_name}" ] && raise "Empty input argument" -l "${fn_name}" -arg + log -deb "$fn_name - Adding bridge port ${port_name} to ${bridge_name}" + ovs-vsctl br-exists ${bridge_name} + if [ $? = 2 ]; then + raise "Failed: bridge ${bridge_name} does not exits" -l "${fn_name}" -ds + fi + ovs-vsctl list-ports "${bridge_name}" | grep -qwF "${port_name}" + if [ $? = 0 ]; then + log -deb "$fn_name - Port ${port_name} already in bridge ${bridge_name}" + return 0 + else + ovs-vsctl add-port "${bridge_name}" "${port_name}" && + log -deb "$fn_name - Success: ovs-vsctl add-port ${bridge_name} ${port_name}" || + raise "Failed: ovs-vsctl add-port ${bridge_name} ${port_name}" -l $fn_name -ds + fi +} + +remove_bridge_interface() +{ + fn_name="unit_lib:remove_bridge_interface" + br_name=$1 + + ovs-vsctl del-br "$br_name" && + log -deb "$fn_name - Success: ovs-vsctl del-br $br_name" || + raise "Failed: ovs-vsctl del-br $br_name" -l "$fn_name" -ds +} + +set_interface_patch() +{ + fn_name="unit_lib:set_interface_patch" + if_name=$1 + patch=$2 + peer=$3 + + ovs-vsctl set interface "$patch" type=patch && + log -deb "$fn_name - Success: ovs-vsctl set interface $patch type=patch" || + raise "Failed ovs-vsctl set interface $patch type=patch" -l "$fn_name" -ds + + ovs-vsctl set interface "$patch" options:peer="$peer" && + log -deb "$fn_name - Success: ovs-vsctl set interface $patch options:peer=$peer" || + raise "Failed ovs-vsctl set interface $patch options:peer=$peer" -l "$fn_name" -ds +} + +check_if_port_in_bridge() +{ + fn_name="unit_lib:check_if_port_in_bridge" + if_name=$1 + br_name=$2 + + ovs-vsctl list-ports "$br_name" | grep -q "$if_name" + + if [ "$?" = 0 ]; then + log -deb "$fn_name - Port $if_name exists on $br_name" + return 0 + else + log -deb "$fn_name - Port $if_name does not exist on $br_name" + return 1 + fi +} + +######################################### FUT CLOUD SECTION - START #################################################### + + +connect_to_fut_cloud() +{ + fn_name="unit_lib:connect_to_fut_cloud" + target=${1:-"192.168.200.1"} + port=${2:-"443"} + cert_dir=${3:-"$FUT_TOPDIR/shell/tools/device/files"} + ca_fname=${4:-"fut_ca.pem"} + inactivity_probe=30000 + + log -deb "$fn_name - Configure certificates, check if file exists" + test -f "$cert_dir/$ca_fname" || + raise "FAILED: file $cert_dir/$ca_fname NOT found" -l "$fn_name" -ds + + update_ovsdb_entry SSL -u ca_cert "$cert_dir/$ca_fname" + log -deb "$fn_name - SSL ca_cert set to $cert_dir/$ca_fname" || + raise "SSL ca_cert NOT set to $cert_dir/$ca_fname" -l "$fn_name" -ds + + # Remove redirector, to not interfere with the flow + update_ovsdb_entry AWLAN_Node -u redirector_addr '' + log -deb "$fn_name - AWLAN_Node redirector_addr set to ''" || + raise "AWLAN_Node redirector_addr NOT set to ''" -l "$fn_name" -ds + + # Inactivity probe sets the timing of keepalive packets + update_ovsdb_entry Manager -u inactivity_probe $inactivity_probe && + log -deb "$fn_name - Manager inactivity_probe set to $inactivity_probe" || + raise "Manager inactivity_probe NOT set to $inactivity_probe" -l "$fn_name" -ds + + # AWLAN_Node::manager_addr is the controller address, provided by redirector + update_ovsdb_entry AWLAN_Node -u manager_addr "ssl:$target:$port" && + log -deb "$fn_name - AWLAN_Node manager_addr set to ssl:$target:$port" || + raise "AWLAN_Node manager_addr NOT set to ssl:$target:$port" -l "$fn_name" -ds + + # CM should ideally fill in Manager::target itself + update_ovsdb_entry Manager -u target "ssl:$target:$port" + log -deb "$fn_name - Manager target set to ssl:$target:$port" || + raise "Manager target NOT set to ssl:$target:$port" -l "$fn_name" -ds + + log -deb "$fn_name - Waiting for cloud status to go to ACTIVE" + wait_cloud_state ACTIVE && + log -deb "$fn_name - Manager cloud status is set to ACTIVE. Connected to FUT cloud." || + raise "FAIL: Manager cloud state is NOT ACTIVE. NOT connected to FUT cloud." -l "$fn_name" -ds +} + +wait_cloud_state() +{ + wait_for_cloud_state=$1 + fn_name="cm2_lib:wait_cloud_state" + log -deb "$fn_name - Waiting for cloud state $wait_for_cloud_state" + wait_for_function_response 0 "${OVSH} s Manager status -r | grep -q \"$wait_for_cloud_state\"" && + log -deb "$fn_name - Cloud state is $wait_for_cloud_state" || + raise "Manager - {status:=$wait_for_cloud_state}" -l "$fn_name" -ow + print_tables Manager +} + +######################################### FUT CLOUD SECTION - STOP ##################################################### + + +########################################## FUT CMD SECTION - START ##################################################### + +########################################## FUT CMD SECTION - STOP ###################################################### diff --git a/src/fut/shell/lib/ut_lib.sh b/src/fut/shell/lib/ut_lib.sh new file mode 100755 index 00000000..5ee14b61 --- /dev/null +++ b/src/fut/shell/lib/ut_lib.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source ${FUT_TOPDIR}/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Upgrade Manager functions (Plume specific) +# +############################################ INFORMATION SECTION - STOP ################################################ + + +############################################ SETUP SECTION - START ##################################################### + +ut_setup_test_environment() +{ + log -deb "UT SETUP" + + stop_healthcheck || + die "lib/um_lib: ut_setup_test_environment - Failed stop_healthcheck" + + cm_disable_fatal_state || + die "lib/cm2_lib: ut_setup_test_environment - Failed: cm_disable_fatal_state" + + # Ignoring failures + /etc/init.d/manager restart || true +} + +############################################ SETUP SECTION - STOP ###################################################### diff --git a/src/fut/shell/lib/wm2_lib.sh b/src/fut/shell/lib/wm2_lib.sh new file mode 100755 index 00000000..4bf6b61d --- /dev/null +++ b/src/fut/shell/lib/wm2_lib.sh @@ -0,0 +1,892 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source "${FUT_TOPDIR}/shell/config/default_shell.sh" +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +############################################ INFORMATION SECTION - START ############################################### +# +# Base library of common Wireless Manager functions +# +############################################ INFORMATION SECTION - STOP ################################################ + + +############################################ SETUP SECTION - START ##################################################### + +start_qca_hostapd() +{ + fn_name="wm2_lib:start_qca_hostapd" + log -deb "$fn_name - Starting qca-hostapd" + /etc/init.d/qca-hostapd boot + sleep 2 +} + +start_qca_wpa_supplicant() +{ + fn_name="wm2_lib:start_qca_wpa_supplicant" + log -deb "$fn_name - Starting qca-wpa-supplicant" + /etc/init.d/qca-wpa-supplicant boot + sleep 2 +} + +start_wireless_driver() +{ + fn_name="wm2_lib:start_wireless_driver" + start_qca_hostapd || + raise "start_qca_hostapd" -l "$fn_name" -ds + start_qca_wpa_supplicant || + raise "start_qca_wpa_supplicant" -l "$fn_name" -ds +} + +wm_setup_test_environment() +{ + fn_name="wm2_lib:wm_setup_test_environment" + log -deb "$fn_name - WM2 SETUP" + + device_init || + raise "device_init" -l "$fn_name" -ds + + start_openswitch || + raise "start_openswitch" -l "$fn_name" -ds + + start_wireless_driver || + raise "start_wireless_driver" -l "$fn_name" -ds + + start_specific_manager wm || + raise "start_specific_manager wm" -l "$fn_name" -ds + + empty_ovsdb_table AW_Debug || + raise "empty_ovsdb_table AW_Debug" -l "$fn_name" -ds + + set_manager_log WM TRACE || + raise "set_manager_log WM TRACE" -l "$fn_name" -ds + + vif_clean || + raise "vif_clean" -l "$fn_name" -ow + + for if_name in "$@" + do + wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is if_name "$if_name" || + raise "wait_ovsdb_entry" -l "$fn_name" -tc + done + +} +############################################ SETUP SECTION - STOP ###################################################### + +############################################ VIF SECTION - START ####################################################### + +# Clear all existing VIF interfaces +vif_clean() +{ + fn_name="wm2_lib:vif_clean" + log -deb "$fn_name - Purging VIF" + + empty_ovsdb_table Wifi_VIF_Config || + raise "empty_ovsdb_table" -l "$fn_name" -oe + + wait_for_empty_ovsdb_table Wifi_VIF_State || + raise "wait_for_empty_ovsdb_table" -l "$fn_name" -ow +} + +############################################ VIF SECTION - STOP ####################################################### + + +############################################ RADIO SECTION - START ##################################################### + +configure_radio_interface() +{ + radio_args="" + replace="func_arg" + fn_name="wm2_lib:configure_radio_interface" + while [ -n "${1}" ]; do + option=${1} + shift + case "${option}" in + -if_name) + radio_if_name=${1} + radio_args="${radio_args} ${replace} ${option#?} ${1}" + shift + ;; + -channel_mode | \ + -fallback_parents | \ + -ht_mode | \ + -hw_mode | \ + -tx_chainmask | \ + -tx_power | \ + -enabled) + radio_args="${radio_args} ${replace} ${option#?} ${1}" + shift + ;; + -country) + country_arg="${replace} ${option#?} ${1}" + radio_args="${radio_args} ${replace} ${option#?} ${1}" + shift + ;; + -channel) + channel_arg="${replace} ${option#?} ${1}" + radio_args="${radio_args} ${replace} ${option#?} ${1}" + check_is_channel_ready_for_use "${1}" "$radio_if_name" && + log "$fn_name - Channel ${1} is ready for use on $radio_if_name" || + raise "Channel ${1} is not ready for use on $radio_if_name" -l "$fn_name" -ds + shift + ;; + esac + done + + # Perform action configure Radio + [ -z ${radio_if_name} ] && raise "Radio interface name argument empty" -l "${fn_name}" -arg + check_ovsdb_entry Wifi_Radio_Config -w if_name "${radio_if_name}" + [ $? -eq 0 ] || raise "Radio interface does not exits" -l "${fn_name}" -ds + log -deb "$fn_name - Configuring radio interface" + func_params=${radio_args//${replace}/-u} + update_ovsdb_entry Wifi_Radio_Config -w if_name "$radio_if_name" $func_params && + log -deb "$fn_name - Success update_ovsdb_entry Wifi_Radio_Config -w if_name $radio_if_name $func_params" || + raise "Failure update_ovsdb_entry Wifi_Radio_Config -w if_name $radio_if_name $func_params" -l "$fn_name" -oe + + # Do not check channel, as we do not know if VAPS exist on radio + func_params=${radio_args//$channel_arg/""} + # WAR: country does not show up in state, remove from verification args + func_params=${func_params//$country_arg/""} # WAR: remove asap + # Validate action configure Radio + func_params=${func_params//$replace/-is} + wait_ovsdb_entry Wifi_Radio_State -w if_name "$radio_if_name" $func_params && + log -deb "$fn_name - Success wait_ovsdb_entry Wifi_Radio_State -w if_name $radio_if_name $func_params" || + raise "Failure wait_ovsdb_entry Wifi_Radio_State -w if_name $radio_if_name $func_params" -l "$fn_name" -ow +} + +create_vif_interface() +{ + vif_args_c="" + vif_args_w="" + replace="func_arg" + fn_name="wm2_lib:create_vif_interface" + while [ -n "${1}" ]; do + option=${1} + shift + case "${option}" in + -radio_if_name) + radio_if_name=${1} + shift + ;; + -if_name) + vif_if_name=${1} + vif_args_c="${vif_args_c} ${replace} ${option#?} "${1} + vif_args_w="${vif_args_w} ${replace} ${option#?} "${1} + shift + ;; + -ap_bridge | \ + -bridge | \ + -dynamic_beacon | \ + -mac_list_type | \ + -mac_list | \ + -parent | \ + -ssid_broadcast | \ + -ssid | \ + -vif_radio_idx | \ + -vlan_id | \ + -enabled) + vif_args_c="${vif_args_c} ${replace} ${option#?} "${1} + vif_args_w="${vif_args_w} ${replace} ${option#?} "${1} + shift + ;; + -mode) + wm2_mode=${1} + vif_args_c="${vif_args_c} ${replace} ${option#?} "${1} + vif_args_w="${vif_args_w} ${replace} ${option#?} "${1} + shift + ;; + -security) + vif_args_c="${vif_args_c} ${replace} ${option#?} "${1} + vif_args_w="${vif_args_w} -is_not ${option#?} [\"map\",[]]" + shift + ;; + -credential_configs) + vif_args_c="${vif_args_c} ${replace} ${option#?} "${1} + shift + ;; + -channel) + vif_args_w="${vif_args_w} ${replace} ${option#?} "${1} + check_is_channel_ready_for_use "${1}" "$radio_if_name" && + log "$fn_name - Channel ${1} is ready for use on $radio_if_name" || + raise "Channel ${1} is not ready for use on $radio_if_name" -l "$fn_name" -ds + shift + ;; + esac + done + + [ "$wm2_mode" = "sta" ] && remove_sta_connections "$vif_if_name" + + [ -z ${vif_if_name} ] && raise "Interface name argument empty" -l "${fn_name}" -arg + check_ovsdb_entry Wifi_VIF_Config -w if_name "${vif_if_name}" + if [ $? -eq 0 ]; then + log -deb "$fn_name - Updating existing VIF entry" + function_to_call="update_ovsdb_entry" + function_arg="-u" + else + log -deb "$fn_name - Creating VIF entry" + function_to_call="insert_ovsdb_entry2" + function_arg="-i" + fi + + # Perform action insert/update VIF + func_params=${vif_args_c//$replace/$function_arg} + $function_to_call Wifi_VIF_Config -w if_name "$vif_if_name" $func_params && + log -deb "$fn_name - Success $function_to_call Wifi_VIF_Config -w if_name $vif_if_name $func_params" || + raise "Failure Success $function_to_call Wifi_VIF_Config -w if_name $vif_if_name $func_params" -l "$fn_name" -oe + + # Mutate radio entry with VIF uuid + if [ "${function_to_call}" == "insert_ovsdb_entry2" ]; then + vif_uuid=$(get_ovsdb_entry_value Wifi_VIF_Config _uuid -w if_name "$vif_if_name" ) || + raise "get_ovsdb_entry_value" -l "$fn_name" -oe + ${OVSH} u Wifi_Radio_Config -w if_name==${radio_if_name} vif_configs:ins:'["set",[["uuid","'${vif_uuid//" "/}'"]]]' + fi + + # Validate action insert/update VIF + func_params=${vif_args_w//$replace/-is} + wait_ovsdb_entry Wifi_VIF_State -w if_name "$vif_if_name" $func_params && + log -deb "$fn_name - Success wait_ovsdb_entry Wifi_VIF_State -w if_name $vif_if_name $func_params" || + raise "Failure wait_ovsdb_entry Wifi_VIF_State -w if_name $vif_if_name $func_params" -l "$fn_name" -ow +} + +check_sta_associated() +{ + local fn_name="wm2_lib:check_sta_associated" + local vif_if_name=${1} + local fnc_retry_count=${2:-"5"} + local fnc_retry_sleep=${3:-"3"} + log -deb "$fn_name - Checking if $vif_if_name is associated" + # Makes sense if VIF mode==sta, search for "parent" field + fnc_str="get_ovsdb_entry_value Wifi_VIF_State parent -w if_name $vif_if_name -raw" + wait_for_function_output "notempty" "${fnc_str}" ${fnc_retry_count} ${fnc_retry_sleep} + if [ $? -eq 0 ]; then + parent_mac="$($fnc_str)" + if false; then # do not retrofit Wifi_VIF_Config with parent_mac + update_ovsdb_entry Wifi_VIF_Config -w if_name "$vif_if_name" -u parent "$parent_mac" + fi + log -deb "$fn_name - VIF ${vif_if_name} associated to parent MAC ${parent_mac}" + return 0 + else + log -deb "$fn_name - VIF ${vif_if_name} not associated, no parent MAC" + return 1 + fi +} + +create_radio_vif_interface() +{ + vif_args_c="" + vif_args_w="" + radio_args="" + replace="func_arg" + fn_name="wm2_lib:create_radio_vif_interface" + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -if_name) + radio_args="$radio_args $replace if_name $1" + wm2_if_name=$1 + shift + ;; + -vif_if_name) + vif_args_c="$vif_args_c $replace if_name $1" + vif_args_w="$vif_args_w $replace if_name $1" + wm2_vif_if_name=$1 + shift + ;; + -vif_radio_idx) + vif_args_c="$vif_args_c $replace vif_radio_idx $1" + vif_args_w="$vif_args_w $replace vif_radio_idx $1" + shift + ;; + -channel) + radio_args="$radio_args $replace channel $1" + vif_args_w="$vif_args_w $replace channel $1" + log "wm2/$(basename "$0"): Checking if channel $1 is ready for use?" + check_is_channel_ready_for_use "$1" "$wm2_if_name" && + log "wm2/$(basename "$0"): check_is_channel_ready_for_use - Channel $1 is ready for use" + shift + ;; + -channel_mode) + radio_args="$radio_args $replace channel_mode $1" + shift + ;; + -ht_mode) + radio_args="$radio_args $replace ht_mode $1" + shift + ;; + -hw_mode) + radio_args="$radio_args $replace hw_mode $1" + shift + ;; + -country) + radio_args="$radio_args $replace country $1" + country_arg="$replace country $1" + shift + ;; + -enabled) + radio_args="$radio_args $replace enabled $1" + vif_args_c="$vif_args_c $replace enabled $1" + vif_args_w="$vif_args_w $replace enabled $1" + shift + ;; + -mode) + vif_args_c="$vif_args_c $replace mode $1" + vif_args_w="$vif_args_w $replace mode $1" + wm2_mode=$1 + shift + ;; + -ssid) + vif_args_c="$vif_args_c $replace ssid $1" + vif_args_w="$vif_args_w $replace ssid $1" + shift + ;; + -ssid_broadcast) + vif_args_c="$vif_args_c $replace ssid_broadcast $1" + vif_args_w="$vif_args_w $replace ssid_broadcast $1" + shift + ;; + -security) + vif_args_c="$vif_args_c $replace security $1" + vif_args_w="$vif_args_w -is_not security [\"map\",[]]" + shift + ;; + -parent) + vif_args_c="$vif_args_c $replace parent $1" + vif_args_w="$vif_args_w $replace parent $1" + shift + ;; + -mac_list) + vif_args_c="$vif_args_c $replace mac_list $1" + vif_args_w="$vif_args_w $replace mac_list $1" + shift + ;; + -mac_list_type) + vif_args_c="$vif_args_c $replace mac_list_type $1" + vif_args_w="$vif_args_w $replace mac_list_type $1" + shift + ;; + -tx_chainmask) + radio_args="$radio_args $replace tx_chainmask $1" + shift + ;; + -tx_power) + radio_args="$radio_args $replace tx_power $1" + shift + ;; + -fallback_parents) + radio_args="$radio_args $replace fallback_parents $1" + shift + ;; + -ap_bridge) + vif_args_c="$vif_args_c $replace ap_bridge $1" + vif_args_w="$vif_args_w $replace if_name $1" + shift + ;; + -bridge) + vif_args_c="$vif_args_c $replace bridge $1" + vif_args_w="$vif_args_w $replace bridge $1" + shift + ;; + -dynamic_beacon) + vif_args_c="$vif_args_c $replace dynamic_beacon $1" + vif_args_w="$vif_args_w $replace dynamic_beacon $1" + shift + ;; + -vlan_id) + vif_args_c="$vif_args_c $replace vlan_id $1" + vif_args_w="$vif_args_w $replace vlan_id $1" + shift + ;; + esac + done + + log -deb "$fn_name - Bringing up radio/vif interface" + + func_params=${radio_args//$replace/-u} + update_ovsdb_entry Wifi_Radio_Config -w if_name "$wm2_if_name" $func_params && + log -deb "$fn_name - Table Wifi_Radio_Config updated" || + raise "Wifi_Radio_Config -> update" -l "$fn_name" -tc + + if [ "$wm2_mode" = "sta" ]; then + remove_sta_connections "$wm2_vif_if_name" + fi + + function_to_call="insert_ovsdb_entry" + function_arg="-i" + + ${OVSH} s Wifi_VIF_Config -w if_name=="$wm2_vif_if_name" && update=0 || update=1 + if [ "$update" -eq 0 ]; then + log -deb "$fn_name - VIF entry exists, updating instead" + function_to_call="update_ovsdb_entry" + function_arg="-u" + fi + + func_params=${vif_args_c//$replace/$function_arg} + $function_to_call Wifi_VIF_Config -w if_name "$wm2_vif_if_name" $func_params && + log -deb "$fn_name - $function_to_call Wifi_VIF_Config" || + raise "Failed $function_to_call" -l "$fn_name" -fc + + wm2_uuids=$(get_ovsdb_entry_value Wifi_VIF_Config _uuid -w if_name "$wm2_vif_if_name") || + raise "get_ovsdb_entry_value" -l "$fn_name" -oe + + wm2_vif_configs_set="[\"set\",[[\"uuid\",\"$wm2_uuids\"]]]" + + func_params=${radio_args//$replace/-u} + update_ovsdb_entry Wifi_Radio_Config -w if_name "$wm2_if_name" $func_params \ + -u vif_configs "$wm2_vif_configs_set" && + log -deb "$fn_name - Table Wifi_Radio_Config updated" || + raise "Wifi_Radio_Config -> update" -l "$fn_name" -oe + + func_params=${vif_args_w//$replace/-is} + wait_ovsdb_entry Wifi_VIF_State -w if_name "$wm2_vif_if_name" $func_params && + log -deb "$fn_name - Wifi_Radio/VIF_Config reflected to Wifi_VIF_State" || + raise "Wifi_Radio_Config -> Wifi_VIF_State" -l "$fn_name" -ow + + if [ -n "$country_arg" ]; then + radio_args=${radio_args//$country_arg/""} + fi + + func_params=${radio_args//$replace/-is} + wait_ovsdb_entry Wifi_Radio_State -w if_name "$wm2_if_name" $func_params && + log -deb "$fn_name - Wifi_Radio_Config reflected to Wifi_Radio_State" || + raise "Wifi_Radio_Config -> Wifi_Radio_State" -l "$fn_name" -ow + + if [ "$wm2_mode" = "sta" ]; then + wait_for_function_response "notempty" "get_ovsdb_entry_value Wifi_VIF_State parent -w if_name $wm2_vif_if_name" && parent_mac=0 || parent_mac=1 + if [ "$parent_mac" -eq 0 ]; then + parent_mac=$(get_ovsdb_entry_value Wifi_VIF_State parent -w if_name "$wm2_vif_if_name") + update_ovsdb_entry Wifi_VIF_Config -w if_name "$wm2_vif_if_name" \ + -u parent "$parent_mac" && + log -deb "$fn_name - VIF_State parent was associated" || + log -deb "$fn_name - VIF_State parent was not associated" + fi + fi + + log -deb "$fn_name - Wireless interface created" +} + +check_radio_vif_state() +{ + vif_args_c="" + vif_args_w="" + radio_args="" + replace="func_arg" + fn_name="wm2_lib:check_radio_vif_state" + + interface_is_up "$if_name" + + if [ "$?" -eq 0 ]; then + log -deb "$fn_name - Interface $if_name is up" + else + log -deb "$fn_name - Interface $if_name is not up" + return 1 + fi + + + while [ -n "$1" ]; do + option=$1 + shift + case "$option" in + -if_name) + radio_args="$radio_args $replace if_name $1" + shift + ;; + -vif_if_name) + vif_args="$vif_args $replace if_name $1" + wm2_vif_if_name=$1 + shift + ;; + -vif_radio_idx) + vif_args="$vif_args $replace vif_radio_idx $1" + shift + ;; + -ssid) + vif_args="$vif_args $replace ssid $1" + shift + ;; + -channel) + radio_args="$radio_args $replace channel $1" + vif_args="$vif_args $replace channel $1" + shift + ;; + -ht_mode) + radio_args="$radio_args $replace ht_mode $1" + shift + ;; + -hw_mode) + radio_args="$radio_args $replace hw_mode $1" + shift + ;; + -mode) + vif_args="$vif_args $replace mode $1" + shift + ;; + esac + done + + func_params=${radio_args//$replace/-w} + + check_ovsdb_entry Wifi_Radio_State $func_params && + log -deb "$fn_name - Wifi_Radio_State is valid for given configuration" || + ( + log -deb "$fn_name - VIF_State does not exist" && + return 1 + ) + + func_params=${vif_args//$replace/-w} + check_ovsdb_entry Wifi_VIF_State $func_params && + log -deb "$fn_name - Wifi_Radio_State is valid for given configuration" || + ( + log -deb "$fn_name - VIF_State does not exist" && + return 1 + ) +} + +check_channel_type() +{ + wm2_channel=$1 + wm2_if_name=$2 + wm2_channel_type=$3 + fn_name="wm2_lib:check_channel_type" + + log -deb "$fn_name - Checking if $wm2_channel is valid" + if ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" -r | grep -qF "\"$wm2_channel\""; then + log -deb "$fn_name - Channel $wm2_channel is VALID" + log -deb "$fn_name - Checking if channel $wm2_channel is DFS or NON DFS channel" + if ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" -r | grep -qF '["'$wm2_channel'","{\"state\":\"allowed\"}"]'; then + if [ "$wm2_channel_type" = "NON_DFS" ]; then + log -deb "$fn_name - Channel $wm2_channel is NON DFS - PROCEEDING to next step" + return 0 + fi + log -deb "$fn_name - Channel $wm2_channel is NON DFS - $wm2_channel_type expected - EXITING" + return 1 + else + if [ $wm2_channel_type = "DFS" ]; then + log -deb "$fn_name - Channel $wm2_channel is DFS - PROCEEDING to next step" + return 0 + fi + log -deb "$fn_name - Channel $wm2_channel is DFS - $wm2_channel_type expected - EXITING" + return 1 + fi + else + raise "Channel $wm2_channel NOT $wm2_channel_type" -l "$fn_name" -tc + fi +} + +check_channel_at_os_level() +{ + wm2_channel=$1 + wm2_vif_if_name=$2 + fn_name="wm2_lib:check_channel_at_os_level" + + log -deb "$fn_name - Checking channel at OS" + + wait_for_function_response 0 "iwlist $wm2_vif_if_name channel | grep -F \"Current\" | grep -qF \"(Channel $wm2_channel)\"" + + if [ $? = 0 ]; then + log -deb "$fn_name - Channel is set to $wm2_channel at OS level" + return 0 + fi + + raise "Channel is NOT set to $wm2_channel" -l "$fn_name" -tc +} + +check_ht_mode_at_os_level() +{ + wm2_ht_mode=$1 + wm2_vif_if_name=$2 + fn_name="wm2_lib:check_ht_mode_at_os_level" + + log -deb "$fn_name - Checking HT MODE at OS level" + + wait_for_function_response 0 "iwpriv $wm2_vif_if_name get_mode | grep -qF $wm2_ht_mode" + + if [ $? = 0 ]; then + log -deb "$fn_name - HT MODE: $wm2_ht_mode is SET at OS level" + return 0 + else + raise "HT MODE: $wm2_ht_mode is NOT set at OS" -l "$fn_name" -tc + fi + +} + +check_beacon_interval_at_os_level() +{ + wm2_bcn_int=$1 + wm2_vif_if_name=$2 + fn_name="wm2_lib:check_beacon_interval_at_os_level" + + log -deb "$fn_name - Checking BEACON INTERVAL at OS level" + + wait_for_function_response 0 "iwpriv $wm2_vif_if_name get_bintval | grep -qF get_bintval:$wm2_bcn_int" + if [ $? = 0 ]; then + log -deb "$fn_name - BEACON INTERVAL: $wm2_bcn_int is SET at OS level" + return 0 + else + raise "BEACON INTERVAL: $wm2_bcn_int is NOT set at OS" -l "$fn_name" -tc + fi + +} + +check_radio_mimo_config() +{ + wm2_tx_chainmask_max_value=$1 + wm2_if_name=$2 + fn_name="wm2_lib:check_radio_mimo_config" + + update_ovsdb_entry Wifi_Radio_Config -w if_name $wm2_if_name \ + -u tx_chainmask 0 || + raise "update_ovsdb_entry" -l "$fn_name" -tc + + wait_ovsdb_entry Wifi_Radio_State -w if_name "$wm2_if_name" \ + -is tx_chainmask "$wm2_tx_chainmask_max_value" && + log -deb "$fn_name - Max TX_CHAINMASK value is $wm2_tx_chainmask_max_value" || + raise "$wm2_tx_chainmask_max_value is not valid for this radio MIMO" -l "$fn_name" -tc + + mimo=$(get_ovsdb_entry_value Wifi_Radio_State tx_chainmask -w if_name "$wm2_if_name") + + case "$mimo" in + 3) + log -deb "$fn_name - Radio MIMO config is 2x2" + ;; + 7) + log -deb "$fn_name - Radio MIMO config is 3x3" + ;; + 15) + log -deb "$fn_name - Radio MIMO config is 4x4" + ;; + esac +} + +check_tx_chainmask_at_os_level() +{ + wm2_tx_chainmask=$1 + wm2_if_name=$2 + fn_name="wm2_lib:check_tx_chainmask_at_os_level" + + log -deb "$fn_name - Checking TX CHAINMASK at OS level" + + wait_for_function_response 0 "iwpriv $wm2_if_name get_txchainsoft | grep -qF get_txchainsoft:$wm2_tx_chainmask" + if [ $? = 0 ]; then + log -deb "$fn_name - TX CHAINMASK: $wm2_tx_chainmask is SET at OS level" + return 0 + else + wait_for_function_response 0 "iwpriv $wm2_if_name get_txchainmask | grep -qF get_txchainmask:$wm2_tx_chainmask" + if [ $? = 0 ]; then + log -deb "$fn_name - TX CHAINMASK: $wm2_tx_chainmask is SET at OS level" + return 0 + else + raise "TX CHAINMASK: $wm2_tx_chainmask is NOT set at OS" -l "$fn_name" -tc + fi + fi + +} + +check_tx_power_at_os_level() +{ + wm2_tx_power=$1 + wm2_if_name=$2 + fn_name="wm2_lib:check_tx_power_at_os_level" + + log -deb "$fn_name - Checking Tx-Power at OS level" + + wait_for_function_response 0 "iwconfig $wm2_if_name | grep -qE Tx-Power[:=]$wm2_tx_power" && + log -deb "$fn_name - Tx-Power: $wm2_tx_power is set at OS level" || + ( + iwconfig "$wm2_if_name" + return 1 + ) || raise "Tx-Power: $wm2_tx_power is NOT set at OS" -l "$fn_name" -tc +} + +check_country_at_os_level() +{ + wm2_country=$1 + wm2_if_name=$2 + fn_name="wm2_lib:check_country_at_os_level" + + log -deb "$fn_name - Checking COUNTRY at OS level" + + wait_for_function_response 0 "iwpriv $wm2_if_name getCountryID | grep -qF getCountryID:$wm2_country" + if [ $? = 0 ]; then + log -deb "$fn_name - COUNTRY: $wm2_country is SET at OS level" + return 0 + else + raise "COUNTRY: $wm2_country is NOT set at OS" -l "$fn_name" -tc + fi + +} + +check_is_channel_ready_for_use() +{ + wm2_channel=$1 + wm2_if_name=$2 + is_empty=false + fn_name="wm2_lib:check_is_channel_ready_for_use" + log -deb "$fn_name - Checking is CHANNEL $wm2_channel ready for IMMEDIATE use" + + wait_for_function_response "notempty" "get_ovsdb_entry_value Wifi_Radio_State channels -w if_name $wm2_if_name" || is_empty=true + + if [ "$is_empty" = "true" ]; then + log -deb "$fn_name - Table Wifi_Radio_State dump" + ${OVSH} s Wifi_Radio_State || true + raise "Field channels is empty in Wifi_Radio_State for $if_name" -l "$fn_name" -ds + fi + + if ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" -r | grep -qF '["'"$wm2_channel"'","{\"state\": \"cac_completed\"}"]'; then + log -deb "$fn_name - CHANNEL $wm2_channel is ready for USE - cac_finished" + return 0 + elif ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" -r | grep -qF '["'"$wm2_channel"'","{\"state\": \"nop_finished\"}"]'; then + log -deb "$fn_name - CHANNEL $wm2_channel is ready for USE - nop_finished" + return 0 + elif ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" -r | grep -qF '["'"$wm2_channel"'","{\"state\":\"allowed\"}"]'; then + log -deb "$fn_name - CHANNEL $wm2_channel is ready for USE - allowed" + return 0 + fi + + ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" || true + raise "CHANNEL $wm2_channel is NOT ready for USE" -l "$fn_name" -s +} + +check_is_cac_started() +{ + wm2_channel=$1 + wm2_if_name=$2 + fn_name="wm2_lib:check_is_cac_started" + + log -deb "$fn_name - Checking is CAC STARTED on CHANNEL $wm2_channel" + + if ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" -r | grep -qF '["'$wm2_channel'","{\"state\": \"cac_started\"}"]'; then + log -deb "$fn_name - CAC STARTED on CHANNEL $wm2_channel" + return 0 + fi + + ${OVSH} s Wifi_Radio_State channels -w if_name=="$wm2_if_name" || true + raise "CAC is NOT STARTED on CHANNEL" -l "$fn_name" -tc +} + +check_is_nop_finished() +{ + wm2_channel=$1 + wm2_if_name=$2 + fn_name="wm2_lib:check_is_nop_finished" + log -deb "$fn_name - Checking is NOP FINISHED on CHANNEL $wm2_channel" + + if ${OVSH} s Wifi_Radio_State channels -w if_name==$wm2_if_name -r | grep -qF '["'$wm2_channel'","{\"state\": \"nop_finished\"}"]'; then + log -deb "$fn_name - NOP FINISHED on CHANNEL $wm2_channel" + return 0 + elif + ${OVSH} s Wifi_Radio_State channels -w if_name==$wm2_if_name -r | grep -qF '["'$wm2_channel'","{\"state\":\"allowed\"}"]'; then + log -deb "$fn_name - CHANNEL $wm2_channel is ALLOWED" + return 0 + fi + + ${OVSH} s Wifi_Radio_State channels -w if_name==$wm2_if_name || true + raise "NOP is NOT FINISHED on CHANNEL" -l "$fn_name" -tc +} + +simulate_DFS_radar() +{ + wm2_if_name=$1 + fn_name="wm2_lib:simulate_DFS_radar" + log -deb "$fn_name - Triggering DFS radar event on wm2_if_name" + + wait_for_function_response 0 "radartool -i $wm2_if_name bangradar" + + if [ $? = 0 ]; then + log -deb "$fn_name - DFS event: $wm2_if_name simulation was SUCCESSFUL" + return 0 + else + log -err "$fn_name - DFS event: $wm2_if_name simulation was UNSUCCESSFUL" + fi +} +############################################ RADIO SECTION - STOP ###################################################### + + +############################################ STATION SECTION - START ################################################### + +remove_sta_connections() +{ + wm2_sta_if_name=$1 + fn_name="wm2_lib:remove_sta_connections" + log -deb "[DEPRECATED] - Function ${fn_name} is deprecated in favor of remove_sta_interfaces" + log -deb "$fn_name - Removing sta connections except $wm2_sta_if_name" + ${OVSH} d Wifi_VIF_Config -w if_name!="$wm2_sta_if_name" -w mode==sta || + raise "Failed to remove sta" -l "$fn_name" -oe +} + +remove_sta_interfaces() +{ + # Removes all STA interfaces, except for explicitly provided ones. + # Waits for system to react, or timeouts with error. + # Input arguments: + # wait_timeout: how long to wait for system to react (int, optional, default=DEFAULT_WAIT_TIME) + # wm2_sta_if_name: interface name to keep from removing (str, optional) + local wait_timeout=${1:-$DEFAULT_WAIT_TIME} + local wm2_sta_if_name=$2 + + local fn_name="wm2_lib:remove_sta_interfaces" + + if [ -n "${wm2_sta_if_name}" ]; then + log -deb "$fn_name - Removing STA interfaces except ${wm2_sta_if_name}" + ovs_cmd="-w mode==sta -w if_name!=${wm2_sta_if_name}" + else + log -deb "$fn_name - Removing all STA interfaces" + ovs_cmd="-w mode==sta" + fi + + ${OVSH} d Wifi_VIF_Config ${ovs_cmd} && + log -deb "$fn_name - Removed STA interfaces from Wifi_VIF_Config" || + raise "Failed to remove STA interfaces from Wifi_VIF_Config" -l "$fn_name" -oe + + wait_time=0 + while true ; do + log -deb "$fn_name - Waiting for Wifi_VIF_State table, retry $wait_time" + table_select=$(${OVSH} s Wifi_VIF_State ${ovs_cmd}) || true + if [ -z "$table_select" ]; then + log -deb "$fn_name - Removed STA interfaces from Wifi_VIF_State" + return 0 + fi + if [ $wait_time -gt $wait_timeout ]; then + raise "Failed to remove STA interfaces from Wifi_VIF_State" -l "$fn_name" -oe + fi + wait_time=$((wait_time+1)) + sleep 1 + done +} + +############################################ STATION SECTION - STOP #################################################### + + +############################################ DHCP SECTION - START ###################################################### + +############################################ DHCP SECTION - STOP ####################################################### diff --git a/src/fut/shell/tests/ut/unit.mk b/src/fut/shell/tests/ut/unit.mk new file mode 100644 index 00000000..279df5c8 --- /dev/null +++ b/src/fut/shell/tests/ut/unit.mk @@ -0,0 +1,34 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_ut + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/ut + +UNIT_FILE := ut_setup.sh diff --git a/src/fut/shell/tests/ut/ut_setup.sh b/src/fut/shell/tests/ut/ut_setup.sh new file mode 100755 index 00000000..b229876f --- /dev/null +++ b/src/fut/shell/tests/ut/ut_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for Unit Tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/ut_lib.sh +source ${LIB_OVERRIDE_FILE} + +tc_name="ut/$(basename "$0")" + +ut_setup_test_environment "$@" && + log "$tc_name: ut_setup_test_environment - Success " || + raise "ut_setup_test_environment - Failed" -l "$tc_name" -ds + +exit 0 diff --git a/src/fut/shell/tools/device/change_channel.sh b/src/fut/shell/tools/device/change_channel.sh new file mode 100755 index 00000000..c9cab8f2 --- /dev/null +++ b/src/fut/shell/tools/device/change_channel.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage="$(basename "$0") [-h] \$1 \$2 + +where arguments are: + if_name=\$1 -- if_name in Wifi_Radio_Config for which interface to change channel (string)(required) + channel=\$2 -- channel to set for if_name (int)(required) + +Script is used to set the channel for interface if_name in Wifi_Radio_Config table + +Script does following: + - update channel column in Wifi_Radio_Config table where if_name + - wait for changes to reflect into Wifi_Radio_State table + +Dependent on: + - running WM/NM managers - min_wm2_setup.sh - existance of active interfaces + +Example of usage: + $(basename "$0") wifi1 49 - change channel to 49 for interface if_name wifi1 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +if_name=$1 +channel=$2 + +change_channel "$if_name" "$channel" || + raise "change_channel - Failed" -l "tools/device/$(basename "$0")" -tc + +exit 0 diff --git a/src/fut/shell/tools/device/check_time.sh b/src/fut/shell/tools/device/check_time.sh new file mode 100755 index 00000000..0cd7241c --- /dev/null +++ b/src/fut/shell/tools/device/check_time.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# It is important for this particular testcase, to capture current time ASAP +time_now=$(date -u +"%s") + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +usage="$(basename "$0") [-h] + +Script is used to check device time synchonization. + +where options are: + -h show this help message +arguments: + time_ref=\$1 -- format: seconds since epoch. Used to compare system time. (int)(required) + accuracy=\$2 -- format: seconds. Allowed time deviation from reference time. (int)(required) +It is important to compare timestamps to the same time zone: UTC is used internally! + +example of usage: + reference_time=\$(date --utc +\"%s\") + /tmp/fut-base/shell/tools/$(basename "$0") \$reference_time +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Input parameters +if [[ $# -lt 1 ]]; then + echo 1>&2 "$0: incorrect number of input arguments" + echo "$usage" + exit 2 +fi + +time_ref=$1 +accuracy=5 +tc_name="tools/device/$(basename "$0")" + +# Timestamps in human readable format +time_ref_str=$(date -d @"${time_ref}") +time_now_str=$(date -d @"${time_now}") + +# Calculate time difference and ensure absolute value +time_diff=$(( time_ref - time_now )) +if [ $time_diff -lt 0 ]; then + time_diff=$(( -time_diff )) +fi + +log "$tc_name: Checking time ${time_now_str} against reference ${time_ref_str}" +if [ $time_diff -le "$accuracy" ]; then + log "$tc_name: Time difference ${time_diff}s is within ${accuracy}s" +else + log "$tc_name: Time difference ${time_diff}s is NOT within ${accuracy}s. Test might fail." +fi + +exit 0 diff --git a/src/fut/shell/tools/device/check_wifi_presence.sh b/src/fut/shell/tools/device/check_wifi_presence.sh new file mode 100755 index 00000000..b513c1f9 --- /dev/null +++ b/src/fut/shell/tools/device/check_wifi_presence.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source $LIB_DIR/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +# check_type options: +# - "Wifi_VIF_State" : default +# - "Wifi_Radio_State" +# - "client_connect" +# - "leaf_connect" + +check_type=${1:-Wifi_VIF_State} +enabled=${2:-true} +key=$3 +value=$4 + +log "tools/device/$(basename "$0"): Checking WiFi presence - check type: $check_type" + +case $check_type in + Wifi_VIF_State) + ${OVSH} s Wifi_VIF_State --where $key==$value enabled:=$enabled + [[ $? == 0 ]] && + log "tools/device/$(basename "$0"): WiFi is present"; exit $? || + log "tools/device/$(basename "$0"): WiFi is NOT present"; exit $? + ;; + Wifi_Radio_State) + ${OVSH} s Wifi_Radio_State --where $key==$value enabled:=$enabled + [[ $? == 0 ]] && + log "tools/device/$(basename "$0"): WiFi is present"; exit $? || + log "tools/device/$(basename "$0"): WiFi is NOT present"; exit $? + ;; + leaf_connect) + log "tools/device/$(basename "$0"): Not implemented. Pending implementation!" + exit 0 + ;; + client_connect) + log "tools/device/$(basename "$0"): Not implemented. Pending implementation!" + exit 0 + ;; + *) + log "tools/device/$(basename "$0"): Usage: $0 {Wifi_VIF_State|Wifi_Radio_State|client_connect}" + exit 1 +esac diff --git a/src/fut/shell/tools/device/connect_to_fut_cloud.sh b/src/fut/shell/tools/device/connect_to_fut_cloud.sh new file mode 100755 index 00000000..1ae0a755 --- /dev/null +++ b/src/fut/shell/tools/device/connect_to_fut_cloud.sh @@ -0,0 +1,135 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +log "tools/device/$(basename "$0"): Redirecting device to simulated cloud on RPI server" + +target=${1:-"192.168.200.1"} +port=${2:-"443"} +cert_dir=${3:-"${FUT_TOPDIR}/shell/tools/device/files"} +ca_fname=${4:-"fut_ca.pem"} + +wan_if="br-wan" +wan_port="eth0" + +# Ensure startup procedure +stop_wd_man_hc || + die "tools/device/$(basename "$0"): stop_wd_man_hc - Failed" + +start_openswitch || + die "tools/device/$(basename "$0"): start_openswitch - Failed" + +cm_disable_fatal_state || + die "tools/device/$(basename "$0"): cm_disable_fatal_state - Failed" + +# Ensure upstream connectivity +log "tools/device/$(basename "$0"): Create WAN bridge" +add_bridge_interface "$wan_if" "$wan_port" || + die "tools/device/$(basename "$0"): add_bridge_interface $wan_if $wan_port - Failed" + +log "tools/device/$(basename "$0"): Add interface to WAN bridge" +add_bridge_port "$wan_if" "$wan_port" || + die "tools/device/$(basename "$0"): add_bridge_port $wan_if $wan_port - Failed" + +log "tools/device/$(basename "$0"): Bring up interface $wan_if" +ifconfig "$wan_if" up || + die "tools/device/$(basename "$0"): Failed to bring up interface $wan_if" + +log "tools/device/$(basename "$0"): Check for dhcp client and WAN IP" +start_udhcpc "$wan_if" true || + die "tools/device/$(basename "$0"): start_udhcpc - Failed" + +log "Check for ${target} ping" +ping -c5 "$target" >/dev/null 2>&1 || + log "tools/device/$(basename "$0"): $wan_if did not get IP lease - Failed" + +start_specific_manager cm -v || + die "tools/device/$(basename "$0"): start_specific_manager cm - Failed" + +log "tools/device/$(basename "$0"): Configure certificates" +test -f "$cert_dir/$ca_fname" || die "tools/device/$(basename "$0"): file not found - Failed" + +update_ovsdb_entry SSL \ + -u ca_cert "$cert_dir/$ca_fname" + +log "Configure uplink information" +insert_ovsdb_entry Connection_Manager_Uplink \ + -i if_name "$wan_port" \ + -i if_type eth \ + -i has_L2 true \ + -i has_L3 true \ + -i priority 2 + +log "Make CM happy" +insert_ovsdb_entry Wifi_Master_State \ + -i if_name "$wan_port" \ + -i if_type eth \ + -i network_state up \ + -i port_state active \ + -i inet_addr 0.0.0.0 \ + -i netmask 0.0.0.0 + +insert_ovsdb_entry Wifi_Master_State \ + -i if_name "$wan_if" \ + -i if_type bridge \ + -i network_state up \ + -i port_state active \ + -i inet_addr 192.168.200.10 \ + -i netmask 255.255.255.0 + +# Inactivity probe sets the timing of keepalive packets +update_ovsdb_entry Manager \ + -u inactivity_probe 60000 + +for i in $(seq 1 3); do + # Remove redirector, to not interfere with the flow + update_ovsdb_entry AWLAN_Node \ + -u redirector_addr '' + # AWLAN_Node::manager_addr is the controller address, provided by redirector + update_ovsdb_entry AWLAN_Node \ + -u manager_addr "ssl:$target:$port" + # CM should ideally fill in Manager::target itself + update_ovsdb_entry Manager \ + -u target "ssl:$target:$port" + + # Ensure ovsdb connection is maintained + wait_cloud_state ACTIVE + + # If connection is maintained, succeed + test $? && break + done + +log "tools/device/$(basename "$0"): CM Connected to simulated Cloud" +exit 0 diff --git a/src/fut/shell/tools/device/connect_to_fut_cloud_min.sh b/src/fut/shell/tools/device/connect_to_fut_cloud_min.sh new file mode 100755 index 00000000..f3e6150f --- /dev/null +++ b/src/fut/shell/tools/device/connect_to_fut_cloud_min.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +log "tools/device/$(basename "$0"): Connect device to FUT Cloud on RPI server" + +connect_to_fut_cloud && + log "tools/device/$(basename "$0"): Device connected to FUT Cloud" || + die "tools/device/$(basename "$0"): Failed to connect to FUT Cloud" + +exit 0 diff --git a/src/fut/shell/tools/device/create_inet_interface.sh b/src/fut/shell/tools/device/create_inet_interface.sh new file mode 100755 index 00000000..f06fcb54 --- /dev/null +++ b/src/fut/shell/tools/device/create_inet_interface.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/nm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +log "tools/device/$(basename "$0"): Creating Inet entry" +create_inet_entry "$@" && + log "tools/device/$(basename "$0"): create_inet_entry - Success" || + raise "create_inet_entry - Failed" -l "tools/device/$(basename "$0")" -tc + +exit 0 diff --git a/src/fut/shell/tools/device/create_radio_vif_interface.sh b/src/fut/shell/tools/device/create_radio_vif_interface.sh new file mode 100755 index 00000000..3de2b430 --- /dev/null +++ b/src/fut/shell/tools/device/create_radio_vif_interface.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +log "tools/device/$(basename "$0"): create_radio_vif_interface - Bringing up interface" + +create_radio_vif_interface "$@" && + log "tools/device/$(basename "$0"): create_radio_vif_interface - Success" || + raise "create_radio_vif_interface - Failed" -l "tools/device/$(basename "$0")" -tc + +exit 0 diff --git a/src/fut/shell/tools/device/default_setup.sh b/src/fut/shell/tools/device/default_setup.sh new file mode 100755 index 00000000..f3c281ab --- /dev/null +++ b/src/fut/shell/tools/device/default_setup.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + +tc_name="tools/device/$(basename $0)" +help() +{ +cat << EOF +${tc_name} [-h] + +This script returns the device into a default state, that should be equal to the state right after boot. +EOF +raise "Printed help" -l "$tc_name" -arg +} + +while getopts h option; do + case "$option" in + h) + help + ;; + esac +done + + +log "${tc_name}: Device Default Setup" + +cm_disable_fatal_state && + log -deb "${tc_name} Success: cm_disable_fatal_state" || + raise "Failed: cm_disable_fatal_state" -l "${tc_name}" -ds + +disable_watchdog && + log -deb "${tc_name} Success: disable_watchdog" || + raise "Failed: disable_watchdog" -l "${tc_name}" -ds + +stop_healthcheck && + log -deb "${tc_name} Success: stop_healthcheck" || + raise "Failed: stop_healthcheck" -l "${tc_name}" -ds + +restart_managers +log -deb "${tc_name}: Executed restart_managers, exit code: $?" + +exit 0 diff --git a/src/fut/shell/tools/device/dut_ref/add_bridge.sh b/src/fut/shell/tools/device/dut_ref/add_bridge.sh new file mode 100755 index 00000000..ae9aa03c --- /dev/null +++ b/src/fut/shell/tools/device/dut_ref/add_bridge.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +br_name=$1 +br_if=${2:-""} + +log "tools/device/dut_ref/$(basename "$0"): Adding bridge $br_name on $br_if" + +add_bridge_interface $br_name $br_if && + log "tools/device/dut_ref/$(basename "$0"): add_bridge_interface - Success" || + die "tools/device/dut_ref/$(basename "$0"): add_bridge_interface - Failed" + +exit 0 diff --git a/src/fut/shell/tools/device/dut_ref/add_bridge_port.sh b/src/fut/shell/tools/device/dut_ref/add_bridge_port.sh new file mode 100755 index 00000000..ff1ddbff --- /dev/null +++ b/src/fut/shell/tools/device/dut_ref/add_bridge_port.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +br_name=$1 +br_port=$2 + +log "tools/device/dut_ref/$(basename "$0"): Adding bridge $br_name on $br_port" + +add_bridge_port $br_name $br_port && + log "tools/device/dut_ref/$(basename "$0"): add_bridge_port - Success" || + die "tools/device/dut_ref/$(basename "$0"): add_bridge_port - Failed" + +exit 0 diff --git a/src/fut/shell/tools/device/dut_ref/gre_setup.sh b/src/fut/shell/tools/device/dut_ref/gre_setup.sh new file mode 100755 index 00000000..fcb714bf --- /dev/null +++ b/src/fut/shell/tools/device/dut_ref/gre_setup.sh @@ -0,0 +1,88 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/nm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +if_name=$1 +if_role=$2 + +log "tools/device/dut_ref/$(basename "$0"): $if_role GRE Setup" + +if [ "$if_role" == "gw" ]; then + wait_for_function_response 'notempty' "cat /tmp/dhcp.leases | awk '{print $3}'" + gre_remote_inet_addr=$(cat /tmp/dhcp.leases | awk '{print $3}') + gre_if_name="pgd$(echo ${gre_remote_inet_addr//./-}| cut -d'-' -f3-4)" + gre_local_inet_addr=$(ovsh s Wifi_Inet_Config -w if_name=="$if_name" inet_addr -r) + + add_bridge_port br-home "$gre_if_name" +elif [ "$if_role" == "leaf" ]; then + gre_if_name="g-${if_name}" + gre_local_inet_addr=$(ifconfig "${if_name}" | grep "inet addr:" | awk '{print $2}' | cut -d':' -f2) + gw_ap_subnet=$(${OVSH} s Wifi_Route_State -w if_name=="$if_name" dest_addr -r) + gre_remote_inet_addr="$(echo "$gw_ap_subnet" | cut -d'.' -f1-3).$(( $(echo "$gw_ap_subnet" | cut -d'.' -f4) +1 ))" + + add_bridge_port br-wan "$gre_if_name" +else + die "tools/device/dut_ref/$(basename "$0"): Wrong if_role provided" +fi + +create_inet_entry \ + -if_name "$gre_if_name" \ + -network true \ + -enabled true \ + -if_type gre \ + -ip_assign_scheme none \ + -mtu 1500 \ + -gre_ifname "$if_name" \ + -gre_remote_inet_addr "$gre_remote_inet_addr" \ + -gre_local_inet_addr "$gre_local_inet_addr" && + log "tools/device/dut_ref/$(basename "$0"): Gre interface $gre_if_name created" || + die "tools/device/dut_ref/$(basename "$0"): Failed to create Gre interface $gre_if_name" + +add_bridge_port br-wan patch-w2h && + log "tools/device/dut_ref/$(basename "$0"): Success - add_bridge_port br-wan patch-w2h" || + die "tools/device/dut_ref/$(basename "$0"): Failed - add_bridge_port br-wan patch-w2h" + +add_bridge_port br-home patch-h2w && + log "tools/device/dut_ref/$(basename "$0"): Success - add_bridge_port br-wan patch-h2w" || + die "tools/device/dut_ref/$(basename "$0"): Failed - add_bridge_port br-wan patch-h2w" + +set_interface_patch patch-w2h patch-h2w patch-w2h && + log "tools/device/dut_ref/$(basename "$0"): Success - set_interface_patch patch-w2h patch-h2w" || + die "tools/device/dut_ref/$(basename "$0"): Failed - set_interface_patch patch-w2h patch-h2w" + +set_interface_patch patch-h2w patch-w2h patch-h2w && + log "tools/device/dut_ref/$(basename "$0"): Success - set_interface_patch patch-h2w patch-w2h" || + die "tools/device/dut_ref/$(basename "$0"): Failed - set_interface_patch patch-h2w patch-w2h" + +exit 0 diff --git a/src/fut/shell/tools/device/dut_ref/initial_setup.sh b/src/fut/shell/tools/device/dut_ref/initial_setup.sh new file mode 100755 index 00000000..909d24c3 --- /dev/null +++ b/src/fut/shell/tools/device/dut_ref/initial_setup.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +log "tools/device/dut_ref/$(basename "$0"): GW Setup" + +log "tools/device/dut_ref/$(basename "$0"): Running device_init" +device_init && + log "tools/device/dut_ref/$(basename "$0"): device_init - Success" || + die "tools/device/dut_ref/$(basename "$0"): device_init - Failed" + +log "tools/device/dut_ref/$(basename "$0"): Running start_openswitch" +start_openswitch && + log "tools/device/dut_ref/$(basename "$0"): start_openswitch - Success" || + die "tools/device/dut_ref/$(basename "$0"): start_openswitch - Failed" + +log "tools/device/dut_ref/$(basename "$0"): Running start_wireless_driver" +start_wireless_driver && + log "tools/device/dut_ref/$(basename "$0"): start_wireless_driver - Success" || + die "tools/device/dut_ref/$(basename "$0"): start_wireless_driver - Failed" + +log "tools/device/dut_ref/$(basename "$0"): Starting WM manager" +start_specific_manager wm && + log "tools/device/dut_ref/$(basename "$0"): WM manager started" || + die "tools/device/dut_ref/$(basename "$0") - start_specific_manager wm - Failed" + +log "tools/device/dut_ref/$(basename "$0"): Starting NM manager" +start_specific_manager nm && + log "tools/device/dut_ref/$(basename "$0"): NM manager started" || + die "tools/device/dut_ref/$(basename "$0") - start_specific_manager nm - Failed" + +empty_ovsdb_table AW_Debug || + die "tools/device/dut_ref/$(basename "$0"): empty_ovsdb_table AW_Debug - Failed" + +set_manager_log WM TRACE || + die "tools/device/dut_ref/$(basename "$0"): set_manager_log WM TRACE - Failed" + +set_manager_log NM TRACE || + die "tools/device/dut_ref/$(basename "$0"): set_manager_log NM TRACE - Failed" + +exit 0 diff --git a/src/fut/shell/tools/device/dut_ref/unit.mk b/src/fut/shell/tools/device/dut_ref/unit.mk new file mode 100644 index 00000000..f07ac36e --- /dev/null +++ b/src/fut/shell/tools/device/dut_ref/unit.mk @@ -0,0 +1,37 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_dut_ref_tools + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/device/dut_ref + +UNIT_FILE := add_bridge_port.sh +UNIT_FILE += add_bridge.sh +UNIT_FILE += gre_setup.sh +UNIT_FILE += initial_setup.sh diff --git a/src/fut/shell/tools/device/files/fut_ca.pem b/src/fut/shell/tools/device/files/fut_ca.pem new file mode 100644 index 00000000..81a59ad0 --- /dev/null +++ b/src/fut/shell/tools/device/files/fut_ca.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFtjCCA56gAwIBAgIJANHraQLcwSsGMA0GCSqGSIb3DQEBCwUAMHAxCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJDQTEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4x +IjAgBgNVBAsMGUZVVCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFDASBgNVBAMMC0ZV +VCBSb290IENBMB4XDTcwMDEwMTAwMDAwMFoXDTM1MDEwMTAwMDAwMFowcDELMAkG +A1UEBhMCVVMxCzAJBgNVBAgMAkNBMRowGAYDVQQKDBFQbHVtZSBEZXNpZ24gSW5j +LjEiMCAGA1UECwwZRlVUIENlcnRpZmljYXRlIEF1dGhvcml0eTEUMBIGA1UEAwwL +RlVUIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0bsOS +h0qYopNmTI0mFeR1tQvpL+a8TR6nmHKb00QeX6XXhb2EgJpPuxI+8sV+gh9SOwFl +2j5ozFID+BA2FH41GiNCNVVurV7xbW39/4oe1WVpbkkR9tSCnECsms1xMiLfH9Hs +XrsD9v2WDczhXoHakF4T1//fn3+OqrYUHiAI2wdQUqZYh55AWY0n1oNVJ/GlSUBW +ZqD/xe8xz0ZmxNE57swXtyYC7dDRO09DCWFSsLfd9PK9ohgNGp0oKlVeQogpM1Qf +nQNnzFjUffi8GTUZdce4+o+Q0sTOoucqFxyEXkNFmGtuVkAG3fL6sMq03w1iLDBs +7RkxWSFwL3VhM0L5kJ9ZW7nYnc61i/Va/k0Aj0Uwj+zJMKDQlWTyI5tTd+RRnEXm +WHQNZZ5d+BKcOlDT8Q0VJttC5WUMEhuEVKw1gghClBoQJhKmhOkNvgMyuwYJAgnZ +GXsEEWegUEJtlIoIEw7ztflZrL5ohl0fidBZS6RrlsktDz+wTOqykVTUeD8Q4n1W +s0vSYKRuWp/99RvZBW61NP+OFm8wk1lgvTR2FiwWJUqUy24cd5T/83ykUHEffhG7 +/uTsq2dE8rrcAQkBKPyWlilQadjHoJcjF4l2xcWtoJByAuyNKgD9tG34nfnMb4vu +wYuGUU2g4CjnUjCROHBbrDBujsN2k69j8mnJowIDAQABo1MwUTAdBgNVHQ4EFgQU +G5SceRGGaTvFg7pKHH9/YUVA5j4wHwYDVR0jBBgwFoAUG5SceRGGaTvFg7pKHH9/ +YUVA5j4wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAPRXTOPz8 +A1ua9pNwII1sK+DwSkQOxsnD6nkrbTkgLIQlPS0qgEzYh29nySDTXqpa1QV6A0E3 +PMOdZ5tfU/ZYepaJT6346bXzH9mb85zjNAIZrWxHKq/ptGJl8karkNftw/CuGOVi +WZ4am6L5YQu8lmxfbwWrHSJ++54BkoQ4Gih3JH+JngDqFBiq6eIejTEa+wiZgvIy +r/iJLUIHHzggtW13YUM/dfhvCVGagUZlEybCixPErUpvSsRLHoQHDc47ZtT/rIRZ +cNRdsgUR4LpmbdrPkbxYYe2nkSjflZf9h4sOfmG0qAgwHSgch5haW8pPX1cIEZUx +qw1yQezlHVKbjrQl7FtmLaItAwhzPvnMkFyuGI3tXy+YE8hbaqLlY46bI0XDxCMJ +gPcgs64R9GB1nYZgmsD3Z34uf9pOpDyemIMVKQ+8cJ5sdJaAkXV0C09xLz18Ekhg +Jh4/dwWqb+ilB6cN7bYlofJw6fj0pHic/JKtSrGTnB9FY7QB+NV2/aXitpQWd8ri +qplIvY9jXW5679oJy77MeZ774L0X7atx26bIBHD5j7wqC93dlSH6bGJMqg2yzITT +meZHKAkvZlsbOxLicnu7wNfx/mBXwMD0cI+uZ/3iP9DjC32WDjxiugaerjQEsEOK +ScfSziG+kVSfSLC4Cb4L2qmkptI9a4/HjXY= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/fut/shell/tools/device/files/unit.mk b/src/fut/shell/tools/device/files/unit.mk new file mode 100644 index 00000000..f8102140 --- /dev/null +++ b/src/fut/shell/tools/device/files/unit.mk @@ -0,0 +1,34 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_device_files + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/device/files + +UNIT_FILE := fut_ca.pem diff --git a/src/fut/shell/tools/device/genCA.sh b/src/fut/shell/tools/device/genCA.sh new file mode 100755 index 00000000..fbebf88d --- /dev/null +++ b/src/fut/shell/tools/device/genCA.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Create CA, no passwd +echo "Generationg fut_rootCA.key" +openssl genrsa -out fut_rootCA.key 4096 + +# Self sign it +openssl req -x509 -new -nodes -key fut_rootCA.key -sha256 -days 60 -out fut_rootCA.pem + +# Create fut-server certificate +echo "Generating fut_sever.key" +openssl genrsa -out fut_server.key 4096 + +# Self sign it +openssl req -new -key fut_server.key -out fut_server.csr +openssl x509 -req -in fut_server.csr -CA fut_rootCA.pem -CAkey fut_rootCA.key -CAcreateserial -out fut_server.pem -days 30 -sha256 + +# Create device certificate +echo "Generating fut_device.key" +openssl genrsa -out fut_device.key 4096 + +# Self sign it +openssl req -new -key fut_device.key -out fut_device.csr +openssl x509 -req -in fut_device.csr -CA fut_rootCA.pem -CAkey fut_rootCA.key -CAcreateserial -out fut_device.pem -days 30 -sha256 + + diff --git a/src/fut/shell/tools/device/get_radio_mac_from_ovsdb.sh b/src/fut/shell/tools/device/get_radio_mac_from_ovsdb.sh new file mode 100755 index 00000000..0a647a5d --- /dev/null +++ b/src/fut/shell/tools/device/get_radio_mac_from_ovsdb.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +source /tmp/fut-base/shell/config/default_shell.sh +[ -e "/tmp/fut_set_env.sh" ] && source /tmp/fut_set_env.sh +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + +tc_name="tools/device/$(basename $0)" +help() +{ +cat << EOF +${tc_name} [-h] where_clause + +This script gets radio physical (MAC) address from ovsdb + +Arguments: + where_clause=$1: ovsdb "where" clause for Wifi_Radio_State table, that determines how we get the MAC address +Examples of usage: + ${tc_name} "if_name==wifi1" + ${tc_name} "freq_band==5GL" + ${tc_name} "channel==44" +EOF +raise "Printed help and usage string" -l "$tc_name" -arg +} + +while getopts h option; do + case "$option" in + h) + help + ;; + esac +done + +NARGS=1 +[ $# -ne ${NARGS} ] && raise "Failure: requires exactly '${NARGS}' input argument(s)" -l "${tc_name}" -arg +where_clause="${1}" + +# It is important that no logging is performed for functions that output values +fnc_str="get_radio_mac_from_ovsdb ${where_clause}" +wait_for_function_output "notempty" "${fnc_str}" 2>&1 >/dev/null +if [ $? -eq 0 ]; then + iface_mac_raw=$($fnc_str) || raise "Failure: ${fnc_str}" -l "$tc_name" -f +else + raise "Failure: ${fnc_str}" -l "${tc_name}" -f +fi + +echo "${iface_mac_raw}" +exit 0 diff --git a/src/fut/shell/tools/device/man_traffic_address.sh b/src/fut/shell/tools/device/man_traffic_address.sh new file mode 100755 index 00000000..09fafc56 --- /dev/null +++ b/src/fut/shell/tools/device/man_traffic_address.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +address=$1 +type=$2 + +log "tools/device/$(basename "$0"): Manipulating traffic for $address - $type" + +manipulate_iptables_address "$type" "$address" + log "tools/device/$(basename "$0"): manipulate_iptables_address - Success" || + die "tools/device/$(basename "$0"): manipulate_iptables_address - Failed" + +exit 0 diff --git a/src/fut/shell/tools/device/man_traffic_protocol.sh b/src/fut/shell/tools/device/man_traffic_protocol.sh new file mode 100755 index 00000000..f0ab4eaa --- /dev/null +++ b/src/fut/shell/tools/device/man_traffic_protocol.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +type=$1 + +log "tools/device/$(basename "$0"): Manipulating DNS and SSL traffic - $type" + +manipulate_iptables_protocol "$type" DNS + log "tools/device/$(basename "$0"): manipulate_iptables_protocol - Success" || + die "tools/device/$(basename "$0"): manipulate_iptables_protocol - Failed" + +manipulate_iptables_protocol "$type" SSL + log "tools/device/$(basename "$0"): manipulate_iptables_protocol - Success" || + die "tools/device/$(basename "$0"): manipulate_iptables_protocol - Failed" + +exit 0 diff --git a/src/fut/shell/tools/device/ovsdb/get_ovsdb_value.sh b/src/fut/shell/tools/device/ovsdb/get_ovsdb_value.sh new file mode 100755 index 00000000..23ec3c02 --- /dev/null +++ b/src/fut/shell/tools/device/ovsdb/get_ovsdb_value.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + + +ovsdb_table=${1} +ovsdb_field=${2} +ovsdb_where_field=${3} +ovsdb_where_value=${4} +ovsdb_raw=${5:-false} +ovsdb_opt='' +ovsdb_where='' + +if [ "$ovsdb_raw" == 'true' ]; then + ovsdb_opt='-raw' +fi + +if [ -n "$ovsdb_where_field" ] && [ -n "$ovsdb_where_value" ]; then + ovsdb_where="-w $ovsdb_where_field $ovsdb_where_value" +fi + +get_ovsdb_entry_value "$ovsdb_table" "$ovsdb_field" $ovsdb_where ${ovsdb_opt} || + raise "Failed to retrive ovsdb value {$ovsdb_table:$ovsdb_field $ovsdb_where}" -l "$(basename "$0")" -oe diff --git a/src/fut/shell/tools/device/ovsdb/unit.mk b/src/fut/shell/tools/device/ovsdb/unit.mk new file mode 100644 index 00000000..c5baebd2 --- /dev/null +++ b/src/fut/shell/tools/device/ovsdb/unit.mk @@ -0,0 +1,34 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_ovsdb_tools + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/device/ovsdb + +UNIT_FILE := get_ovsdb_value.sh diff --git a/src/fut/shell/tools/device/start_udhcpc.sh b/src/fut/shell/tools/device/start_udhcpc.sh new file mode 100755 index 00000000..83708a18 --- /dev/null +++ b/src/fut/shell/tools/device/start_udhcpc.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/cm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +if_name=$1 +should_get_address=$2 + +log "tools/device/$(basename "$0"): Starting udhcpc on interface $if_name" +start_udhcpc $if_name $should_get_address && + log "tools/device/$(basename "$0"): start_udhcpc - Success" || + raise "start_udhcpc - Failed" -l "tools/device/$(basename "$0")" -tc + +exit 0 diff --git a/src/fut/shell/tools/device/unit.mk b/src/fut/shell/tools/device/unit.mk new file mode 100644 index 00000000..c48103a3 --- /dev/null +++ b/src/fut/shell/tools/device/unit.mk @@ -0,0 +1,48 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_device_tools + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/device + +UNIT_FILE := change_channel.sh +UNIT_FILE += check_time.sh +UNIT_FILE += check_wifi_presence.sh +UNIT_FILE += connect_to_fut_cloud_min.sh +UNIT_FILE += connect_to_fut_cloud.sh +UNIT_FILE += create_inet_interface.sh +UNIT_FILE += create_radio_vif_interface.sh +UNIT_FILE += default_setup.sh +UNIT_FILE += genCA.sh +UNIT_FILE += get_radio_mac_from_ovsdb.sh +UNIT_FILE += man_traffic_address.sh +UNIT_FILE += man_traffic_protocol.sh +UNIT_FILE += start_udhcpc.sh +UNIT_FILE += vif_clean.sh +UNIT_FILE += wm2_setup.sh diff --git a/src/fut/shell/tools/device/vif_clean.sh b/src/fut/shell/tools/device/vif_clean.sh new file mode 100755 index 00000000..568eccbe --- /dev/null +++ b/src/fut/shell/tools/device/vif_clean.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + + +usage="$(basename "$0") [-h] + +Script is used to empty Wifi_VIF_Config table + +Script does following: + - delete whole Wifi_VIF_Config table + +Example of usage: + $(basename "$0") - delete/empty Wifi_VIF_Config table +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +vif_clean || + raise "vif_clean - Failed" -l "tools/device/$(basename "$0")" -tc + +exit 0 diff --git a/src/fut/shell/tools/device/wm2_setup.sh b/src/fut/shell/tools/device/wm2_setup.sh new file mode 100755 index 00000000..c3107190 --- /dev/null +++ b/src/fut/shell/tools/device/wm2_setup.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for WM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/wm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +wm_setup_test_environment "$@" && + log "tools/device/$(basename "$0"): wm_setup_test_environment - Success " || + raise "wm_setup_test_environment - Failed" -l "tools/device/$(basename "$0")" -tc + +exit 0 diff --git a/src/fut/shell/tools/rpi/cm/address_dns_man.sh b/src/fut/shell/tools/rpi/cm/address_dns_man.sh new file mode 100755 index 00000000..fcf1638b --- /dev/null +++ b/src/fut/shell/tools/rpi/cm/address_dns_man.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +tc_name="tools/rpi/cm/$(basename $0)" +usage() +{ +cat << EOF +${tc_name} [-h] ip_address type +Options: + -h show this help message +Arguments: + ip_address=$1 -- IP address to perform action on - (string)(required) + type=$2 -- type of action to perform: block/unblock - (string)(required) +example of usage: + ${tc_name} "192.168.200.11" "block" + ${tc_name} "192.168.200.10" "unblock" +EOF +exit 1 +} + +while getopts h option; do + case "$option" in + h) + usage + ;; + esac +done + +NARGS=2 +[ $# -ne ${NARGS} ] && raise "Requires exactly '${NARGS}' input argument(s)" -l "$tc_name" -arg +ip_address=${1} +type=${2} + +log "${tc_name}: Manipulate DNS traffic: ${type} ${ip_address}" +address_dns_manipulation2 "$ip_address" "$type" diff --git a/src/fut/shell/tools/rpi/cm/address_internet_man.sh b/src/fut/shell/tools/rpi/cm/address_internet_man.sh new file mode 100755 index 00000000..31b70fa8 --- /dev/null +++ b/src/fut/shell/tools/rpi/cm/address_internet_man.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +tc_name="tools/rpi/cm/$(basename $0)" +usage() +{ +cat << EOF +${tc_name} [-h] ip_address type +Options: + -h show this help message +Arguments: + ip_address=$1 -- IP address to perform action on - (string)(required) + type=$2 -- type of action to perform: block/unblock - (string)(required) +example of usage: + ${tc_name} "192.168.200.11" "block" + ${tc_name} "192.168.200.10" "unblock" +EOF +exit 1 +} + +while getopts h option; do + case "$option" in + h) + usage + ;; + esac +done + +NARGS=2 +[ $# -ne ${NARGS} ] && raise "Requires exactly '${NARGS}' input argument(s)" -l "$tc_name" -arg +ip_address=${1} +type=${2} + +log "${tc_name}: Manipulate internet traffic: ${type} ${ip_address}" +address_internet_manipulation "$ip_address" "$type" diff --git a/src/fut/shell/tools/rpi/cm/unit.mk b/src/fut/shell/tools/rpi/cm/unit.mk new file mode 100644 index 00000000..fb2a49cb --- /dev/null +++ b/src/fut/shell/tools/rpi/cm/unit.mk @@ -0,0 +1,35 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_cm_tools + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/rpi/cm + +UNIT_FILE := address_dns_man.sh +UNIT_FILE += address_internet_man.sh diff --git a/src/fut/shell/tools/rpi/connect_to_wpa2.sh b/src/fut/shell/tools/rpi/connect_to_wpa2.sh new file mode 100755 index 00000000..d202a3a1 --- /dev/null +++ b/src/fut/shell/tools/rpi/connect_to_wpa2.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +usage="$(basename "$0") [-h] \$1 \$2 \$3 + +where arguments are: + interface=\$1 -- interface name which to use to connect to network (string)(required) + network_ssid=\$2 -- network ssid to which rpi client will try and connect (string)(required) + network_bssid=\$3 -- network bssid (MAC) to which rpi client will try and connect (string)(required) + network_pass=\$4 -- network password which rpi client will use to try and connect to network (string)(required) + network_key_mgmt=\$5 -- used as key_mgmt value in wpa_supplicant.conf file + enable_dhcp=\$6 -- enable or disable DHCPDISCOVER on network !!! PARTIALLY IMPLEMENTED !!! + - possibilities: + - on (string) - enable dhcp discover for interface + - off (string) - disable dhcp discover for interface - (default value) + - killing dhclient process after 5 seconds - workaround + msg_prefix=\$7 -- used as message prefix for log messages (string)(optional) +Script is used to connect RPI client to WPA2 network + +Script does following: + - bring down interface wlan0 -> ifdown wlan0 + - clear wpa_supplicant.conf file + - create new wpa_supplicant.conf using wpa_passphrase and other configuration + - bring up interface wlan0 -> ifup wlan0 + - check if RPI client is connected to netowork -> ip link show wlan0 + +Example of usage: + $(basename "$0") wlan0 wm_dut_24g_network 72:a7:56:f0:0d:72 WifiPassword123 WPA-PSK on + - connect to wm_dut_24g_network ssid with bssid 72:a7:56:f0:0d:72 using wlan0 interface key_mgmnt mode of + WPA-PSK using network password WifiPassword123 and keeping dhcp discover on +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 6 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +interface=$1 +network_ssid=$2 +network_bssid=$3 +network_pass=$4 +network_key_mgmt=$5 +enable_dhcp=$6 +msg_prefix=$7 + +network_connect_to_wpa2 $interface $network_ssid $network_bssid $network_pass $network_key_mgmt $enable_dhcp $msg_prefix \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/files/fut_controller.pem b/src/fut/shell/tools/rpi/files/fut_controller.pem new file mode 100644 index 00000000..0d118d54 --- /dev/null +++ b/src/fut/shell/tools/rpi/files/fut_controller.pem @@ -0,0 +1,177 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=CA, O=Plume Design Inc., OU=FUT Certificate Authority, CN=FUT Root CA + Validity + Not Before: Jan 1 00:00:00 1970 GMT + Not After : Jan 1 00:00:00 2035 GMT + Subject: CN=192.168.200.1, C=US, OU=FUT Certificate Authority, O=Plume Design Inc., ST=CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a9:94:88:2b:92:6a:8c:19:86:b5:2d:d4:37:db: + 9d:f4:3c:b5:d2:3d:86:18:8f:e0:75:13:f0:9c:82: + 72:b9:16:6e:30:d4:06:ce:66:36:4a:32:b5:e5:11: + 6c:00:94:21:b5:d1:4e:e6:05:bb:97:20:90:f6:cf: + 10:72:62:19:fd:61:03:94:3a:26:04:c3:f0:d7:15: + f6:28:e8:d4:df:b6:03:77:97:23:3b:4e:4c:ef:bc: + 57:96:c7:c5:17:06:ca:2e:9b:a6:a2:be:23:d7:14: + 7a:da:13:16:37:84:a8:5e:17:06:64:d7:5c:eb:42: + 91:29:75:a9:02:e1:05:f2:a0:8c:cd:e7:e9:92:0c: + 54:ab:8b:60:51:2f:a0:e0:3b:9c:09:ad:b3:33:5a: + c0:2f:ab:a2:5c:ae:b3:00:b3:08:bf:e8:9a:c7:9d: + 4a:46:c2:e7:12:19:dd:69:d7:aa:a4:0e:6a:05:87: + ed:a3:e6:a1:1a:6a:4b:e2:0b:83:14:cf:ee:6e:66: + e4:37:2a:9e:80:12:c8:e4:ab:7c:72:1c:1b:66:62: + 05:83:b7:46:de:c2:89:0e:e0:d4:2d:2e:8a:a8:ad: + d4:92:63:89:7c:2c:f8:d8:18:e2:1e:b0:2e:22:a1: + 72:38:80:47:a3:06:47:4b:ab:ac:02:d5:08:c6:42: + 10:ce:74:89:63:43:ae:ce:d2:9e:b4:bd:a9:af:44: + e5:c7:64:33:2e:3d:e8:93:38:51:5f:5a:4d:97:24: + 45:43:84:88:99:fe:88:ac:7e:d0:ec:3a:58:e9:54: + 28:ff:b3:01:1e:57:67:3c:2f:e6:ef:9b:72:d4:58: + af:31:fd:87:38:66:7e:64:88:ff:bc:7b:6c:ec:37: + 8a:cd:11:b0:66:b8:24:8c:41:35:a6:6f:9b:73:9a: + bc:cd:34:f7:92:93:db:d9:be:c4:4a:9b:7a:56:ca: + cf:f6:f7:05:84:fb:4b:91:56:4a:86:36:4f:9b:7a: + 49:d4:ee:9f:3f:e3:81:2e:1a:47:fe:36:9c:2f:4a: + 2f:8b:d7:0d:e7:7c:8d:b8:9a:e4:b8:8f:92:5d:fd: + c6:1a:c7:18:48:34:fa:6a:a0:f4:3f:db:af:65:e2: + 78:36:0c:dc:1d:c3:da:eb:e0:2d:13:2b:d1:72:47: + 06:ff:6a:db:f2:67:b2:95:de:12:d7:8c:ba:cc:39: + d4:e6:b0:b7:3b:81:a3:9a:38:87:b9:cf:b2:52:bb: + 65:76:3e:77:77:01:c9:9f:56:e4:c3:64:e1:dd:cf: + 1a:36:17:46:ea:30:6f:69:ed:31:42:60:db:77:04: + 18:c3:82:90:10:3c:88:16:a2:8d:70:61:0e:a6:fd: + 2c:7e:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:1B:94:9C:79:11:86:69:3B:C5:83:BA:4A:1C:7F:7F:61:45:40:E6:3E + + X509v3 Subject Key Identifier: + FB:5F:48:D8:8F:08:C9:D9:3F:33:BA:80:1E:F2:E2:C3:DD:49:E8:7F + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + Signature Algorithm: sha256WithRSAEncryption + 38:85:68:0d:54:ff:d3:5b:29:5c:81:2b:29:3e:b7:fe:d6:a4: + 80:26:db:d3:47:9a:c1:db:fb:d3:86:85:b2:a9:35:76:f4:04: + c6:2e:9a:80:10:69:16:06:87:3b:dc:65:69:2c:d1:31:35:9b: + bb:c4:20:e6:97:02:59:bb:58:cc:a5:a7:7b:b4:2f:b4:59:2e: + 49:14:54:6d:97:61:58:c3:70:08:20:89:72:f6:fe:9e:87:cf: + 30:83:af:c3:15:64:db:81:c5:52:7f:74:da:30:0f:2a:17:d6: + 37:3b:78:f5:ba:4e:c3:1e:2a:3b:cf:b9:ab:3e:26:c3:ef:4b: + a4:9d:67:4f:4e:e8:87:02:b8:f8:68:13:b9:a2:3c:1f:7a:52: + a5:93:d4:9c:05:76:60:03:ff:57:07:e4:7c:0c:47:77:b6:2a: + 95:ed:d6:e4:ba:3d:f1:42:7a:3b:dd:4f:f9:67:60:9d:de:75: + 1f:3a:13:8c:df:ef:27:a7:8d:22:c5:bd:35:85:ef:71:30:f3: + fe:52:35:6b:a1:0b:c7:39:13:40:50:84:54:df:48:89:b3:f5: + 24:d8:94:88:9c:c9:1a:9a:13:b1:3a:b8:63:9c:c5:54:ed:f6: + 96:f1:5d:4f:97:68:db:43:25:79:b7:a5:4c:da:31:01:62:6f: + 00:f2:ef:48:6c:1c:ea:35:88:d3:09:3f:00:cc:d4:06:59:b3: + 7d:d9:7c:0e:73:a2:20:21:1b:45:fd:15:fe:df:f1:8a:e7:1f: + c8:50:fc:6e:a8:12:90:98:17:ec:d1:58:79:2d:b9:18:f0:56: + f7:09:75:be:39:f6:94:bb:f1:c0:73:be:e2:98:1a:13:7d:9f: + 14:20:a6:29:86:6f:14:03:99:46:31:67:f9:8d:bc:37:14:bf: + 66:49:c7:73:65:41:b6:12:cc:77:b1:a2:77:c3:99:5b:97:47: + 70:52:99:39:2c:4a:19:2b:54:6f:95:38:cb:c8:f1:2f:af:41: + cc:a5:c3:27:8a:66:f1:28:93:cf:21:a4:74:fb:72:a4:94:1e: + e9:95:b4:51:7e:d5:0e:1e:74:c4:3b:eb:7c:14:68:fa:ec:20: + 84:0c:d6:8b:9e:d1:f6:e3:f3:5b:45:4a:23:41:a2:68:16:5d: + 1a:9b:37:37:9f:47:41:7a:2f:cc:0c:c7:93:e9:d2:19:45:8a: + ed:0b:44:75:17:ce:bd:3c:43:80:f3:b1:f4:31:66:01:ad:c0: + f1:7c:4d:c2:fa:b6:8e:18:58:20:d4:19:50:ac:b2:bc:b4:04: + 21:cc:89:dc:b7:51:0d:97:10:f0:27:f4:25:70:7b:4e:c8:9b: + cf:ec:6f:a7:22:f6:9d:23 +-----BEGIN CERTIFICATE----- +MIIF3DCCA8SgAwIBAgIBATANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEL +MAkGA1UECAwCQ0ExGjAYBgNVBAoMEVBsdW1lIERlc2lnbiBJbmMuMSIwIAYDVQQL +DBlGVVQgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRQwEgYDVQQDDAtGVVQgUm9vdCBD +QTAeFw03MDAxMDEwMDAwMDBaFw0zNTAxMDEwMDAwMDBaMHIxFjAUBgNVBAMMDTE5 +Mi4xNjguMjAwLjExCzAJBgNVBAYTAlVTMSIwIAYDVQQLDBlGVVQgQ2VydGlmaWNh +dGUgQXV0aG9yaXR5MRowGAYDVQQKDBFQbHVtZSBEZXNpZ24gSW5jLjELMAkGA1UE +CAwCQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCplIgrkmqMGYa1 +LdQ32530PLXSPYYYj+B1E/CcgnK5Fm4w1AbOZjZKMrXlEWwAlCG10U7mBbuXIJD2 +zxByYhn9YQOUOiYEw/DXFfYo6NTftgN3lyM7TkzvvFeWx8UXBsoum6aiviPXFHra +ExY3hKheFwZk11zrQpEpdakC4QXyoIzN5+mSDFSri2BRL6DgO5wJrbMzWsAvq6Jc +rrMAswi/6JrHnUpGwucSGd1p16qkDmoFh+2j5qEaakviC4MUz+5uZuQ3Kp6AEsjk +q3xyHBtmYgWDt0bewokO4NQtLoqordSSY4l8LPjYGOIesC4ioXI4gEejBkdLq6wC +1QjGQhDOdIljQ67O0p60vamvROXHZDMuPeiTOFFfWk2XJEVDhIiZ/oisftDsOljp +VCj/swEeV2c8L+bvm3LUWK8x/Yc4Zn5kiP+8e2zsN4rNEbBmuCSMQTWmb5tzmrzN +NPeSk9vZvsRKm3pWys/29wWE+0uRVkqGNk+beknU7p8/44EuGkf+NpwvSi+L1w3n +fI24muS4j5Jd/cYaxxhINPpqoPQ/269l4ng2DNwdw9rr4C0TK9FyRwb/atvyZ7KV +3hLXjLrMOdTmsLc7gaOaOIe5z7JSu2V2Pnd3AcmfVuTDZOHdzxo2F0bqMG9p7TFC +YNt3BBjDgpAQPIgWoo1wYQ6m/Sx+DwIDAQABo38wfTAfBgNVHSMEGDAWgBQblJx5 +EYZpO8WDukocf39hRUDmPjAdBgNVHQ4EFgQU+19I2I8Iydk/M7qAHvLiw91J6H8w +DAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH +AwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQA4hWgNVP/TWylcgSspPrf+ +1qSAJtvTR5rB2/vThoWyqTV29ATGLpqAEGkWBoc73GVpLNExNZu7xCDmlwJZu1jM +pad7tC+0WS5JFFRtl2FYw3AIIIly9v6eh88wg6/DFWTbgcVSf3TaMA8qF9Y3O3j1 +uk7DHio7z7mrPibD70uknWdPTuiHArj4aBO5ojwfelKlk9ScBXZgA/9XB+R8DEd3 +tiqV7dbkuj3xQno73U/5Z2Cd3nUfOhOM3+8np40ixb01he9xMPP+UjVroQvHORNA +UIRU30iJs/Uk2JSInMkamhOxOrhjnMVU7faW8V1Pl2jbQyV5t6VM2jEBYm8A8u9I +bBzqNYjTCT8AzNQGWbN92XwOc6IgIRtF/RX+3/GK5x/IUPxuqBKQmBfs0Vh5LbkY +8Fb3CXW+OfaUu/HAc77imBoTfZ8UIKYphm8UA5lGMWf5jbw3FL9mScdzZUG2Esx3 +saJ3w5lbl0dwUpk5LEoZK1RvlTjLyPEvr0HMpcMnimbxKJPPIaR0+3KklB7plbRR +ftUOHnTEO+t8FGj67CCEDNaLntH24/NbRUojQaJoFl0amzc3n0dBei/MDMeT6dIZ +RYrtC0R1F869PEOA87H0MWYBrcDxfE3C+raOGFgg1BlQrLK8tAQhzInct1ENlxDw +J/QlcHtOyJvP7G+nIvadIw== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAqZSIK5JqjBmGtS3UN9ud9Dy10j2GGI/gdRPwnIJyuRZuMNQG +zmY2SjK15RFsAJQhtdFO5gW7lyCQ9s8QcmIZ/WEDlDomBMPw1xX2KOjU37YDd5cj +O05M77xXlsfFFwbKLpumor4j1xR62hMWN4SoXhcGZNdc60KRKXWpAuEF8qCMzefp +kgxUq4tgUS+g4DucCa2zM1rAL6uiXK6zALMIv+iax51KRsLnEhndadeqpA5qBYft +o+ahGmpL4guDFM/ubmbkNyqegBLI5Kt8chwbZmIFg7dG3sKJDuDULS6KqK3UkmOJ +fCz42BjiHrAuIqFyOIBHowZHS6usAtUIxkIQznSJY0OuztKetL2pr0Tlx2QzLj3o +kzhRX1pNlyRFQ4SImf6IrH7Q7DpY6VQo/7MBHldnPC/m75ty1FivMf2HOGZ+ZIj/ +vHts7DeKzRGwZrgkjEE1pm+bc5q8zTT3kpPb2b7ESpt6VsrP9vcFhPtLkVZKhjZP +m3pJ1O6fP+OBLhpH/jacL0ovi9cN53yNuJrkuI+SXf3GGscYSDT6aqD0P9uvZeJ4 +NgzcHcPa6+AtEyvRckcG/2rb8meyld4S14y6zDnU5rC3O4GjmjiHuc+yUrtldj53 +dwHJn1bkw2Th3c8aNhdG6jBvae0xQmDbdwQYw4KQEDyIFqKNcGEOpv0sfg8CAwEA +AQKCAgEAgVlXaIzdEpIh6y7S0eyFlhd8xKnDEBcmqYcVH/xsj3tpf3sq2eKjBIOb +tOdODz7uW6YU3WWACi2ABZI5xFXJ5zhJp5WXDEl8+kK5Kck3HpDSIjU5XXJDQxXR +ZaRpVEAMlfKJ71bDNbpcXtzyNFTOrD451U9kg9qZqRsjWJvVkpUd8a00vv8C0nqU +dDi1KHSvd75zkvdk4rezN6jVxvHI+cDt1tbGIiVmZasu9R3Y/hw0iJV/EWbIecKc +sQYA7S4Re0qmRuIOVjh93dZkLRH9YGHiPO7ecunF64BYt0Hp5/H309VyuDIBeau5 +RpkyB55H5osKmXIfjbubj+l5MOiRsfpQvoyGV4xQEsrNoYr3gBVoryGX71RqRMfq +DH8wpOUOBnp5Hw094CWMCcIhC7+L46OukJcd6e/uUZ0mkJ8lyqfBZ5kx9sXS/QIS +/0excqqGYSB2Cp/Lf2vsstTv7cDYNydYCzRqxUPlR/oxeSRy79AS6vc+T7NFoMKG +zLZIfsZO3qMPf1Fd4vEqxSsnyPsEir7iWoTVLmNABpQGmOp80C74jt0RLa556pEm +0YrMR4GpAnsCmFjYwQ47Hlr2uxPv4CqaOb7Qf92Yzw0Q6t50CgaNFLjxpvd9edrI +ly7960jSNoZ+FRKbmXH4Op6YekqtFDvA1Trziwl3wBbnD368fskCggEBANzwDtJb +NrcOZ655koLVLuEw13M+OjvXpUa35VjUek1HByaVLy0atSBMCdm3DKVszineOWA4 +qGpFo6xQkrqM9cEu7o/qQFHKXqp+tDcxdOu9z8aa6JIHFONSKS976U5AoJfOUlWU +z3V/slckp490J+U1KBny8BChJikr1d90y2ZHUUlDfaqw95UVwKz3VZIFIGARr7ft +lMp4zlQ8FauibjTDen9fzp1JqBwcwx5rcV+l591aLorYf2aPZTI3M1nDtUexzJPt +G9ugkCCMTTYdzT+X1gvEkR0XWOJ0dHq2Zdy3m0x20tPIllSNpdkkyBtHhlECraqw +KW55oviJJW8Li7MCggEBAMR9/nUkcD8gcJCSL203wGqBd94a2VHjQHWEVO/sOabX +Pa06RWO2gVHw+gPfHfr8hFVoQT6aD0KLy4dWfF4knkE5CJpm0vOSjN6Z5jZW7RuN +n2wm2vGzKYa6ueP3bNFy+KDVFuEwlJQE2ZHvtZg7IQ33Jxvrjz5ZDdwNeMT0fXZH +jqqwbqJfGRWGSWjbnmEY9ml/uJX49FBsRqQJaGsKUxhA3+w9J4/RGIrmDenz+Jx2 +0g1Yi8NgKFFpBNBGHAJxWIOpg7HMNvWYiYNYwdBGNjnc8RDM15Q9wKDTi63VCGJo +QwCU4g110ny3HBPrWCgiD6WpysFIGDx3g1KeIFzEJjUCggEAH40MoM+z1ZpyBgGI +gbSN+EywR93YFRmrmZjDYNcfDBAbnk/pp8hLm2wgb/3rCWirXGFG0k3lByAgyofL +HGbq5YadPOIYA1YiBLkJZWRjrRKzLEqM8eWe/wOJrCVG4QzroiItsdkJc18kCbvL +TfophFr9+g6uZ8GLoI+JAFs+fMGsgwjnVkvlX1324PyFNNAUmoOME3kTKYLs/CyE +b7lHgbN0t+HnsKCHKFSXLK3tR9p6bSrmwJ9AOlY5/lzRsXz4U1+5tlpDAy8/xdYj +ZJoG6JD3WUDd9EiUQeqdg7SugUGbJOVHIEVh6ns79vGAvhyNut3mDR0RHZyzQEjd +lqkQbwKCAQATJwTKfkbCoHLYZKdiyfBjcUMxzwQnyzLZQZDV4fysmoZUgD2LPprU +VdzIy9KsSDjN6l+RroqWPfIUuwVcV81lJh4Ejsk5HKvGdtHNsiNicCd97zugG4qM +q167Lb7Zm49IffzA7m9NDjv20Zqtv/W02sZhHlDUDvIe5OFEsWAZS1hIovHlucdE +Jda59c42QKykE+L2G1IVFLi9/HzFEjiPQKOS71MP3Z26zDnG+BTfi2VmD59v58uG +Q+pIMs1AH7Q1ASzpA7LHtZqRxvD9UBqxASwuKwlIVcyU4InY487xaKA/SkPOdBGU +PnTqLCJnpwpHZ4lv1YsnOa7/OpKE+EmRAoIBACs403vhIALN1Fo1PjYjoBk66Lqn +6u1+D42R3DyzTzd9sZgy0v4YWlxcgiE5RT4HUOEFE2TinZLfOaYMaVjlxeZRAcOI +85+nJamAQJZLZM1BV+0pfaBf44QKUJy1TbO+zTWgqorHXG+W3DenJv5OdJMNUv7k ++lUjudIpZAO6YwAhGmo+F0ndmFM4rCx3aUwo7sC3qoW0L4YKws+vLGzGzYpopc4f +6y7/3VNZN5DOa7TLcZmkXajXBjRxTDVnMThJiT6/vlmKRpwME9ZHpyzeQVNznYUd +CH3/Ifly3U2sGJv37dsQy/sh6PjnRWGRZUoj71SNU+0PLE/+c0LAfUMbNGo= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/files/haproxy.cfg b/src/fut/shell/tools/rpi/files/haproxy.cfg new file mode 100644 index 00000000..7d615445 --- /dev/null +++ b/src/fut/shell/tools/rpi/files/haproxy.cfg @@ -0,0 +1,39 @@ +global + chroot /var/lib/haproxy + pidfile /var/run/haproxy.pid + maxconn 4000 + user haproxy + group haproxy + daemon + # turn on stats unix socket + stats socket /var/lib/haproxy/stats + + ssl-default-bind-options force-tlsv12 ssl-max-ver TLSv1.2 ssl-min-ver TLSv1.2 + ssl-default-bind-ciphers ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM + + ssl-default-server-options force-tlsv12 ssl-max-ver TLSv1.2 ssl-min-ver TLSv1.2 + ssl-default-server-ciphers ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM + + tune.ssl.default-dh-param 2048 + +defaults + mode tcp + log global + retries 3 + timeout http-request 10s + timeout http-keep-alive 10s + timeout check 10s + timeout queue 1m + timeout connect 100s + timeout client 100s + timeout server 100s + +frontend fut-tls-termination-proxy + bind *:443 transparent ssl crt /etc/haproxy/certs/fut_controller.pem ca-file /etc/haproxy/certs/plume_ca_chain.pem verify required + log /dev/log local0 debug + default_backend fut-simulated-cloud + +backend fut-simulated-cloud + balance roundrobin + log global + server simulated-cloud 192.168.200.1:5000 diff --git a/src/fut/shell/tools/rpi/files/plume_ca_chain.pem b/src/fut/shell/tools/rpi/files/plume_ca_chain.pem new file mode 100644 index 00000000..c7d51c1c --- /dev/null +++ b/src/fut/shell/tools/rpi/files/plume_ca_chain.pem @@ -0,0 +1,275 @@ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGxzCCBK+gAwIBAgIJAIyLecDrnpzeMA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJUGFsbyBBbHRv +MRswGQYDVQQKExJQbHVtZSBEZXNpZ24sIEluYy4xJDAiBgkqhkiG9w0BCQEWFXN1 +cHBvcnRAcGx1bWV3aWZpLmNvbTEiMCAGA1UEAxMZUGx1bWUgRGVzaWduIEF1dGhv +cml0eSBBMTAeFw0xNjAzMDMyMjQwMTRaFw0yMTAzMDIyMjQwMTRaMIGdMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJUGFsbyBBbHRv +MRswGQYDVQQKExJQbHVtZSBEZXNpZ24sIEluYy4xJDAiBgkqhkiG9w0BCQEWFXN1 +cHBvcnRAcGx1bWV3aWZpLmNvbTEiMCAGA1UEAxMZUGx1bWUgRGVzaWduIEF1dGhv +cml0eSBBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALo0cr8ZyiLs +CUyp4P4JFXkU6Ymx6QhN1DZ1SCuDgiMkX8A7/QCDMKz7Q70qqM022NwYW3Ff5VJG +El/epXmcaPx7vzfXpsy023mtyaLcwovCwr+IRDM5LgKlW9v3wcaWBWLEXbbv8are +a9q1eXW5jJjAyDMPdkrUqCwdJy3Gjnwy16mRiBnaY6A2+wVr5mTzkrtNGzJiEzhX +MECnal7T16sOC8HeaJZ4BVYJzxAnyU+wlf0ygzQeF4WaYXTDgcRs8g1D62LHcr7f +ioAT2Z69V5CVHFX7VJoE1PJeU867GwZDtM+osZ0WJFkeMA8cJgrs7ujKTl9nmiVp +Q2qt6BDABrd9ibZkjHj5XcXQz7o+z3zwL9v9x/1bilmY/yBz2rlozR+xbNwTM6Ra +D+FXpcv2caj2851Ci59eh+5eCJJkMNzGKdZZ9wyMaPqk2bynGDf6glhJc2cML9L3 ++L/iLq63yiYDOmDwKXiAjPVCPPgMPxp+Y4gwfiZdop2ou8W7xzFxOEwKuS8qK6Qp +9j8Mq1ritAFa4WIiVsuHjrEkmykCzHvb9z5ujsrZ4hJzBDNqfjXkazpR2wb4o895 +YfBQIHdoQy2H+wsOEaNatUkFuSE5uw2nMS+SDf8J2ouAG0U51n/SnWKd636WC4s+ +Mn5Bd8nwNP1H1DXCUf8TS7iow+Bt0A+VAgMBAAGjggEGMIIBAjAdBgNVHQ4EFgQU +CBK8rxUUByBBgsU0VXsOLjVIWiEwgdIGA1UdIwSByjCBx4AUCBK8rxUUByBBgsU0 +VXsOLjVIWiGhgaOkgaAwgZ0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9y +bmlhMRIwEAYDVQQHEwlQYWxvIEFsdG8xGzAZBgNVBAoTElBsdW1lIERlc2lnbiwg +SW5jLjEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBwbHVtZXdpZmkuY29tMSIwIAYD +VQQDExlQbHVtZSBEZXNpZ24gQXV0aG9yaXR5IEExggkAjIt5wOuenN4wDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAsTLMCgl/1rSf/+/14y0FWyj2yvOq +X5hgd/+kIRfIp/5Ib1wWdpWGY5sTV3Vy1rQvWHF/PijP9qMWE5QKfxHh/l2+HKv0 +gyRPW3I4QgK3Qr/u75nNFizYhI2L2n1+2MQmoejcu6TI9Kk5n7oVo3dGn2KxkrKC +WiB0QZmJgD6iIrJQt6oXB/oG4gSHqTIaTawflIvFgr5S94rKjVm+ZBtz6nOO184s +fDGXNOfw8zOXkGB5gAtxF5oX+XQ9s/2y0nrDbT/Oup3MzzrZ2zAEXqIUvb6cP8z6 +IqYGiwtzzhD8F/4jA6dUI/pnlPMnT670sy4YO7GsJaZi/Af/pvdRh342FFUpV3HF ++jJJxuejI+yehI2y0S1M4idmJLaCS5EldJF1GB3DU5CjSOhCeZKpIrkWEAIEXf4f +VTffDmOn/5SAcdKwe9v7tzJ2knNME0BPhVei/cSmU3VI6sAY04HzPtC498BLyaUJ +Nj+70iQ3tvNjegwfRI4CIgn0/Y90W6NcEd9Ihg/MTImH5uQag7ftupFqp7wP882N +SJGjWsd/oMDbB8kcyLKZ8z05nYhxG8v0/D6esu51SAXhnC2G2jybjuk3QHvMRTBo +jMnFwM/u3cRLzWwsHP3dSkY1NsnfMKA+ivUEXslq+8R0EH02Js4OUTrscDKPJSWo +YDLIkv5E8HWLVoc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFyDCCA7CgAwIBAgIJAJ78fVrF1kYwMA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJDQTEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4x +JzAlBgNVBAsMHk9wZW5TeW5jIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UE +AwwOT3BlblN5bmMgQ0EgQTEwIBcNMTkwMzI4MTI0ODIwWhgPMjA2OTAzMTUxMjQ4 +MjBaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEaMBgGA1UECgwRUGx1bWUg +RGVzaWduIEluYy4xJzAlBgNVBAsMHk9wZW5TeW5jIENlcnRpZmljYXRlIEF1dGhv +cml0eTEXMBUGA1UEAwwOT3BlblN5bmMgQ0EgQTEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDZOu6RWVfAJy10izzsgcSVTPqkIK84Jhy02ZxEx+XUOLJg +G6d75a2X2Qdb0xyu4vIr/zAnsFcm8L/w9J5MZh+IRvW1c9f5P7ROjzivM9vfub2I +CJ+4acoN0ErWX5qqNPx1FvL5gM7TzsgbvmUMYKcRxRUKmo9CCO1uJy/zjvr8jDNZ +ZvrI2cPA70UHjwzP3LPANH8gnQTZMdFM3W/K6vyRIJdIYGmsGRYdzrqI2jP7z5Ex +5tiqthZQPlXhwj8QFk8vONbuUEdWq/dPlY4LKDgg4qE0t9eV3kLwC8WPTcly2KwZ +FaFdrQFpeLQh3H3CcaN8O++lv5BlCNEbOkEE9CUaUHbAVSNDv4tePpHp0pFJGkl4 +io6OkJ20hywjyJ71RY+qxgw/oyTii5mDTcqIVYJ3nkblrHKlQihnZ7+uHSJzhioO +JEv0t/eBetG62N4GzuiUH6MUARsDf7sd8anFf+pk4zUEwTVkdkYb2j/tp+g0WV08 +kvnNJ/wRuT9mYO+PKS9HXHwG1brBEwAepN524FgncopTwm+VglsHqrH9c91c5bbC +GwHKlEUEhRy45+2OACIhqhaoPqolFXNLSXGJFAkA7hYzbXrCs7kc8tzrqFj7kUQn +uMQj8TtVM1+gFOfy0J0nGOV7hs/ya30obLGYa8MHXD2cR3GK6Xpl8ZDHeCmQvwID +AQABo1MwUTAdBgNVHQ4EFgQU3Ji6Gbgbvie8gFgWEJNd1OzU31QwHwYDVR0jBBgw +FoAU3Ji6Gbgbvie8gFgWEJNd1OzU31QwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQsFAAOCAgEAkjs7a0eHLLRuzt6+WKA/Q0/MD01H0r9ZaY9LC4WfyY49qsF+ +CYK/7pYPJVc7YbO8hlnxKfCkJlCxP7i4lNN91BW+Lw4keI0J/VKa0GdSnPy88Ps/ +5QtSXn+Yix1VHXfu7q45ORra2ZpuESNxXOCobbLBE6ow8lKNapCYkuex9wE2iMlA +Z72Wul8K8X7oX1yIzNrnBc89b7vbMAc6F0iseE9eINmQpp5sqhk347/dLKOMVVNX +lDqrw1bOgbDLW4aQdkws4fUnH8m7DjeOxSiJhR9jZRimtFdQ9VVv5wuQswGPOXue +7vBDeHP8td3pZrsQygFzprOUvREKSJcle3xgiYxhbtVUfi/nBBgxLPM7+ga4jol6 +AByOCa6nPcMGbWikFTbO+bQgwka7V54RBXjKhBx1XBtpZHAooRm8PPDmesLbUWc1 +SB21o+8Kfm9+kVxup2udDrXo0cQpLskHKNCQOZbiIW/TCF+6cnQGSCCzgcMazgGS +pm5oJskK3/z30xvKphU4o6CZzJocdIX5xS7lX+iQIYZNT42U31juEbhOpGUmg3xO +lBGhysfYkR2AzDifN11uuy8uWca+4JDA6qutieEoNqY2gBMkyBe7qsvlsYphvnCM +gIOXqPD3c4IGS6uxP+hzqn0na/b5Ai4I3iSAh5IvXr5pm+ZaQISq0WFBPIk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGXDCCBESgAwIBAgIUEfmSPQrznK0RTzR4uiTcrHV0eQwwDQYJKoZIhvcNAQEL +BQAweDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRowGAYDVQQKDBFQbHVtZSBE +ZXNpZ24gSW5jLjEaMBgGA1UECwwRUGx1bWUgZGV2ZWxvcG1lbnQxJDAiBgNVBAMM +G1BsdW1lIERlc2lnbiBEZXZlbG9wbWVudCBDQTAeFw0xOTExMDQxNzQ2NDZaFw0y +OTExMDExNzQ2NDZaMHgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEaMBgGA1UE +CgwRUGx1bWUgRGVzaWduIEluYy4xGjAYBgNVBAsMEVBsdW1lIGRldmVsb3BtZW50 +MSQwIgYDVQQDDBtQbHVtZSBEZXNpZ24gRGV2ZWxvcG1lbnQgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/SzaDgw19be05SjAn9G3mNW5csPAQzWl4 +4YSEeJhGyjyyK5uVB4JpmZt/v8hjggPFijLA9KK7YyQfPAWve4zsoZxYV2Es32la +ajCfXuyqQmOJRYySPOgEsglmScPV/Xl+bpTCjbSQ4MAqVYshFQiqZ5fsZxGAm/UY +es8qBwmW8BfXJ5TJAGqvjHsmojCcHS9++2wfeHKMI7TlbGfZKaZl1UFJ04lIYr+H +9RJosJnwlhhG9X4rgGqvmu/FDRHpyOEQfKEQF76uqtIBChLU7aNrpQc4pwRsLMsR +INsH2V2zXmN8wQnsGouKjYEau5OrPkmeIvdjXHXqdqL47fN+8cKmteB2ewG2rQjN +lhoeu10a1NJY69t1+GY7RrHHXiLiqVFmu+8gvf9qutgpf36BlZLHsi9lYcKQvtET +qkHMLM6x+FewVpYhaUmsQSwebu13wJvfAxIlGSFPJQccCK6HNyh71noMDS3GRqu0 +24wyXmglF6Yq0ROkY0kB7wy1FmlbF9tDwvX7UhjACe8phdpOOfHreJMSrxtFmOvS +ddo6ceczHidjcXdmplbKOBjZtdHhi3AgxV7dLDG9p34VBYgKFkExPoXhmvFCL/In +9SGQSN1CBZQi7OehCXQ+EhsyNOUBUXcek83nIQDQhcFebull2RGD/dQLzAAnUyjF +/VN54k+huQIDAQABo4HdMIHaMA4GA1UdDwEB/wQEAwIBBjBABggrBgEFBQcBAQQ0 +MDIwMAYIKwYBBQUHMAKGJGh0dHBzOi8vd3d3LnBsdW1lLmNvbS9jYS9yb290LWNh +LmNlcjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwczovL3d3dy5wbHVtZS5jb20vY2Ev +cm9vdC1jYS5jcmwwHQYDVR0OBBYEFGQkoCS/zImHMxEzvIpaYhKCgoyXMB8GA1Ud +IwQYMBaAFGQkoCS/zImHMxEzvIpaYhKCgoyXMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggIBAGfsrAyPTcAjSC181ZJKFWi6+AegG05Jy2k5nr7qgVoR +xjMQj55qgDE/MCaIXjyXRUiU1V/4PADgSrMxIuDRZpy3y/NpPERRGo09g/FoLnoW +eyqrWvYxkitXo8Gom/iCzJY7Ksu95S44veqlJroLZQQ6Ek4N738Odz/6Hicr0x4D +wiOug/nY8uGmOw4bE4ZoCuaL76hV8Xr8CWLtyPaiD29+PWbrKSQ7C05GQ+nW8eG/ +WwMp/gL96axVnmtT7/rWz+M8gYBp/RUZHJsDdjHyWKrg9ulSyzrQqAwYS4wVvBas +y5+liHzKPqVx4a5aTGt/1/fxNu3nwHPhoDkhZx2UajrRZpf+zC38vogCMzO2PDkS +6bF3OGCLUo99BsLNDjJ2x+idIlKYsDfZh2VObp2T2IwcPx/rOOHwIgMbYDjATegd +KJwZNk1KbPEb/gqf3rlFIrSdpJfnjcXV4LMp+RzRNXt7jzSyTpM1r8H1FVtqS793 ++L/J7t+lxhr5xGOShouBBN50L2OTR5kGc0VHlL6MwqYEZL+VV+Pus4ooaUVy6UAi +/rjBk8quTzYYwyfagJKx1wKHf3AeKprPVeql0dGdDB7dNOzuBnMNyI6h/3szJuYu +VUOxmip7s3DEzk66luxPXR4pbRy/vNg3mqcg8uwttArL8g9kCm8pBhCcanOXByYa +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFzTCCA7WgAwIBAgIEEAAAAzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV +UzEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4xKzApBgNVBAsMIlBsdW1lIERl +c2lnbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHTAbBgNVBAMMFFBsdW1lIERlc2ln +biBSb290IENBMCAXDTE4MDEyMjIzMTUyOFoYDzIwNTAxMjMxMjM1OTU5WjB1MQsw +CQYDVQQGEwJVUzEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4xKzApBgNVBAsM +IlBsdW1lIERlc2lnbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHTAbBgNVBAMMFFBs +dW1lIERlc2lnbiBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEAnu2hWO6WPQA6H4Wk8+BuSrV5FJg1Uc4xYmoPN6YB8foUrbMgjg3MDkTHSZxM +p/ZOF8ylPy2YY2N/seTqMap5B/me6ybhnW8P051agarjm7H2OXRenaDSvk6cy0C/ +tiDhF8PZuYQbsrrIZ6l7Tc2V8dxxWv6+WatVrbXPZY9YNkkV25yL0dLRnKcBUCk2 +pAFgUVlAfwdNG6jsxUrecVMAUAijhxVoLQ+GrQIZyPTqCmF1uzInS46qlrGPIdMh +KHatRqi3elW6hgn5r4JKHvfTHx6wfHkKxH6yrRAM98FdczUIJUsmlBrucQyGqD8/ +Bpv6GkXjozYtErdty0Xey+NzaKJ7PvLsv1YxKsvSfJTh9m3jxuhSW/njbn/4wf2U +uZFgD0u8UK3LxRu6BXIn/k4uEaudZbIiuEqzFYQH9Qt1OxoNi0p2gByfPDoC4B5o +Qr+sj7spnKzh3TFu+Q21w5Mta8TBezj6Qu2WDXvLEVeacjV3J22fkTweCB1Bwctz +DVrJ68kdOwgnFKLGsAk9eXsmEH5CyuG3Pjud0Fynos791SV3i115U9cdwFC18JjN +3msqBIQo1SzdtIcjjKsx2xwLCcmimOHzyx3Z1TLqUe0wcdHeE7bMpHEGVSWmClL6 +TjK6+iI5rNPT+1Chogf52k7olFYy0UEoQ257fui96wovB0UCAwEAAaNjMGEwDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCK+E0iBzYwF +j27rin0xgW9aYM05MB8GA1UdIwQYMBaAFCK+E0iBzYwFj27rin0xgW9aYM05MA0G +CSqGSIb3DQEBCwUAA4ICAQBenUZ+yDh8eHG5Lg4LU1R73DAGQAuyLTH3IINpA0gP +kRv8ZuTjZ1s40xmZo6fsgbK5UpHoMWxaqk0cBJxBV0QvtfHvJpciEuUOLsC60EVV +44bDDyn+pdyI2cZaZEn1dBTppQaQz5lTXHugPhiCa8sDrIVZ1N6cYD6heJr22/yp +o44Tj3BSPLbgm6JGN/6dMlXRZd0ulG3/FDhD54oaZibDGZMjTi0xVKiLLzJ0vF23 +FjDx66DrtrFCcrve3CO0l0TrqwI/J3sPUoDb64FfC199dPYMnzv59GyMu3rClga7 +6e+P4xK2qAu2jgt9oHbG36OwsxBGGZT9wnPcz3U0G3tHjpoRupi6GUjg++JaXz27 +pOua+EkkHtLIRMDmEO0V6x/iohSGMWXbevl0SUqIYmeYiu27rLIODmgWt2an7f8D +ZsQD/f9K/+pX4xDSxIICDc7vShVJNU8qoVxupldDWw0xUVGDaWw1+JNIfgQfWcqk +GtbY8KgY77GCxg5l/oMWdBSWCOrUJGr8XiF/JfG1rVLbyO+FZMi7WRiL1Lnvpxhn +cjnQGFvMrRkzSSjiqn+tRMoLXw0LaK3TQoP0+bEtJ0Czy2i8wFIqCMaWnXqijY7N +dbImNSwJb6GT/1RWqcTBhzEGfph+5h3j+RDX0PYZ8Z/orMJBmfGGusX8V+zuzYBY +cg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGUDCCBDigAwIBAgIEEAAABTANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV +UzEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4xKzApBgNVBAsMIlBsdW1lIERl +c2lnbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHTAbBgNVBAMMFFBsdW1lIERlc2ln +biBSb290IENBMB4XDTE4MDEyMjIzMzE0MloXDTI4MDEyMjIzMzE0MlowdDELMAkG +A1UEBhMCVVMxGjAYBgNVBAoMEVBsdW1lIERlc2lnbiBJbmMuMS0wKwYDVQQLDCRQ +bHVtZSBIYXJkd2FyZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxGjAYBgNVBAMMEVBs +dW1lIEhhcmR3YXJlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +nvfRUieAWMIpF53VLkD6TvRguF63B5chH4Zp2teaDoRiUoCqH0OY+5VUAUHzQzl4 +B5DFJkZra2BfHyNrcSfsOUBGkMpj/uJK8LucPek8qDvMs2uT8uiDAcNnhP4j00lR +MVYT5Wpqmhl4xdX+rt4IfdoBC7rYEStLpu5RqHJjBbQOWoezNdrjQaDeqYDxTZfm +8kTrjte9nuhD6euTosa1ulvrlxDQ0MYb4sX/jXyiznIGHTMjpEvQIosJQuHN+VWR +gtyxQJg0Ypri8otqJ3GMFDjZrd4yrRJYyeiTq7sXKwN6WKKnpxvXrPBH0MloOdj9 +EdRoVSyf+JZhPwQLrtkWyTuVUjR4maxxn4uCacrgFC06g3DhLUvGvTVsFFZHGdV7 +wfjQ+rrQ/Ht8NWevz4b/GeTBoz2jD2wtj7jA5faO0ja5RHLHnBD9X67eacKnZnZN +VMDRhUrlTCvrCWIL0rp5BZ8QmNdhZ7DZurxURbHBt3B9CjZ4D3AhYialP+TI+99j +pvo6jgQ0P0LzQ0XwUuxKpzuyA7Wrx1Yu8ZjJsUErjP5bNAzue3mpGy+f5zOZFR8w +eDz9AS6RSZdKPV2/zWXRdu5AqCT1z1SOyUvFWsHnvw/MujF94busXtc/gSyxvYw1 +UaYAlGoSSbzLl1OrBcd8hwL2bpKIg0EHFUShnqCGtQkCAwEAAaOB6DCB5TAOBgNV +HQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU9EWNJwcL +PP6c6x1ML5eOFr4X/yMwHwYDVR0jBBgwFoAUIr4TSIHNjAWPbuuKfTGBb1pgzTkw +RAYIKwYBBQUHAQEEODA2MDQGCCsGAQUFBzAChihodHRwczovL3d3dy5wbHVtZXdp +ZmkuY29tL2NhL3Jvb3QtY2EuY2VyMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHBzOi8v +d3d3LnBsdW1ld2lmaS5jb20vY2Evcm9vdC1jYS5jcmwwDQYJKoZIhvcNAQELBQAD +ggIBABsiEdWtDoblBozLh0k5lYcfXdtABv2hYD5Np+ijg+TftIR8N9dlFU7zE4qV +y0rcqQeU1tn/VpfEeWoWXunxXSFaKjpvXYH3yfA5SlWR1adkVGXgeUy3xVMUz5Sv +SZi1fHNuW7tWvCYuUslQv3gpt2hjmPt18zMOAoM88/9w33d30tjS8vGnB3t/+Kqc +m2pWoB0In1taWQWRJFy9YlF5cpZlK+mItZOMtCXU2/cdcT1mJOEH1OrNygkxWO30 +QqIesT59T+W0hBrhN5p7lmRB0BSMN16mP9faLnpoIo8e+22rpZvozypqkz2VkfZ6 +i4f7rI6IZSMhh/ciMOzn3oZdSzW/3a3KvYiF/HBf781j6qqQG53HP/VH4kSByKW7 +Qe543gNRo9hqRnX6RKHWla6ilk3KhULvt8tlooU7uDVNru8TUSJyAeoaZ37g5wyE +dvFn7JTc8OKDAsKtwvqwRAFZX484aXXfu4I68NWoaT9sKTRtfw1plfpqRTiLZY03 +YZ4O+TxuoR/zXc+tLL/MIQmY40WRL6ID3PhUvar26GHVqFo5Yi2xuPELRczId98i +qQYESgPHx5yJyJVwLpY+Wn7vMV+0D6MbP8ry5GY+inE2XS+H8GFvSF/M7jQiF/ff +CaQO9J7UdvwU2ytBpPzg5VQS+dOc0V0vFtf7FktdE/hdQn5X +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGSTCCBDGgAwIBAgIEEAAABDANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV +UzEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4xKzApBgNVBAsMIlBsdW1lIERl +c2lnbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHTAbBgNVBAMMFFBsdW1lIERlc2ln +biBSb290IENBMB4XDTE4MDEyMjIzMjMzOVoXDTI4MDEyMjIzMjMzOVowbTELMAkG +A1UEBhMCVVMxGjAYBgNVBAoMEVBsdW1lIERlc2lnbiBJbmMuMSswKQYDVQQLDCJQ +bHVtZSBEZXNpZ24gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRUwEwYDVQQDDAxQbHVt +ZSBUTFMgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDSDVhBzdBE +OM7oi7YzRevbzmM5dJhYKC+l44lFnltTIObbFk4QGN/sGQmgtZybEHtBnFgbamb5 +sIJsBVCkNFojFjg/HQwDc7TpwWN339t3Ih7iXmReiEfp8h1msWQRBpP3+d3E56ZP +PlJwivbw3ywfXSv7QlxSZ5iJeC6amPohvj3/VJeqM5c8hiiDuuZsZMAaW2Yl9gm/ +keM//Z7AfIGjbidUmJ9nfDftNPexqzx82RROATONIglk3PXjZxAyKSEuYS0djuPK +XXu5j8w222efdS6ARufpEZAO5LH/MVPdZpT1Emzh+uKjTQYlL0Flu8PyP30Do/cK +KBGMwZYAV4op8or8ntK7ndDTu3Xr6tq6g6KduxUjVukXpAmQhbwoGRUzJj4zC3oM +QkIYLlM1JOUrIlSw0s/E2ONNaWhL89bNFw3/LOhG6yAjbeJvjsebB/iQEvVJQfmV +i73QNwQQ93kCj+/unIkc+hi1/Vjuhkx3Q+LV4wjG4iaUoPlf49K1SqV9xDcc+2KF +0K8sVQ4Tqb2UQYp63C44HEZzRS3fhBp7xmEBTncCOckttqz1zCZQ0dcuyYm3bovf +NO5ur7OvvNL7ALJz9ah56v5KUDDqeH+aRm8i/rYdDSpcNm5kA9Ct2Q7/RSCCqFlO +bk+1yEkgAm9Jkebvi5L05dJryhXw31cXVwIDAQABo4HoMIHlMA4GA1UdDwEB/wQE +AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTKifKsuPwRxf+47Nsr +UHqivPBIkTAfBgNVHSMEGDAWgBQivhNIgc2MBY9u64p9MYFvWmDNOTBEBggrBgEF +BQcBAQQ4MDYwNAYIKwYBBQUHMAKGKGh0dHBzOi8vd3d3LnBsdW1ld2lmaS5jb20v +Y2Evcm9vdC1jYS5jZXIwOQYDVR0fBDIwMDAuoCygKoYoaHR0cHM6Ly93d3cucGx1 +bWV3aWZpLmNvbS9jYS9yb290LWNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAjG4R +nkcVdO4oQqjJeWLIdNu48V3T7CB08t3sqjQaxu4gAXfYm8a+tdubff6Dg0PuTFzh +edogXQchaEiYeEFTPNrz4hf5NhS+9t2PKcEpAKCbY6vjpfT9F5gUDrXmfUZnLIUV +SVXZ6NC+/jI56cAykbCv5ytYxSE0LxSgA3OLZyd4QESJdSJIkCw7s3nDx7rv05Np +UjQuFu1+WbXxUkrKYZBCTwczuKsDc2syiscC2sBUydDbK1jySV1og3nY6JXojNSa +V8OtnsnAUdD8Gbg38UNFb3SN7VmE1RIYgXgj7tVEKW/Rhyf49LCchAl+CO2m9TKW +ZPA2NcQ94b++VoreAdkpH3eOkko12RofWQo+wHT/g6qm668L7exONawjmU+Or2Wj +TXJFz5xb57kEnZjyXX4GgCxVSr8hHPA0+gFRPS4mkUZAQaH5XkODvcLAJ6CCSYIp +78B89VI8lkSji0wanlGcrSbUVHg6bVNw++gW//N4DRfqURRqYwDLQt6BXi11vgSu +l8NrrzBLU7leb1+IcY5p8g+z9HE4PM7uxd9fcP/P3Rldq7EW9V1NIXTn0kPHJd2C +zDReVg7t/tCFWM6wyXL1KKuXd36Py1XxATsgEwkmfXJn4QjOn60NK/SxTDKIBfvZ +9iWfWz/J3JLDRMk5Y/5CFuC6lm+6cHkbT4WR3wA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtjCCA56gAwIBAgIJANHraQLcwSsGMA0GCSqGSIb3DQEBCwUAMHAxCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJDQTEaMBgGA1UECgwRUGx1bWUgRGVzaWduIEluYy4x +IjAgBgNVBAsMGUZVVCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFDASBgNVBAMMC0ZV +VCBSb290IENBMB4XDTcwMDEwMTAwMDAwMFoXDTM1MDEwMTAwMDAwMFowcDELMAkG +A1UEBhMCVVMxCzAJBgNVBAgMAkNBMRowGAYDVQQKDBFQbHVtZSBEZXNpZ24gSW5j +LjEiMCAGA1UECwwZRlVUIENlcnRpZmljYXRlIEF1dGhvcml0eTEUMBIGA1UEAwwL +RlVUIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0bsOS +h0qYopNmTI0mFeR1tQvpL+a8TR6nmHKb00QeX6XXhb2EgJpPuxI+8sV+gh9SOwFl +2j5ozFID+BA2FH41GiNCNVVurV7xbW39/4oe1WVpbkkR9tSCnECsms1xMiLfH9Hs +XrsD9v2WDczhXoHakF4T1//fn3+OqrYUHiAI2wdQUqZYh55AWY0n1oNVJ/GlSUBW +ZqD/xe8xz0ZmxNE57swXtyYC7dDRO09DCWFSsLfd9PK9ohgNGp0oKlVeQogpM1Qf +nQNnzFjUffi8GTUZdce4+o+Q0sTOoucqFxyEXkNFmGtuVkAG3fL6sMq03w1iLDBs +7RkxWSFwL3VhM0L5kJ9ZW7nYnc61i/Va/k0Aj0Uwj+zJMKDQlWTyI5tTd+RRnEXm +WHQNZZ5d+BKcOlDT8Q0VJttC5WUMEhuEVKw1gghClBoQJhKmhOkNvgMyuwYJAgnZ +GXsEEWegUEJtlIoIEw7ztflZrL5ohl0fidBZS6RrlsktDz+wTOqykVTUeD8Q4n1W +s0vSYKRuWp/99RvZBW61NP+OFm8wk1lgvTR2FiwWJUqUy24cd5T/83ykUHEffhG7 +/uTsq2dE8rrcAQkBKPyWlilQadjHoJcjF4l2xcWtoJByAuyNKgD9tG34nfnMb4vu +wYuGUU2g4CjnUjCROHBbrDBujsN2k69j8mnJowIDAQABo1MwUTAdBgNVHQ4EFgQU +G5SceRGGaTvFg7pKHH9/YUVA5j4wHwYDVR0jBBgwFoAUG5SceRGGaTvFg7pKHH9/ +YUVA5j4wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAPRXTOPz8 +A1ua9pNwII1sK+DwSkQOxsnD6nkrbTkgLIQlPS0qgEzYh29nySDTXqpa1QV6A0E3 +PMOdZ5tfU/ZYepaJT6346bXzH9mb85zjNAIZrWxHKq/ptGJl8karkNftw/CuGOVi +WZ4am6L5YQu8lmxfbwWrHSJ++54BkoQ4Gih3JH+JngDqFBiq6eIejTEa+wiZgvIy +r/iJLUIHHzggtW13YUM/dfhvCVGagUZlEybCixPErUpvSsRLHoQHDc47ZtT/rIRZ +cNRdsgUR4LpmbdrPkbxYYe2nkSjflZf9h4sOfmG0qAgwHSgch5haW8pPX1cIEZUx +qw1yQezlHVKbjrQl7FtmLaItAwhzPvnMkFyuGI3tXy+YE8hbaqLlY46bI0XDxCMJ +gPcgs64R9GB1nYZgmsD3Z34uf9pOpDyemIMVKQ+8cJ5sdJaAkXV0C09xLz18Ekhg +Jh4/dwWqb+ilB6cN7bYlofJw6fj0pHic/JKtSrGTnB9FY7QB+NV2/aXitpQWd8ri +qplIvY9jXW5679oJy77MeZ774L0X7atx26bIBHD5j7wqC93dlSH6bGJMqg2yzITT +meZHKAkvZlsbOxLicnu7wNfx/mBXwMD0cI+uZ/3iP9DjC32WDjxiugaerjQEsEOK +ScfSziG+kVSfSLC4Cb4L2qmkptI9a4/HjXY= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/files/unit.mk b/src/fut/shell/tools/rpi/files/unit.mk new file mode 100644 index 00000000..974a4138 --- /dev/null +++ b/src/fut/shell/tools/rpi/files/unit.mk @@ -0,0 +1,36 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_rpi_files + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/rpi/files + +UNIT_FILE := fut_controller.pem +UNIT_FILE += haproxy.cfg +UNIT_FILE += plume_ca_chain.pem diff --git a/src/fut/shell/tools/rpi/start_cloud_simulation.sh b/src/fut/shell/tools/rpi/start_cloud_simulation.sh new file mode 100755 index 00000000..3b8fd2cb --- /dev/null +++ b/src/fut/shell/tools/rpi/start_cloud_simulation.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +help() +{ +cat << EOF +Usage: ${MY_NAME} [--help|-h] [--stop|-s] + +OPTIONS: + --help|-h : this help message + --stop|-s : stop the service instead of starting it + +Script configures and (re)starts haproxy that acts as simulated cloud. +EOF +} + +ARGS="" +# parse command line arguments +while [[ "${1}" == -* ]]; do + option="${1}" + shift + case "${option}" in + -h|--help) + help + exit 0 + ;; + -s|--stop) + stop_cloud_simulation + exit 0 + ;; + -r|--restart) + stop_cloud_simulation + ;; + -*) + help + exit 0 + ;; + esac +done + +start_cloud_simulation diff --git a/src/fut/shell/tools/rpi/um/um_create_corrupt_image_file.sh b/src/fut/shell/tools/rpi/um/um_create_corrupt_image_file.sh new file mode 100755 index 00000000..38490702 --- /dev/null +++ b/src/fut/shell/tools/rpi/um/um_create_corrupt_image_file.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +usage="$(basename "$0") [-h] \$1 + +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 1 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +um_fw_path=$1 + +um_create_corrupt_image "$um_fw_path" diff --git a/src/fut/shell/tools/rpi/um/um_create_corrupt_md5_file.sh b/src/fut/shell/tools/rpi/um/um_create_corrupt_md5_file.sh new file mode 100755 index 00000000..c1d254a6 --- /dev/null +++ b/src/fut/shell/tools/rpi/um/um_create_corrupt_md5_file.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +usage="$(basename "$0") [-h] \$1 \$2 + +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 1 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +um_file_path=$1 + +um_create_corrupt_md5_file "$um_file_path" \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/um/um_create_fw_key_file.sh b/src/fut/shell/tools/rpi/um/um_create_fw_key_file.sh new file mode 100755 index 00000000..8c3a16cf --- /dev/null +++ b/src/fut/shell/tools/rpi/um/um_create_fw_key_file.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +usage="$(basename "$0") [-h] \$1 \$2 + +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +um_fw_path=$1 +um_fw_key=$2 + +um_create_fw_key_file "$um_fw_path" "$um_fw_key" \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/um/um_create_md5_file.sh b/src/fut/shell/tools/rpi/um/um_create_md5_file.sh new file mode 100755 index 00000000..614c7baa --- /dev/null +++ b/src/fut/shell/tools/rpi/um/um_create_md5_file.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +usage="$(basename "$0") [-h] \$1 \$2 + +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 1 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +um_file_path=$1 + +um_create_md5_file "$um_file_path" \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/um/um_encrypt_image.sh b/src/fut/shell/tools/rpi/um/um_encrypt_image.sh new file mode 100755 index 00000000..43604f1f --- /dev/null +++ b/src/fut/shell/tools/rpi/um/um_encrypt_image.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +current_dir=$(dirname "$(realpath "$BASH_SOURCE")") +fut_topdir="$(realpath "$current_dir"/../../..)" +source "$fut_topdir/lib/rpi_lib.sh" + +usage="$(basename "$0") [-h] \$1 \$2 + +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +um_fw_unc_path=$1 +um_fw_key_path=$2 + +um_encrypt_image "$um_fw_unc_path" "$um_fw_key_path" \ No newline at end of file diff --git a/src/fut/shell/tools/rpi/um/unit.mk b/src/fut/shell/tools/rpi/um/unit.mk new file mode 100644 index 00000000..fc47a922 --- /dev/null +++ b/src/fut/shell/tools/rpi/um/unit.mk @@ -0,0 +1,38 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_um_tools + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/rpi/um + +UNIT_FILE := um_create_corrupt_image_file.sh +UNIT_FILE += um_create_corrupt_md5_file.sh +UNIT_FILE += um_create_fw_key_file.sh +UNIT_FILE += um_create_md5_file.sh +UNIT_FILE += um_encrypt_image.sh diff --git a/src/fut/shell/tools/rpi/unit.mk b/src/fut/shell/tools/rpi/unit.mk new file mode 100644 index 00000000..ed5f1c90 --- /dev/null +++ b/src/fut/shell/tools/rpi/unit.mk @@ -0,0 +1,35 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_rpi_tools + +UNIT_DISABLE := n + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tools/rpi + +UNIT_FILE := connect_to_wpa2.sh +UNIT_FILE += start_cloud_simulation.sh diff --git a/src/hello_world/fut/hello_world_insert_demo_fail_to_update.sh b/src/hello_world/fut/hello_world_insert_demo_fail_to_update.sh new file mode 100755 index 00000000..90d68b15 --- /dev/null +++ b/src/hello_world/fut/hello_world_insert_demo_fail_to_update.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# This test script will simulate an issue with the manager target layer +# implementation, which will look like failing to update OVSDB - layer 1 test. +# This test is expected to fail for demonstration purposes, to show what +# happens when tests fail due to incorrect manager implementation - in this +# case, manager failing to updatte Node_State table, yet still writing to file. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh + +DEMO_MODULE_NAME="hello-world" +DEMO_OUTPUT_FILE=${DEMO_OUTPUT_FILE:-"/tmp/$DEMO_MODULE_NAME-demo"} +DEMO_TEST_TITLE="Fail to update ovsdb table" +# Input arguments: +DEMO_TEST_KEY=${1:-"demo"} +DEMO_TEST_VALUE=${2:-"fail-to-update"} + +log_title "$DEMO_MODULE_NAME: $DEMO_TEST_TITLE" + +log "Test preconditions: Clean ovsdb table if not empty" +${OVSH} delete Node_Config || die "Failed to empty table" + +log "Start test: Write to Node_Config" +${OVSH} insert Node_Config module:=$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY value:=$DEMO_TEST_VALUE || die "Failed" + +# Level 1 test - checking correct OVSDB behaviour +log "Waiting for Node_State table to reflect entry in Node_Config table" +${OVSH} wait Node_State --where module==$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY module:=$DEMO_MODULE_NAME value:=$DEMO_TEST_VALUE || die_with_code 11 "Failed" + +# Level 2 test - checking the expected actions were applied to the system +# Note: This test is redundant, due to above test failing, but is kept for clarity +log "Checking correct system action was performed" +log "Verifying existence of file $DEMO_OUTPUT_FILE." +[ -f $DEMO_OUTPUT_FILE ] || die_with_code 21 "File not present on system!" +file_content="$(cat $DEMO_OUTPUT_FILE)" +log "Expecting file content: $DEMO_TEST_KEY=$DEMO_TEST_VALUE" +[ "$file_content" = "$DEMO_TEST_KEY=$DEMO_TEST_VALUE" ] || die_with_code 22 "File content not correct: $file_content" + +pass "$DEMO_TEST_TITLE - TEST PASSED" diff --git a/src/hello_world/fut/hello_world_insert_demo_fail_to_write.sh b/src/hello_world/fut/hello_world_insert_demo_fail_to_write.sh new file mode 100755 index 00000000..4f98aad1 --- /dev/null +++ b/src/hello_world/fut/hello_world_insert_demo_fail_to_write.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# This test script will simulate an issue with the manager target layer +# implementation, which will look like failing to write to file - layer 2 test. +# This test is expected to fail for demonstration purposes, to show what +# happenswhen tests fail due to incorrect manager implementation - in this +# case, manager failing to write to file, but still updating Node_State table. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh + +DEMO_MODULE_NAME="hello-world" +DEMO_OUTPUT_FILE=${DEMO_OUTPUT_FILE:-"/tmp/$DEMO_MODULE_NAME-demo"} +DEMO_TEST_TITLE="Fail to write to file" +# Input arguments: +DEMO_TEST_KEY=${1:-"demo"} +DEMO_TEST_VALUE=${2:-"fail-to-write"} + +log_title "$DEMO_MODULE_NAME: $DEMO_TEST_TITLE" + +log "Test preconditions: Clean ovsdb table if not empty" +${OVSH} delete Node_Config || die "Failed to empty table" + +log "Start test: Write to Node_Config" +${OVSH} insert Node_Config module:=$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY value:=$DEMO_TEST_VALUE || die "Failed" + +# Level 1 test - checking correct OVSDB behaviour +log "Waiting for Node_State table to reflect entry in Node_Config table" +${OVSH} wait Node_State --where module==$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY module:=$DEMO_MODULE_NAME value:=$DEMO_TEST_VALUE || die_with_code 11 "Failed" + +# Level 2 test - checking the expected actions were applied to the system +log "Checking correct system action was performed" +log "Verifying existence of file $DEMO_OUTPUT_FILE." +[ -f $DEMO_OUTPUT_FILE ] || die_with_code 21 "File not present on system!" +file_content="$(cat $DEMO_OUTPUT_FILE)" +log "Expecting file content: $DEMO_TEST_KEY=$DEMO_TEST_VALUE" +[ "$file_content" = "$DEMO_TEST_KEY=$DEMO_TEST_VALUE" ] || die_with_code 22 "File content not correct: $file_content" + +pass "$DEMO_TEST_TITLE - TEST PASSED" diff --git a/src/hello_world/fut/hello_world_insert_foreign_module.sh b/src/hello_world/fut/hello_world_insert_foreign_module.sh new file mode 100755 index 00000000..5969404a --- /dev/null +++ b/src/hello_world/fut/hello_world_insert_foreign_module.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# This test script will verify that the manager only operates on ovsdb entries +# that match the "module" field with value "hello-world", and not others. This +# shows that several managers can use the same ovsdb table and not interfere +# with each other, if the correct "module" field value is chosen. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh + +DEMO_MODULE_NAME="hello-world" +DEMO_OUTPUT_FILE=${DEMO_OUTPUT_FILE:-"/tmp/$DEMO_MODULE_NAME-demo"} +DEMO_TEST_TITLE="Fail to update ovsdb table" +# Input arguments: +DEMO_TEST_KEY=${1:-"fut-variable"} +DEMO_TEST_VALUE=${2:-"test-value"} +DEMO_TEST_FOREIGN_MODULE=${3:-"bye-bye"} + +DEMO_OUTPUT_ALT_FILE=${DEMO_OUTPUT_ALT_FILE:-"/tmp/$DEMO_TEST_FOREIGN_MODULE"} + +log_title "$DEMO_MODULE_NAME: $DEMO_TEST_TITLE" + +log "Test preconditions: Clean ovsdb table if not empty" +${OVSH} delete Node_Config || die "Failed to empty table" + +log "Start test: Write to Node_Config" +${OVSH} insert Node_Config module:=$DEMO_TEST_FOREIGN_MODULE key:=$DEMO_TEST_KEY value:=$DEMO_TEST_VALUE || die "Failed" + +# Level 1 test - checking correct OVSDB behaviour +log "Checking for Node_State table entry, reflecting entry in Node_Config table" +${OVSH} select Node_State --where module==$DEMO_TEST_FOREIGN_MODULE key:=$DEMO_TEST_KEY module:=$DEMO_TEST_FOREIGN_MODULE value:=$DEMO_TEST_VALUE || die_with_code 11 "Failed - entry found!" +log "OK: no entry found, continuing" + +# Level 2 test - checking that no actions were applied to the system +log "Checking correct system action was performed" +log "Verifying existence of file $DEMO_OUTPUT_FILE." +if [ -f $DEMO_OUTPUT_FILE ]; then + log "File present on system, expecting empty file" + [ -n "$(cat $DEMO_OUTPUT_FILE)" ] || die_with_code 22 "File not empty!" +else + log "OK: File $DEMO_OUTPUT_FILE not present on system" +fi +log "Verifying existence of file $DEMO_OUTPUT_ALT_FILE." +[ -f $DEMO_OUTPUT_ALT_FILE ] && die_with_code 23 "File exists!" + +pass "$DEMO_TEST_TITLE - TEST PASSED" diff --git a/src/hello_world/fut/hello_world_insert_module_key_value.sh b/src/hello_world/fut/hello_world_insert_module_key_value.sh new file mode 100755 index 00000000..1e10c280 --- /dev/null +++ b/src/hello_world/fut/hello_world_insert_module_key_value.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# This is a basic test script, verifying what happens when writing to ovsdb. +# It verifies the manager target layer implementation in two layers of tests: +# Layer 1: verify that whatever was written into Node_Config table +# is reflected in Node_State table, after supposed. +# Layer 2: verify that the expected action resulted in changes on the system +# is reflected in Node_State table, after supposed expected action. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh + +DEMO_MODULE_NAME="hello-world" +DEMO_OUTPUT_FILE=${DEMO_OUTPUT_FILE:-"/tmp/$DEMO_MODULE_NAME-demo"} +DEMO_TEST_TITLE="Insert module-key-value into OVSDB" +# Input arguments: +DEMO_TEST_KEY=${1:-"fut-variable"} +DEMO_TEST_VALUE=${2:-"test-value"} + +log_title "$DEMO_MODULE_NAME: $DEMO_TEST_TITLE" + +log "Test preconditions: Clean ovsdb table if not empty" +${OVSH} delete Node_Config || die "Failed to empty table" + +log "Start test: Write to Node_Config" +${OVSH} insert Node_Config module:=$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY value:=$DEMO_TEST_VALUE || die "Failed" + +# Level 1 test - checking correct OVSDB behaviour +log "Waiting for Node_State table to reflect entry in Node_Config table" +${OVSH} wait Node_State --where module==$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY module:=$DEMO_MODULE_NAME value:=$DEMO_TEST_VALUE || die_with_code 11 "Failed" + +# Level 2 test - checking the expected actions were applied to the system +log "Checking correct system action was performed" +log "Verifying existence of file $DEMO_OUTPUT_FILE." +[ -f $DEMO_OUTPUT_FILE ] || die_with_code 21 "File not present on system!" +file_content="$(cat $DEMO_OUTPUT_FILE)" +log "Expecting file content: $DEMO_TEST_KEY=$DEMO_TEST_VALUE" +[ "$file_content" = "$DEMO_TEST_KEY=$DEMO_TEST_VALUE" ] || die_with_code 22 "File content not correct: $file_content" + +pass "$DEMO_TEST_TITLE - TEST PASSED" diff --git a/src/hello_world/fut/hello_world_setup.sh b/src/hello_world/fut/hello_world_setup.sh new file mode 100755 index 00000000..7d9d97ad --- /dev/null +++ b/src/hello_world/fut/hello_world_setup.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${LIB_OVERRIDE_FILE} + +DEMO_MANAGER_BIN_NAME="hello_world" + +log_title "$DEMO_MANAGER_BIN_NAME: SETUP" +device_init + +start_openswitch + +log "Ensure single instance of $DEMO_MANAGER_BIN_NAME" +killall_process_by_name "${DEMO_MANAGER_BIN_NAME}" + +log "Starting $DEMO_MANAGER_BIN_NAME" +start_specific_manager ${DEMO_MANAGER_BIN_NAME} || + raise "start_specific_manager $DEMO_MANAGER_BIN_NAME" -l "$fn_name" -fc + +log "Changing $DEMO_MANAGER_BIN_NAME log level to TRACE" +${OVSH} delete AW_Debug -w name==$DEMO_MANAGER_BIN_NAME +${OVSH} insert AW_Debug name:=$DEMO_MANAGER_BIN_NAME log_severity:=TRACE + +pass "Setup completed!" diff --git a/src/hello_world/fut/hello_world_update_module_key_value.sh b/src/hello_world/fut/hello_world_update_module_key_value.sh new file mode 100755 index 00000000..0a0b7bbf --- /dev/null +++ b/src/hello_world/fut/hello_world_update_module_key_value.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# This is a basic test script, confirming that updating existing ovsdb entries +# works as expected. It verifies the manager target layer implementation in +# two layers of tests: +# Layer 1: verify that whatever was written into Node_Config table +# is reflected in Node_State table, after supposed. +# Layer 2: verify that the expected action resulted in changes on the system +# is reflected in Node_State table, after supposed expected action. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh + +DEMO_MODULE_NAME="hello-world" +DEMO_OUTPUT_FILE=${DEMO_OUTPUT_FILE:-"/tmp/$DEMO_MODULE_NAME-demo"} +DEMO_TEST_TITLE="Update module-key-value in OVSDB" +# Input arguments: +DEMO_TEST_KEY=${1:-"fut-variable"} +DEMO_TEST_VALUE=${2:-"test-value"} +DEMO_TEST_ALT_VALUE=${3:-"changed-value"} + +log_title "$DEMO_MODULE_NAME: $DEMO_TEST_TITLE" + +# Table should have entry - insert if not true, e.g. if executing the test standalone +log "Test preconditions: Ovsdb table should have correct entry" +${OVSH} select Node_Config --where module==$DEMO_MODULE_NAME --where key==$DEMO_TEST_KEY --where value==$DEMO_TEST_VALUE +if [ $? -ne 0 ]; then + log "No entry or entry not correct! Clean and populate ovsdb table" + ${OVSH} delete Node_Config || die "Failed to empty table" + ${OVSH} insert Node_Config module:=$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY value:=$DEMO_TEST_VALUE || die "Failed to initialize test" + ${OVSH} wait Node_State --where value==$DEMO_TEST_VALUE module:=$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY value:=$DEMO_TEST_VALUE || die "Failed to initialize test" +fi + +log "Start test: Update an existing entry in Node_Config" +${OVSH} update Node_Config --where key==$DEMO_TEST_KEY module:=$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY value:=$DEMO_TEST_ALT_VALUE || die "Failed" + +# Level 1 test - checking correct OVSDB behaviour +log "Waiting for Node_State table to reflect changed entry in Node_Config table" +${OVSH} wait Node_State --where module==$DEMO_MODULE_NAME key:=$DEMO_TEST_KEY module:=$DEMO_MODULE_NAME value:=$DEMO_TEST_ALT_VALUE || die_with_code 11 "Failed" + +# Level 2 test - checking the expected actions were applied to the system +log "Checking correct system action was performed" +log "Verifying existence of file $DEMO_OUTPUT_FILE." +[ -f $DEMO_OUTPUT_FILE ] || die_with_code 21 "File not present on system!" +file_content="$(cat $DEMO_OUTPUT_FILE)" +log "Expecting file content: $DEMO_TEST_KEY=$DEMO_TEST_ALT_VALUE" +[ "$file_content" = "$DEMO_TEST_KEY=$DEMO_TEST_ALT_VALUE" ] || die_with_code 22 "File content not correct: $file_content" + +pass "$DEMO_TEST_TITLE - TEST PASSED" diff --git a/src/hello_world/fut/unit.mk b/src/hello_world/fut/unit.mk new file mode 100644 index 00000000..6520ed17 --- /dev/null +++ b/src/hello_world/fut/unit.mk @@ -0,0 +1,39 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_hello_world + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_HELLOWORLD),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/hello_world + +UNIT_FILE := hello_world_setup.sh +UNIT_FILE += hello_world_insert_demo_fail_to_update.sh +UNIT_FILE += hello_world_insert_demo_fail_to_write.sh +UNIT_FILE += hello_world_insert_foreign_module.sh +UNIT_FILE += hello_world_insert_module_key_value.sh +UNIT_FILE += hello_world_update_module_key_value.sh diff --git a/src/lib/arp_parse/inc/arp_parse.h b/src/lib/arp_parse/inc/arp_parse.h new file mode 100644 index 00000000..59f48021 --- /dev/null +++ b/src/lib/arp_parse/inc/arp_parse.h @@ -0,0 +1,230 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARP_PARSE_H_INCLUDED +#define ARP_PARSE_H_INCLUDED + +#include +#include +#include +#include + +#include "fsm.h" +#include "neigh_table.h" +#include "net_header_parse.h" +#include "os_types.h" + +/** + * @brief ehternet ARP + */ +struct eth_arp +{ + os_macaddr_t *s_eth; /* Sender ethernet address */ + uint32_t s_ip; /* Sender IP address */ + os_macaddr_t *t_eth; /* Target ethernet address */ + uint32_t t_ip; /* Target IP address */ +}; + + +/** + * @brief address resolution protocol parser + * + * The parser contains the parsed info for the packet currently processed + * It embeds: + * - the network header, + * - the data length which excludes the network header + * - the amount of data parsed + */ +struct arp_parser +{ + struct net_header_parser *net_parser; /* network header parser */ + size_t data_len; /* Non-network related data length */ + uint8_t *data; /* Non-network data pointer */ + size_t parsed; /* Parsed bytes */ + size_t arp_len; + int op; + bool gratuitous; + struct eth_arp arp; + struct neighbour_entry sender; + struct neighbour_entry target; +}; + + +/** + * @brief a session, instance of processing state and routines. + * + * The session provides an executing instance of the services' + * provided by the plugin. + * It embeds: + * - a fsm session + * - state information + * - a packet parser + */ +struct arp_session +{ + struct fsm_session *session; + bool initialized; + time_t timestamp; + uint64_t ttl; + struct arp_parser parser; + ds_tree_node_t session_node; +}; + +/** + * @brief the plugin cache, a singleton tracking instances + * + * The cache tracks the global initialization of the plugin + * and the running sessions. + */ +struct arp_cache +{ + bool initialized; + ds_tree_t fsm_sessions; +}; + + +/** + * @brief periodic routine + * + * @param session the fsm session keying the arp session to process + */ +void +arp_plugin_periodic(struct fsm_session *session); + + +/** + * @brief session initialization entry point + * + * Initializes the plugin specific fields of the session, + * like the periodic routines called by fsm. + * @param session pointer provided by fsm + */ +int +arp_plugin_init(struct fsm_session *session); + + +/** + * @brief update routine + * + * @param session the fsm session keying the arp session to update + */ +void +arp_plugin_update(struct fsm_session *session); + + +/** + * @brief session exit point + * + * Frees up resources used by the session. + * @param session pointer provided by fsm + */ +void +arp_plugin_exit(struct fsm_session *session); + + +/** + * @brief session packet processing entry point + * + * packet processing handler. + * @param session the fsm session + * @param net_parser the container of parsed header and original packet + */ +void +arp_plugin_handler(struct fsm_session *session, + struct net_header_parser *net_parser); + + +/** + * @brief parses a l2uf message + * + * @param parser the parsed data container + * @return the size of the parsed message, or 0 on parsing error. + */ +size_t +arp_parse_message(struct arp_parser *parser); + + +/** + * @brief parses the received message content + * + * @param parser the parsed data container + * @return the size of the parsed message content, or 0 on parsing error. + */ +size_t +arp_parse_content(struct arp_parser *parser); + + +/** + * @brief process the parsed message + * + * Place holder for message content processing + * @param n_session the l2uf session pointing to the parsed message + */ +void +arp_process_message(struct arp_session *a_session); + + +/** + * @brief looks up a session + * + * Looks up a session, and allocates it if not found. + * @param session the session to lookup + * @return the found/allocated session, or NULL if the allocation failed + */ +struct arp_session * +arp_lookup_session(struct fsm_session *session); + + +/** + * @brief Frees a arp session + * + * @param n_session the arp session to delete + */ +void +arp_free_session(struct arp_session *a_session); + + +/** + * @brief deletes a session + * + * @param session the fsm session keying the ndp session to delete + */ +void +arp_delete_session(struct fsm_session *session); + + +struct arp_cache * +arp_get_mgr(void); + +/** + * @brief checks if an arp packet gratuitous arp + * + * @param arp the arp parsed packet + * @return true if the arp packet is a gratuitous arp, false otherwise + */ +bool +arp_parse_is_gratuitous(struct eth_arp *arp); +#endif /* ARP_PARSE_H_INCLUDED */ diff --git a/src/lib/arp_parse/src/arp_parse.c b/src/lib/arp_parse/src/arp_parse.c new file mode 100644 index 00000000..74d219b9 --- /dev/null +++ b/src/lib/arp_parse/src/arp_parse.c @@ -0,0 +1,547 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "netdb.h" + +#include "const.h" +#include "ds_tree.h" +#include "log.h" +#include "neigh_table.h" +#include "arp_parse.h" +#include "assert.h" +#include "json_util.h" +#include "ovsdb.h" +#include "ovsdb_cache.h" +#include "ovsdb_table.h" +#include "schema.h" +#include "net_header_parse.h" + +static struct arp_cache +cache_mgr = +{ + .initialized = false, +}; + + +struct arp_cache * +arp_get_mgr(void) +{ + return &cache_mgr; +} + + +/** + * @brief compare sessions + * + * @param a session pointer + * @param b session pointer + * @return 0 if sessions matches + */ +static int +arp_session_cmp(void *a, void *b) +{ + uintptr_t p_a = (uintptr_t)a; + uintptr_t p_b = (uintptr_t)b; + + if (p_a == p_b) return 0; + if (p_a < p_b) return -1; + return 1; +} + + +/** + * @brief session initialization entry point + * + * Initializes the plugin specific fields of the session, + * like the packet parsing handler and the periodic routines called + * by fsm. + * @param session pointer provided by fsm + */ +int +arp_plugin_init(struct fsm_session *session) +{ + struct fsm_parser_ops *parser_ops; + struct arp_session *arp_session; + struct arp_parser *parser; + struct arp_cache *mgr; + + if (session == NULL) return -1; + + mgr = arp_get_mgr(); + + /* Initialize the manager on first call */ + if (!mgr->initialized) + { + ds_tree_init(&mgr->fsm_sessions, arp_session_cmp, + struct arp_session, session_node); + mgr->initialized = true; + } + + /* Look up the arp session */ + arp_session = arp_lookup_session(session); + if (arp_session == NULL) + { + LOGE("%s: could not allocate the arp parser", __func__); + + return -1; + } + + /* Bail if the session is already initialized */ + if (arp_session->initialized) return 0; + + parser = &arp_session->parser; + parser->sender.ipaddr = calloc(1, sizeof(*parser->sender.ipaddr)); + if (parser->sender.ipaddr == NULL) + { + LOGE("%s: could not allocate sender ip storage", __func__); + goto exit_on_error; + } + + parser->target.ipaddr = calloc(1, sizeof(*parser->sender.ipaddr)); + if (parser->target.ipaddr == NULL) + { + LOGE("%s: could not allocate sender ip storage", __func__); + goto exit_on_error; + } + + /* Set the fsm session */ + session->ops.update = arp_plugin_update; + session->ops.periodic = arp_plugin_periodic; + session->ops.exit = arp_plugin_exit; + session->handler_ctxt = arp_session; + + /* Set the plugin specific ops */ + parser_ops = &session->p_ops->parser_ops; + parser_ops->handler = arp_plugin_handler; + + /* Wrap up the session initialization */ + arp_session->session = session; + arp_session->timestamp = time(NULL); + arp_plugin_update(session); + + arp_session->initialized = true; + LOGD("%s: added session %s", __func__, session->name); + + return 0; + +exit_on_error: + arp_delete_session(session); + + return -1; +} + + +/** + * @brief session exit point + * + * Frees up resources used by the session. + * @param session pointer provided by fsm + */ +void +arp_plugin_exit(struct fsm_session *session) +{ + struct arp_cache *mgr; + + mgr = arp_get_mgr(); + if (!mgr->initialized) return; + + arp_delete_session(session); + return; +} + + +/** + * @brief session packet processing entry point + * + * packet processing handler. + * @param args the fsm session + * @param net_parser the packet container + */ +void +arp_plugin_handler(struct fsm_session *session, + struct net_header_parser *net_parser) +{ + struct arp_session *a_session; + struct arp_parser *parser; + size_t len; + + a_session = (struct arp_session *)session->handler_ctxt; + parser = &a_session->parser; + parser->net_parser = net_parser; + + len = arp_parse_message(parser); + if (len == 0) return; + + arp_process_message(a_session); + + parser->arp.s_eth = NULL; + parser->arp.t_eth = NULL; + parser->gratuitous = false; + + return; +} + + +/** + * @brief parses the received message + * + * @param parser the parsed data container + * @return the size of the parsed message, or 0 on parsing error. + */ +size_t +arp_parse_message(struct arp_parser *parser) +{ + struct net_header_parser *net_parser; + size_t len; + + if (parser == NULL) return 0; + + /* Some basic validation */ + net_parser = parser->net_parser; + + /* Parse network header */ + parser->parsed = net_parser->parsed; + parser->data = net_parser->data; + + /* Adjust payload length to remove potential ethernet padding */ + parser->arp_len = net_parser->packet_len - net_parser->parsed; + + /* Parse the message content */ + len = arp_parse_content(parser); + return len; +} + + +bool +arp_populate_neigh_entries(struct arp_session *a_session) +{ + struct fsm_session_conf *conf; + struct sockaddr_storage *dst; + struct arp_parser *parser; + struct sockaddr_in *in; + struct eth_arp *arp; + + parser = &a_session->parser; + arp = &parser->arp; + conf = a_session->session->conf; + + dst = parser->sender.ipaddr; + in = (struct sockaddr_in *)dst; + + memset(in, 0, sizeof(struct sockaddr_in)); + in->sin_family = AF_INET; + memcpy(&in->sin_addr, &arp->s_ip, sizeof(in->sin_addr)); + + parser->sender.mac = arp->s_eth; + parser->sender.ifname = conf->if_name; + parser->sender.source = FSM_ARP; + + if (arp->t_eth == NULL) return true; + + dst = parser->target.ipaddr; + in = (struct sockaddr_in *)dst; + + memset(in, 0, sizeof(struct sockaddr_in)); + in->sin_family = AF_INET; + memcpy(&in->sin_addr, &arp->t_ip, sizeof(in->sin_addr)); + + parser->target.mac = arp->t_eth; + parser->target.ifname = conf->if_name; + parser->target.source = FSM_ARP; + + return true; +} + + +/** + * @brief checks if an arp packet gratuitous arp + * + * @param arp the arp parsed packet + * @return true if the arp packet is a gratuitous arp, false otherwise + */ +bool +arp_parse_is_gratuitous(struct eth_arp *arp) +{ + os_macaddr_t fmac = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }; + os_macaddr_t zmac = { 0 }; + os_macaddr_t *t_eth; + int cmp; + + t_eth = arp->t_eth; + if (t_eth == NULL) return false; + + cmp = memcmp(t_eth, &zmac, sizeof(zmac)); + if (cmp == 0) return true; + + cmp = memcmp(t_eth, &fmac, sizeof(fmac)); + if (cmp == 0) return true; + + return false; +} + + +/** + * @brief parses the received message content + * + * @param parser the parsed data container + * @return the size of the parsed message content, or 0 on parsing error. + */ +size_t +arp_parse_content(struct arp_parser *parser) +{ + struct net_header_parser *net_parser; + struct eth_arp *arp; + struct arphdr *arph; + uint16_t ar_hrd; + uint16_t ar_pro; + uint16_t ar_op; + size_t len; + + /* basic validation */ + net_parser = parser->net_parser; + arp = &parser->arp; + + arph = (struct arphdr *)(net_parser->data); + len = parser->arp_len; + if (len < sizeof(*arph)) return 0; + + ar_hrd = ntohs(arph->ar_hrd); + if (ar_hrd != ARPHRD_ETHER) return 0; + + ar_pro = ntohs(arph->ar_pro); + if (ar_pro != ETH_P_IP) return 0; + + if (arph->ar_hln != ETH_ALEN) return 0; + if (arph->ar_pln != 4) return 0; + + ar_op = ntohs(arph->ar_op); + if ((ar_op != ARPOP_REQUEST) && (ar_op != ARPOP_REPLY)) return 0; + parser->op = ar_op; + + /* Access HW/network mapping info */ + net_parser->data += sizeof(*arph); + net_parser->parsed += sizeof(*arph); + + arp->s_eth = (os_macaddr_t *)(net_parser->data); + net_parser->data += ETH_ALEN; + net_parser->parsed += ETH_ALEN; + + arp->s_ip = *(uint32_t *)(net_parser->data); + net_parser->data += 4; + net_parser->parsed += 4; + + if (ar_op == ARPOP_REPLY) + { + arp->t_eth = (os_macaddr_t *)(net_parser->data); + parser->gratuitous = arp_parse_is_gratuitous(arp); + net_parser->data += ETH_ALEN; + arp->t_ip = *(uint32_t *)(net_parser->data); + } + return len; +} + + +/** + * @brief process the parsed message + * + * Prepare a key to lookup the flow stats info, and update the flow stats. + * @param a_session the arp session pointing to the parsed message + */ +void +arp_process_message(struct arp_session *a_session) +{ + struct arp_parser *parser; + + /* basic validation */ + parser = &a_session->parser; + + arp_populate_neigh_entries(a_session); + parser->sender.cache_valid_ts = a_session->timestamp; + neigh_table_add(&parser->sender); + + if (parser->op == ARPOP_REQUEST) return; + + if (parser->gratuitous) return; + + /* Record the target IP mac mapping if available */ + if (parser->arp.t_eth != NULL) + { + parser->target.cache_valid_ts = a_session->timestamp; + neigh_table_add(&parser->target); + } +} + + +/** + * @brief looks up a session + * + * Looks up a session, and allocates it if not found. + * @param session the session to lookup + * @return the found/allocated session, or NULL if the allocation failed + */ +struct arp_session * +arp_lookup_session(struct fsm_session *session) +{ + struct arp_session *a_session; + struct arp_cache *mgr; + ds_tree_t *sessions; + + mgr = arp_get_mgr(); + sessions = &mgr->fsm_sessions; + + a_session = ds_tree_find(sessions, session); + if (a_session != NULL) return a_session; + + LOGD("%s: Adding new session %s", __func__, session->name); + a_session = calloc(1, sizeof(struct arp_session)); + if (a_session == NULL) return NULL; + + ds_tree_insert(sessions, a_session, session); + + return a_session; +} + + +/** + * @brief Frees a arp session + * + * @param a_session the arp session to free + */ +void +arp_free_session(struct arp_session *a_session) +{ + struct arp_parser *parser; + + parser = &a_session->parser; + free(parser->sender.ipaddr); + free(parser->target.ipaddr); + free(a_session); +} + + +/** + * @brief deletes a session + * + * @param session the fsm session keying the arp session to delete + */ +void +arp_delete_session(struct fsm_session *session) +{ + struct arp_session *a_session; + struct arp_cache *mgr; + ds_tree_t *sessions; + + mgr = arp_get_mgr(); + sessions = &mgr->fsm_sessions; + + a_session = ds_tree_find(sessions, session); + if (a_session == NULL) return; + + LOGD("%s: removing session %s", __func__, session->name); + ds_tree_remove(sessions, a_session); + arp_free_session(a_session); + + return; +} + + +#define FSM_ARP_CHECK_TTL (2*60) +/** + * @brief periodic routine + * + * @param session the fsm session keying the arp session to uprocess + */ +void +arp_plugin_periodic(struct fsm_session *session) +{ + struct arp_session *a_session; + struct arp_cache *mgr; + ds_tree_t *sessions; + double cmp_clean; + time_t now; + + mgr = arp_get_mgr(); + sessions = &mgr->fsm_sessions; + + a_session = ds_tree_find(sessions, session); + if (a_session == NULL) return; + + now = time(NULL); + cmp_clean = now - a_session->timestamp; + if (cmp_clean < FSM_ARP_CHECK_TTL) return; + + neigh_table_ttl_cleanup(a_session->ttl, OVSDB_ARP); + a_session->timestamp = now; +} + + +#define FSM_ARP_DEFAULT_TTL (36*60*60) +/** + * @brief update routine + * + * @param session the fsm session keying the arp session to update + */ +void +arp_plugin_update(struct fsm_session *session) +{ + struct arp_session *a_session; + struct arp_cache *mgr; + ds_tree_t *sessions; + unsigned long ttl; + char *str_ttl; + + mgr = arp_get_mgr(); + sessions = &mgr->fsm_sessions; + + a_session = ds_tree_find(sessions, session); + if (a_session == NULL) return; + + /* set the default timer */ + a_session->ttl = FSM_ARP_DEFAULT_TTL; + str_ttl = session->ops.get_config(session, "ttl"); + if (str_ttl == NULL) goto log_settings; + ttl = strtoul(str_ttl, NULL, 10); + if (ttl == 0 || ttl == ULONG_MAX) + { + LOGE("%s: conversion of %s failed: %d", __func__, str_ttl, errno); + goto log_settings; + } + a_session->ttl = (uint64_t)ttl; + +log_settings: + LOGI("%s: %s: setting neighbor entry ttl to %" PRIu64 " secs", __func__, + session->name, a_session->ttl); +} diff --git a/src/lib/arp_parse/tests/futs/create_arp_plugin.sh b/src/lib/arp_parse/tests/futs/create_arp_plugin.sh new file mode 100755 index 00000000..42436c8e --- /dev/null +++ b/src/lib/arp_parse/tests/futs/create_arp_plugin.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Series of generic routines updating ovsdb tables. +# TBD: It would make sense to commonize them all. + +# Check if a specific command is in the path. Bail if not found. +check_cmd() { + cmd=$1 + path_cmd=$(which ${cmd}) + if [ -z ${path_cmd} ]; then + echo "Error: could not find ${cmd} command in path" + exit 1 + fi + echo "found ${cmd} as ${path_cmd}" +} + +# usage +usage() { + echo "Usage: $0 [bridge_name] [interface name] [ofport]" +} + +# Create tap interface +gen_tap_cmd() { + cat << EOF +ovs-vsctl add-port ${bridge} ${intf} \ + -- set interface ${intf} type=internal \ + -- set interface ${intf} ofport_request=${ofport} +EOF +} + +# Bring tap interface up +tap_up_cmd() { + cat << EOF +ip link set ${intf} up +EOF +} + +# Mark the interface no-flood, only the traffic matching the flow filter +# will hit the plugin +gen_no_flood_cmd() { + cat << EOF +ovs-ofctl mod-port ${bridge} ${intf} no-flood +EOF +} + +# Create the openflow rule for the egress traffic +gen_oflow_cmd() { + cat << EOF +ovsh i Openflow_Config \ + token:=${of_token} \ + bridge:=${bridge} \ + table:=0 \ + priority:=${priority} \ + rule:=${of_rule} \ + action:="normal,output:${ofport}" +EOF +} + + +# Create a FSM config entry. Resorting to json format due some +# unexpected map programming errors. +gen_fsmc_cmd() { + cat << EOF +["Open_vSwitch", + { + "op": "insert", + "table": "Flow_Service_Manager_Config", + "row": { + "handler": "${fsm_handler}", + "if_name": "${intf}", + "pkt_capt_filter": "${filter}", + "plugin": "${plugin}", + "other_config": ["map",[["dso_init","${dso_init}"]]] + } + } +] +EOF +} + +# get pod's location ID +get_location_id() { + ovsh s AWLAN_Node mqtt_headers | \ + awk -F'"' '{for (i=1;i +#include +#include +#include +#include +#include +#include + +#include "neigh_table.h" +#include "arp_parse.h" +#include "json_util.h" +#include "log.h" +#include "qm_conn.h" +#include "target.h" +#include "unity.h" +#include "pcap.c" + +const char *test_name = "arp_plugin_tests"; + +#define OTHER_CONFIG_NELEMS 4 +#define OTHER_CONFIG_NELEM_SIZE 128 + +char g_other_configs[][2][OTHER_CONFIG_NELEMS][OTHER_CONFIG_NELEM_SIZE] = +{ + { + { + "mqtt_v", + }, + { + "dev-test/arp_plugin_0/4C70D0007B", + }, + }, + { + { + "mqtt_v", + }, + { + "dev-test/arp_1/4C70D0007B", + }, + }, +}; + + +/** + * @brief a set of sessions as delivered by the ovsdb API + */ +struct fsm_session_conf g_confs[2] = +{ + { + .handler = "arp_test_0", + .if_name = "arp_ut_intf_0", + }, + { + .handler = "arp_test_1", + .if_name = "arp_ut_intf_1", + } +}; + + +union fsm_plugin_ops p_ops; + + +struct fsm_session g_sessions[2] = +{ + { + .type = FSM_PARSER, + .conf = &g_confs[0], + }, + { + .type = FSM_PARSER, + .conf = &g_confs[1], + } +}; + +/** + * @brief sends a json mqtt report + * + * Sends and frees a json report over mqtt. + * when running UTs on the pod, actually send the report + * as QM is expected to be running. + * When running UTs on X86 platforms, simply free the report. + * @params session the fsm session owning the mqtt topic. + * @params the json report. + */ +static void +send_report(struct fsm_session *session, char *report) +{ +#ifndef ARCH_X86 + qm_response_t res; + bool ret = false; +#endif + + LOGD("%s: msg len: %zu, msg: %s\n, topic: %s", + __func__, report ? strlen(report) : 0, + report ? report : "None", session->topic); + if (report == NULL) return; + +#ifndef ARCH_X86 + ret = qm_conn_send_direct(QM_REQ_COMPRESS_DISABLE, session->topic, + report, strlen(report), &res); + if (!ret) LOGE("error sending mqtt with topic %s", session->topic); +#endif + json_free(report); + + return; +} + + +struct fsm_session_ops g_ops = +{ + .send_report = send_report, +}; + + +struct arp_cache *g_mgr; + +/** + * @brief Converts a bytes array in a hex dump file wireshark can import. + * + * Dumps the array in a file that can then be imported by wireshark. + * The file can also be translated to a pcap file using the text2pcap command. + * Useful to visualize the packet content. + * @param fname the file recipient of the hex dump + * @param buf the buffer to dump + * @param length the length of the buffer to dump + */ +void +create_hex_dump(const char *fname, const uint8_t *buf, size_t len) +{ + int line_number = 0; + bool new_line = true; + size_t i; + FILE *f; + + f = fopen(fname, "w+"); + + if (f == NULL) return; + + for (i = 0; i < len; i++) + { + new_line = (i == 0 ? true : ((i % 8) == 0)); + if (new_line) + { + if (line_number) fprintf(f, "\n"); + fprintf(f, "%06x", line_number); + line_number += 8; + } + fprintf(f, " %02x", buf[i]); + } + fprintf(f, "\n"); + fclose(f); + + return; +} + + +char *g_location_id = "foo"; +char *g_node_id = "bar"; + +/** + * @brief Convenient wrapper + * + * Dumps the packet content in /tmp/_.txtpcap + * for wireshark consumption and sets the given parser's data fields. + * @param pkt the C structure containing an exported packet capture + * @param parser theparser structure to set + */ +#define PREPARE_UT(pkt, parser) \ + { \ + char fname[128]; \ + size_t len = sizeof(pkt); \ + \ + snprintf(fname, sizeof(fname), "/tmp/%s_%s.txtpcap", \ + test_name, #pkt); \ + create_hex_dump(fname, pkt, len); \ + parser->packet_len = len; \ + parser->data = (uint8_t *)pkt; \ + } + + +void +global_test_init(void) +{ + size_t n_sessions, i; + + g_mgr = NULL; + n_sessions = sizeof(g_sessions) / sizeof(struct fsm_session); + + /* Reset sessions, register them to the plugin */ + for (i = 0; i < n_sessions; i++) + { + struct fsm_session *session = &g_sessions[i]; + struct str_pair *pair; + + session->conf = &g_confs[i]; + session->ops = g_ops; + session->p_ops = &p_ops; + session->name = g_confs[i].handler; + session->conf->other_config = schema2tree(OTHER_CONFIG_NELEM_SIZE, + OTHER_CONFIG_NELEM_SIZE, + OTHER_CONFIG_NELEMS, + g_other_configs[i][0], + g_other_configs[i][1]); + pair = ds_tree_find(session->conf->other_config, "mqtt_v"); + session->topic = pair->value; + session->location_id = g_location_id; + session->node_id = g_location_id; + } +} + +void +global_test_exit(void) +{ + size_t n_sessions, i; + + g_mgr = NULL; + n_sessions = sizeof(g_sessions) / sizeof(struct fsm_session); + + /* Reset sessions, register them to the plugin */ + for (i = 0; i < n_sessions; i++) + { + struct fsm_session *session = &g_sessions[i]; + + free_str_tree(session->conf->other_config); + } +} + +/** + * @brief called by the Unity framework before every single test + */ +void +setUp(void) +{ +#ifdef ARCH_X86 + struct neigh_table_mgr *neigh_mgr; +#endif + size_t n_sessions, i; + + g_mgr = NULL; + n_sessions = sizeof(g_sessions) / sizeof(struct fsm_session); + + /* Reset sessions, register them to the plugin */ + for (i = 0; i < n_sessions; i++) + { + struct fsm_session *session = &g_sessions[i]; + + arp_plugin_init(session); + } + g_mgr = arp_get_mgr(); + + neigh_table_init(); + +#ifdef ARCH_X86 + neigh_mgr = neigh_table_get_mgr(); + neigh_mgr->update_ovsdb_tables = NULL; +#endif + + return; +} + +/** + * @brief called by the Unity framework after every single test + */ +void +tearDown(void) +{ + size_t n_sessions, i; + + n_sessions = sizeof(g_sessions) / sizeof(struct fsm_session); + + /* Reset sessions, unregister them */ + for (i = 0; i < n_sessions; i++) + { + struct fsm_session *session = &g_sessions[i]; + + arp_plugin_exit(session); + } + g_mgr = NULL; + neigh_table_cleanup(); + + return; +} + + +/** + * @brief log ip mac mapping + */ +void +log_ip_mac_mapping(struct arp_parser *parser) +{ + char ipstr[INET6_ADDRSTRLEN]; + os_macaddr_t null_mac = { 0 }; + os_macaddr_t *mac; + + mac = parser->sender.mac; + if (mac == NULL) + { + LOGI("%s: sender: no IP mac mapping available", __func__); + mac = &null_mac; + } + + memset(ipstr, 0, sizeof(ipstr)); + getnameinfo((struct sockaddr *)(parser->sender.ipaddr), + sizeof(struct sockaddr_storage), ipstr, sizeof(ipstr), + 0, 0, NI_NUMERICHOST); + + LOGI("%s: sender ip: %s, sender mac: "PRI_os_macaddr_lower_t, + __func__, ipstr, FMT_os_macaddr_pt(mac)); + + mac = parser->target.mac; + if (mac == NULL) + { + LOGI("%s: target: no IP mac mapping available", __func__); + mac = &null_mac; + } + + memset(ipstr, 0, sizeof(ipstr)); + getnameinfo((struct sockaddr *)(parser->target.ipaddr), + sizeof(struct sockaddr_storage), ipstr, sizeof(ipstr), + 0, 0, NI_NUMERICHOST); + + LOGI("%s: target ip: %s, target mac: "PRI_os_macaddr_lower_t, + __func__, ipstr, FMT_os_macaddr_pt(mac)); + +} + + +/** + * @brief validate that no session provided is handled correctly + */ +void +test_no_session(void) +{ + int ret; + + ret = arp_plugin_init(NULL); + TEST_ASSERT_TRUE(ret == -1); +} + + +/** + * @brief test plugin init()/exit() sequence + * + * Validate plugin reference counts and pointers + */ +void test_load_unload_plugin(void) +{ + /* SetUp() has called init(). Validate settings */ + TEST_ASSERT_NOT_NULL(g_mgr); + + /* + * tearDown() will call exit(). + * ASAN enabled run of the test will validate that + * there is no memory leak. + */ +} + + +/** + * @brief test arp request parsing + * + */ +void test_arp_req(void) +{ + struct net_header_parser *net_parser; + struct arp_session *a_session; + struct fsm_session *session; + struct arp_parser *parser; + size_t len; + bool ret; + + /* Select the first active session */ + session = &g_sessions[0]; + a_session = arp_lookup_session(session); + TEST_ASSERT_NOT_NULL(a_session); + + parser = &a_session->parser; + net_parser = calloc(1, sizeof(*net_parser)); + TEST_ASSERT_NOT_NULL(net_parser); + parser->net_parser = net_parser; + PREPARE_UT(pkt134, net_parser); + len = net_header_parse(net_parser); + TEST_ASSERT_TRUE(len != 0); + + len = arp_parse_message(parser); + TEST_ASSERT_TRUE(len != 0); + + ret = arp_parse_is_gratuitous(&parser->arp); + TEST_ASSERT_FALSE(ret); + + arp_process_message(a_session); + log_ip_mac_mapping(parser); + + free(net_parser); +} + + +/** + * @brief test arp request parsing + * + */ +void test_arp_reply(void) +{ + struct net_header_parser *net_parser; + struct arp_session *a_session; + struct fsm_session *session; + struct arp_parser *parser; + size_t len; + bool ret; + + /* Select the first active session */ + session = &g_sessions[0]; + a_session = arp_lookup_session(session); + TEST_ASSERT_NOT_NULL(a_session); + + parser = &a_session->parser; + net_parser = calloc(1, sizeof(*net_parser)); + TEST_ASSERT_NOT_NULL(net_parser); + parser->net_parser = net_parser; + PREPARE_UT(pkt135, net_parser); + len = net_header_parse(net_parser); + TEST_ASSERT_TRUE(len != 0); + + len = arp_parse_message(parser); + TEST_ASSERT_TRUE(len != 0); + + ret = arp_parse_is_gratuitous(&parser->arp); + TEST_ASSERT_FALSE(ret); + + arp_process_message(a_session); + log_ip_mac_mapping(parser); + + free(net_parser); +} + + +/** + * @brief test arp request parsing + * + */ +void test_gratuitous_arp_reply(void) +{ + struct net_header_parser *net_parser; + struct arp_session *a_session; + struct fsm_session *session; + struct arp_parser *parser; + size_t len; + bool ret; + + /* Select the first active session */ + session = &g_sessions[0]; + a_session = arp_lookup_session(session); + TEST_ASSERT_NOT_NULL(a_session); + + parser = &a_session->parser; + net_parser = calloc(1, sizeof(*net_parser)); + TEST_ASSERT_NOT_NULL(net_parser); + parser->net_parser = net_parser; + PREPARE_UT(pkt42, net_parser); + len = net_header_parse(net_parser); + TEST_ASSERT_TRUE(len != 0); + + len = arp_parse_message(parser); + TEST_ASSERT_TRUE(len != 0); + + ret = arp_parse_is_gratuitous(&parser->arp); + TEST_ASSERT_TRUE(ret); + + arp_process_message(a_session); + log_ip_mac_mapping(parser); + + free(net_parser); +} + +int +main(int argc, char *argv[]) +{ + /* Set the logs to stdout */ + target_log_open("TEST", LOG_OPEN_STDOUT); + log_severity_set(LOG_SEVERITY_TRACE); + + UnityBegin(test_name); + + global_test_init(); + + RUN_TEST(test_no_session); + RUN_TEST(test_load_unload_plugin); + RUN_TEST(test_arp_req); + RUN_TEST(test_arp_reply); + RUN_TEST(test_gratuitous_arp_reply); + + global_test_exit(); + + return UNITY_END(); +} diff --git a/src/lib/arp_parse/tests/ut/unit.mk b/src/lib/arp_parse/tests/ut/unit.mk new file mode 100644 index 00000000..a9aa5b17 --- /dev/null +++ b/src/lib/arp_parse/tests/ut/unit.mk @@ -0,0 +1,41 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_FSM),n,y) + +UNIT_NAME := test_arp_plugin + +UNIT_TYPE := TEST_BIN + +UNIT_SRC := test_arp_plugin.c + +UNIT_DEPS := src/lib/arp_parse +UNIT_DEPS += src/lib/log +UNIT_DEPS += src/lib/common +UNIT_DEPS += src/lib/json_util +UNIT_DEPS += src/lib/ustack +UNIT_DEPS += src/qm/qm_conn +UNIT_DEPS += src/lib/unity +UNIT_DEPS += src/lib/neigh_table +UNIT_DEPS += src/lib/nf_utils diff --git a/src/lib/arp_parse/unit.mk b/src/lib/arp_parse/unit.mk new file mode 100644 index 00000000..d4b5132b --- /dev/null +++ b/src/lib/arp_parse/unit.mk @@ -0,0 +1,56 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################### +# +# fsm neighbour address resolution protocol plugin library +# +############################################################################### +UNIT_NAME := fsm_arp + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_FSM),n,y) + +# If compiled with clang, assume a native unit test target +# and build a static library +ifneq (,$(findstring clang,$(CC))) + UNIT_TYPE := LIB +else + UNIT_TYPE := SHLIB + UNIT_DIR := lib +endif + +UNIT_SRC := src/arp_parse.c + +UNIT_CFLAGS := -I$(UNIT_PATH)/inc +UNIT_CFLAGS += -Isrc/fsm/inc +UNIT_CFLAGS += -Isrc/lib/fsm_policy/inc + +UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS) +UNIT_EXPORT_LDFLAGS := -ljansson + +UNIT_DEPS := src/lib/const +UNIT_DEPS += src/lib/log +UNIT_DEPS += src/lib/neigh_table +UNIT_DEPS += src/lib/ovsdb +UNIT_DEPS += src/lib/ustack diff --git a/src/lib/ct_stats/futs/create_ct_stats_plugin.sh b/src/lib/ct_stats/futs/create_ct_stats_plugin.sh new file mode 100755 index 00000000..13d194c6 --- /dev/null +++ b/src/lib/ct_stats/futs/create_ct_stats_plugin.sh @@ -0,0 +1,361 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +prog=$0 +this_dir=$(dirname "$0") + +set -x + +OVSH='/usr/opensync/tools/ovsh' + +# get filter index to start from. +get_filter_idx() { + bump=$1 + idx=$(${OVSH} s FCM_Filter index -r | wc -l) + # bump up the index by one if required + idx=$((idx+bump)) + echo ${idx} +} + + +# install collector +install_dev_collector() { + cat < #include @@ -72,6 +75,16 @@ static struct imc_context g_imc_server = }; +/** + * IMC server used for fsm -> fcm app list communication + */ +static struct imc_context g_imc_app_server = +{ + .initialized = false, + .endpoint = "ipc:///tmp/imc_fsm2fcm_app", +}; + + /** * IMC shared library context, when loaded through dlopen() */ @@ -161,6 +174,7 @@ static flow_stats_mgr_t g_ct_stats = .initialized = false, }; +static char *g_appname; /** * @brief compare sessions @@ -1266,6 +1280,57 @@ ct_flow_add_sample(flow_stats_t *ct_stats) free_ct_flow_list(ct_stats); } + +void +ct_stats_block_flow(struct net_md_stats_accumulator *acc) +{ + struct net_md_flow_key *key; + struct flow_key *fkey; + int af; + + fkey = acc->fkey; + key = acc->key; + if (key == NULL) return; + + af = 0; + if (key->ip_version == 4) af = AF_INET; + if (key->ip_version == 6) af = AF_INET6; + if (af == 0) return; + + LOGI("%s: blocking flow src: %s, dst: %s, proto: %d, sport: %d, dport: %d", + __func__, + fkey->src_ip, fkey->dst_ip, fkey->protocol, fkey->sport, fkey->dport); + + fsm_set_ip_dpi_state(NULL, key->src_ip, key->dst_ip, + key->sport, key->dport, + key->ipprotocol, af, FSM_DPI_DROP); + fsm_set_ip_dpi_state(NULL, key->dst_ip, key->src_ip, + key->dport, key->sport, + key->ipprotocol, af, FSM_DPI_DROP); +} + + +bool +ct_stats_process_acc(struct net_md_stats_accumulator *acc) +{ + struct flow_tags *ftag; + struct flow_key *fkey; + size_t i; + int rc; + + if (acc->fkey == NULL) return true; + fkey = acc->fkey; + + for (i = 0; i < fkey->num_tags; i++) + { + ftag = fkey->tags[i]; + rc = strcmp(ftag->app_name, g_appname); + if (rc == 0) ct_stats_block_flow(acc); + } + return true; +} + + /** * @brief collector filter callback processing flows pushed from fsm * @@ -1353,6 +1418,7 @@ alloc_aggr(flow_stats_t *ct_stats) LOGD("%s: Aggregator allocation failed", __func__); return -1; } + aggr->process = ct_stats_process_acc; ct_stats->aggr = aggr; collector->plugin_ctx = ct_stats; @@ -1568,13 +1634,13 @@ ct_stats_plugin_close_cb(fcm_collect_plugin_t *collector) /** - * @brief imc callobak processing the protobuf receivd from fsm + * @brief imc callback processing the protobuf received from fsm * * @param data a pointer to the protobuf * @param len the protobuf length */ static void -test_recv_cb(void *data, size_t len) +proto_recv_cb(void *data, size_t len) { struct net_md_aggregator *aggr; struct packed_buffer recv_pb; @@ -1594,6 +1660,38 @@ test_recv_cb(void *data, size_t len) } + +/** + * @brief imc callback processing the app name received from fsm + * + * @param data a pointer to the string + * @param len the protobuf length + */ +static void +app_recv_cb(void *data, size_t len) +{ + flow_stats_t *ct_stats; + char *str; + + ct_stats = ct_stats_get_active_instance(); + if (ct_stats == NULL) + { + LOGD("%s: No active instance", __func__); + return; + } + + str = calloc(1, len + 1); + if (str == NULL) return; + + strscpy(str, (char *)data, len + 1); + LOGI("%s: received app name %s", __func__, str); + g_appname = str; + net_md_process_aggr(ct_stats->aggr); + g_appname = NULL; + free(str); +} + + /** * @brief starts the imc server receivng flow info from fsm */ @@ -1613,7 +1711,17 @@ ct_stats_imc_init(void) /* Start the server */ server->ztype = IMC_PULL; loop = g_ct_stats.loop; - rc = ct_stats_init_server(server, loop, test_recv_cb); + rc = ct_stats_init_server(server, loop, proto_recv_cb); + if (rc != 0) goto err_init_imc; + + server->initialized = true; + + server = &g_imc_app_server; + + /* Start the server */ + server->ztype = IMC_PULL; + loop = g_ct_stats.loop; + rc = ct_stats_init_server(server, loop, app_recv_cb); if (rc != 0) goto err_init_imc; server->initialized = true; diff --git a/src/lib/ct_stats/unit.mk b/src/lib/ct_stats/unit.mk index 0bbba59f..55fe7843 100644 --- a/src/lib/ct_stats/unit.mk +++ b/src/lib/ct_stats/unit.mk @@ -65,4 +65,5 @@ UNIT_DEPS += src/lib/log UNIT_DEPS += src/lib/fcm_filter UNIT_DEPS += src/lib/ustack UNIT_DEPS += src/lib/nf_utils +UNIT_DEPS += src/lib/fsm_utils UNIT_DEPS += src/lib/neigh_table diff --git a/src/lib/datapipeline/inc/dpp_client.h b/src/lib/datapipeline/inc/dpp_client.h index 45b56079..78327927 100644 --- a/src/lib/datapipeline/inc/dpp_client.h +++ b/src/lib/datapipeline/inc/dpp_client.h @@ -186,6 +186,8 @@ typedef struct double rate_rx; double rate_tx; int32_t rssi; + double rate_rx_perceived; + double rate_tx_perceived; } dpp_client_stats_t; typedef void (*dpp_client_report_cb_t)( diff --git a/src/lib/datapipeline/inc/dpp_survey.h b/src/lib/datapipeline/inc/dpp_survey.h index c59607f2..8598fac5 100644 --- a/src/lib/datapipeline/inc/dpp_survey.h +++ b/src/lib/datapipeline/inc/dpp_survey.h @@ -52,6 +52,7 @@ typedef struct dpp_avg_t chan_self; dpp_avg_t chan_rx; dpp_avg_t chan_tx; + dpp_avg_signed_t chan_noise; /* dBm */ ds_dlist_node_t node; } dpp_survey_record_avg_t; @@ -67,6 +68,7 @@ typedef struct uint32_t chan_self; uint32_t chan_rx; uint32_t chan_tx; + int32_t chan_noise; /* dBm */ uint32_t duration_ms; /* Linked list survey data */ diff --git a/src/lib/datapipeline/inc/dpp_types.h b/src/lib/datapipeline/inc/dpp_types.h index d1ccef32..bef0af77 100644 --- a/src/lib/datapipeline/inc/dpp_types.h +++ b/src/lib/datapipeline/inc/dpp_types.h @@ -70,6 +70,14 @@ typedef struct uint32_t num; } dpp_avg_t; +typedef struct +{ + int32_t avg; + int32_t min; + int32_t max; + uint32_t num; +} dpp_avg_signed_t; + typedef enum { RADIO_802_11_AUTO = 0, diff --git a/src/lib/datapipeline/inc/opensync_stats.pb-c.h b/src/lib/datapipeline/inc/opensync_stats.pb-c.h index 30d96d3f..132fc6c9 100644 --- a/src/lib/datapipeline/inc/opensync_stats.pb-c.h +++ b/src/lib/datapipeline/inc/opensync_stats.pb-c.h @@ -42,6 +42,7 @@ PROTOBUF_C__BEGIN_DECLS typedef struct _Sts__AvgType Sts__AvgType; +typedef struct _Sts__AvgTypeSigned Sts__AvgTypeSigned; typedef struct _Sts__Neighbor Sts__Neighbor; typedef struct _Sts__Neighbor__NeighborBss Sts__Neighbor__NeighborBss; typedef struct _Sts__Client Sts__Client; @@ -198,6 +199,22 @@ struct _Sts__AvgType , 0, 0,0, 0,0, 0,0 } +struct _Sts__AvgTypeSigned +{ + ProtobufCMessage base; + int32_t avg; + protobuf_c_boolean has_min; + int32_t min; + protobuf_c_boolean has_max; + int32_t max; + protobuf_c_boolean has_num; + uint32_t num; +}; +#define STS__AVG_TYPE_SIGNED__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&sts__avg_type_signed__descriptor) \ + , 0, 0,0, 0,0, 0,0 } + + struct _Sts__Neighbor__NeighborBss { ProtobufCMessage base; @@ -263,16 +280,32 @@ struct _Sts__Client__Stats uint64_t rx_errors; protobuf_c_boolean has_tx_errors; uint64_t tx_errors; + /* + * best-effort report of SU capacity, mbps + */ protobuf_c_boolean has_rx_rate; double rx_rate; + /* + * best-effort report of SU capacity, mbps + */ protobuf_c_boolean has_tx_rate; double tx_rate; protobuf_c_boolean has_rssi; uint32_t rssi; + /* + * accounts mixed SU+MU, mbps + */ + protobuf_c_boolean has_rx_rate_perceived; + double rx_rate_perceived; + /* + * accounts mixed SU+MU, mbps + */ + protobuf_c_boolean has_tx_rate_perceived; + double tx_rate_perceived; }; #define STS__CLIENT__STATS__INIT \ { PROTOBUF_C_MESSAGE_INIT (&sts__client__stats__descriptor) \ - , 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 } + , 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 } struct _Sts__Client__RxStats__ChainRSSI @@ -479,10 +512,15 @@ struct _Sts__Survey__SurveySample */ protobuf_c_boolean has_busy_ext; uint32_t busy_ext; + /* + * dBm + */ + protobuf_c_boolean has_noise_floor; + int32_t noise_floor; }; #define STS__SURVEY__SURVEY_SAMPLE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&sts__survey__survey_sample__descriptor) \ - , 0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 } + , 0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 } struct _Sts__Survey__SurveyAvg @@ -509,10 +547,14 @@ struct _Sts__Survey__SurveyAvg * 40MHz extention channel busy */ Sts__AvgType *busy_ext; + /* + * dBm + */ + Sts__AvgTypeSigned *noise_floor; }; #define STS__SURVEY__SURVEY_AVG__INIT \ { PROTOBUF_C_MESSAGE_INIT (&sts__survey__survey_avg__descriptor) \ - , 0, NULL, NULL, NULL, NULL, NULL } + , 0, NULL, NULL, NULL, NULL, NULL, NULL } /* @@ -1003,6 +1045,25 @@ Sts__AvgType * void sts__avg_type__free_unpacked (Sts__AvgType *message, ProtobufCAllocator *allocator); +/* Sts__AvgTypeSigned methods */ +void sts__avg_type_signed__init + (Sts__AvgTypeSigned *message); +size_t sts__avg_type_signed__get_packed_size + (const Sts__AvgTypeSigned *message); +size_t sts__avg_type_signed__pack + (const Sts__AvgTypeSigned *message, + uint8_t *out); +size_t sts__avg_type_signed__pack_to_buffer + (const Sts__AvgTypeSigned *message, + ProtobufCBuffer *buffer); +Sts__AvgTypeSigned * + sts__avg_type_signed__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void sts__avg_type_signed__free_unpacked + (Sts__AvgTypeSigned *message, + ProtobufCAllocator *allocator); /* Sts__Neighbor__NeighborBss methods */ void sts__neighbor__neighbor_bss__init (Sts__Neighbor__NeighborBss *message); @@ -1280,6 +1341,9 @@ void sts__report__free_unpacked typedef void (*Sts__AvgType_Closure) (const Sts__AvgType *message, void *closure_data); +typedef void (*Sts__AvgTypeSigned_Closure) + (const Sts__AvgTypeSigned *message, + void *closure_data); typedef void (*Sts__Neighbor__NeighborBss_Closure) (const Sts__Neighbor__NeighborBss *message, void *closure_data); @@ -1394,6 +1458,7 @@ extern const ProtobufCEnumDescriptor sts__report_type__descriptor; extern const ProtobufCEnumDescriptor sts__fs_type__descriptor; extern const ProtobufCEnumDescriptor sts__diff_type__descriptor; extern const ProtobufCMessageDescriptor sts__avg_type__descriptor; +extern const ProtobufCMessageDescriptor sts__avg_type_signed__descriptor; extern const ProtobufCMessageDescriptor sts__neighbor__descriptor; extern const ProtobufCMessageDescriptor sts__neighbor__neighbor_bss__descriptor; extern const ProtobufCMessageDescriptor sts__client__descriptor; diff --git a/src/lib/datapipeline/src/dppline.c b/src/lib/datapipeline/src/dppline.c index ad135409..31f33733 100644 --- a/src/lib/datapipeline/src/dppline.c +++ b/src/lib/datapipeline/src/dppline.c @@ -31,10 +31,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "target.h" +#include "osp_unit.h" #include "dppline.h" #include "ds.h" #include "ds_dlist.h" -#include "log.h" #include "opensync_stats.pb-c.h" #include "dpp_client.h" @@ -680,7 +680,7 @@ static char * getNodeid() return NULL; } - if (!target_id_get(buff, TARGET_ID_SZ)) + if (!osp_unit_id_get(buff, TARGET_ID_SZ)) { LOG(ERR, "Error acquiring node id."); free(buff); @@ -796,7 +796,8 @@ static void dppline_add_stat_survey(Sts__Report *r, dppline_stats_t *s) dr->channel = rec->info.chan; - Sts__AvgType *davg; + Sts__AvgType *davg; + Sts__AvgTypeSigned *davgs; #define CP_AVG(_name, _name1) do { \ if (rec->_name1.avg) { \ davg = dr->_name = malloc(sizeof(*dr->_name)); \ @@ -817,13 +818,35 @@ static void dppline_add_stat_survey(Sts__Report *r, dppline_stats_t *s) } \ } while (0) +#define CP_AVG_SIGNED(_name, _name1) do { \ + if (rec->_name1.avg) { \ + davgs = dr->_name = malloc(sizeof(*dr->_name)); \ + sts__avg_type_signed__init(davgs); \ + davgs->avg = rec->_name1.avg; \ + if(rec->_name1.min) { \ + davgs->min = rec->_name1.min; \ + davgs->has_min = true;; \ + } \ + if(rec->_name1.max) { \ + davgs->max = rec->_name1.max; \ + davgs->has_max = true;; \ + } \ + if(rec->_name1.num) { \ + davgs->num = rec->_name1.num; \ + davgs->has_num = true;; \ + } \ + } \ + } while (0) + CP_AVG(busy, chan_busy); CP_AVG(busy_tx, chan_tx); CP_AVG(busy_self, chan_self); CP_AVG(busy_rx, chan_rx); CP_AVG(busy_ext, chan_busy_ext); + CP_AVG_SIGNED(noise_floor,chan_noise); #undef CP_AVG +#undef CP_AVG_SIGNED } /* LOG(DEBUG, "============= %s size raw: %d proto struct: %d", __FUNCTION__, sizeof(s->u.survey) + s->u.survey.numrec * sizeof(dpp_survey_record_avg_t), @@ -859,6 +882,7 @@ static void dppline_add_stat_survey(Sts__Report *r, dppline_stats_t *s) CP_OPT(busy_self, chan_self); CP_OPT(busy_rx, chan_rx); CP_OPT(busy_ext, chan_busy_ext); + CP_OPT(noise_floor,chan_noise); #undef CP_OPT @@ -1135,6 +1159,14 @@ static void dppline_add_stat_client(Sts__Report *r, dppline_stats_t *s) dr->stats->rssi = rec->stats.rssi; dr->stats->has_rssi = true; } + if (rec->stats.rate_rx_perceived) { + dr->stats->rx_rate_perceived = rec->stats.rate_rx_perceived; + dr->stats->has_rx_rate_perceived = true; + } + if (rec->stats.rate_tx_perceived) { + dr->stats->tx_rate_perceived = rec->stats.rate_tx_perceived; + dr->stats->has_tx_rate_perceived = true; + } dr->rx_stats = malloc(client->list[i].rx_qty * sizeof(*dr->rx_stats)); size += client->list[i].rx_qty * sizeof(*dr->rx_stats); diff --git a/src/lib/datapipeline/src/opensync_stats.pb-c.c b/src/lib/datapipeline/src/opensync_stats.pb-c.c index 615d2448..5287b9b2 100644 --- a/src/lib/datapipeline/src/opensync_stats.pb-c.c +++ b/src/lib/datapipeline/src/opensync_stats.pb-c.c @@ -76,6 +76,49 @@ void sts__avg_type__free_unpacked assert(message->base.descriptor == &sts__avg_type__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } +void sts__avg_type_signed__init + (Sts__AvgTypeSigned *message) +{ + static Sts__AvgTypeSigned init_value = STS__AVG_TYPE_SIGNED__INIT; + *message = init_value; +} +size_t sts__avg_type_signed__get_packed_size + (const Sts__AvgTypeSigned *message) +{ + assert(message->base.descriptor == &sts__avg_type_signed__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t sts__avg_type_signed__pack + (const Sts__AvgTypeSigned *message, + uint8_t *out) +{ + assert(message->base.descriptor == &sts__avg_type_signed__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t sts__avg_type_signed__pack_to_buffer + (const Sts__AvgTypeSigned *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &sts__avg_type_signed__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Sts__AvgTypeSigned * + sts__avg_type_signed__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Sts__AvgTypeSigned *) + protobuf_c_message_unpack (&sts__avg_type_signed__descriptor, + allocator, len, data); +} +void sts__avg_type_signed__free_unpacked + (Sts__AvgTypeSigned *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &sts__avg_type_signed__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} void sts__neighbor__neighbor_bss__init (Sts__Neighbor__NeighborBss *message) { @@ -752,6 +795,83 @@ const ProtobufCMessageDescriptor sts__avg_type__descriptor = (ProtobufCMessageInit) sts__avg_type__init, NULL,NULL,NULL /* reserved[123] */ }; +static const ProtobufCFieldDescriptor sts__avg_type_signed__field_descriptors[4] = +{ + { + "avg", + 1, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(Sts__AvgTypeSigned, avg), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "min", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT32, + offsetof(Sts__AvgTypeSigned, has_min), + offsetof(Sts__AvgTypeSigned, min), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "max", + 3, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT32, + offsetof(Sts__AvgTypeSigned, has_max), + offsetof(Sts__AvgTypeSigned, max), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "num", + 4, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT32, + offsetof(Sts__AvgTypeSigned, has_num), + offsetof(Sts__AvgTypeSigned, num), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned sts__avg_type_signed__field_indices_by_name[] = { + 0, /* field[0] = avg */ + 2, /* field[2] = max */ + 1, /* field[1] = min */ + 3, /* field[3] = num */ +}; +static const ProtobufCIntRange sts__avg_type_signed__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor sts__avg_type_signed__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "sts.AvgTypeSigned", + "AvgTypeSigned", + "Sts__AvgTypeSigned", + "sts", + sizeof(Sts__AvgTypeSigned), + 4, + sts__avg_type_signed__field_descriptors, + sts__avg_type_signed__field_indices_by_name, + 1, sts__avg_type_signed__number_ranges, + (ProtobufCMessageInit) sts__avg_type_signed__init, + NULL,NULL,NULL /* reserved[123] */ +}; static const ProtobufCFieldDescriptor sts__neighbor__neighbor_bss__field_descriptors[7] = { { @@ -958,7 +1078,7 @@ const ProtobufCMessageDescriptor sts__neighbor__descriptor = (ProtobufCMessageInit) sts__neighbor__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor sts__client__stats__field_descriptors[11] = +static const ProtobufCFieldDescriptor sts__client__stats__field_descriptors[13] = { { "rx_bytes", @@ -1092,6 +1212,30 @@ static const ProtobufCFieldDescriptor sts__client__stats__field_descriptors[11] 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "rx_rate_perceived", + 12, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_DOUBLE, + offsetof(Sts__Client__Stats, has_rx_rate_perceived), + offsetof(Sts__Client__Stats, rx_rate_perceived), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "tx_rate_perceived", + 13, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_DOUBLE, + offsetof(Sts__Client__Stats, has_tx_rate_perceived), + offsetof(Sts__Client__Stats, tx_rate_perceived), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned sts__client__stats__field_indices_by_name[] = { 10, /* field[10] = rssi */ @@ -1099,17 +1243,19 @@ static const unsigned sts__client__stats__field_indices_by_name[] = { 6, /* field[6] = rx_errors */ 2, /* field[2] = rx_frames */ 8, /* field[8] = rx_rate */ + 11, /* field[11] = rx_rate_perceived */ 4, /* field[4] = rx_retries */ 1, /* field[1] = tx_bytes */ 7, /* field[7] = tx_errors */ 3, /* field[3] = tx_frames */ 9, /* field[9] = tx_rate */ + 12, /* field[12] = tx_rate_perceived */ 5, /* field[5] = tx_retries */ }; static const ProtobufCIntRange sts__client__stats__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 11 } + { 0, 13 } }; const ProtobufCMessageDescriptor sts__client__stats__descriptor = { @@ -1119,7 +1265,7 @@ const ProtobufCMessageDescriptor sts__client__stats__descriptor = "Sts__Client__Stats", "sts", sizeof(Sts__Client__Stats), - 11, + 13, sts__client__stats__field_descriptors, sts__client__stats__field_indices_by_name, 1, sts__client__stats__number_ranges, @@ -1912,7 +2058,7 @@ const ProtobufCMessageDescriptor sts__client_report__descriptor = (ProtobufCMessageInit) sts__client_report__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor sts__survey__survey_sample__field_descriptors[10] = +static const ProtobufCFieldDescriptor sts__survey__survey_sample__field_descriptors[11] = { { "channel", @@ -2034,6 +2180,18 @@ static const ProtobufCFieldDescriptor sts__survey__survey_sample__field_descript 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "noise_floor", + 11, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT32, + offsetof(Sts__Survey__SurveySample, has_noise_floor), + offsetof(Sts__Survey__SurveySample, noise_floor), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned sts__survey__survey_sample__field_indices_by_name[] = { 4, /* field[4] = busy */ @@ -2043,6 +2201,7 @@ static const unsigned sts__survey__survey_sample__field_indices_by_name[] = { 5, /* field[5] = busy_tx */ 0, /* field[0] = channel */ 1, /* field[1] = duration_ms */ + 10, /* field[10] = noise_floor */ 8, /* field[8] = offset_ms */ 3, /* field[3] = sample_count */ 2, /* field[2] = total_count */ @@ -2050,7 +2209,7 @@ static const unsigned sts__survey__survey_sample__field_indices_by_name[] = { static const ProtobufCIntRange sts__survey__survey_sample__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 10 } + { 0, 11 } }; const ProtobufCMessageDescriptor sts__survey__survey_sample__descriptor = { @@ -2060,14 +2219,14 @@ const ProtobufCMessageDescriptor sts__survey__survey_sample__descriptor = "Sts__Survey__SurveySample", "sts", sizeof(Sts__Survey__SurveySample), - 10, + 11, sts__survey__survey_sample__field_descriptors, sts__survey__survey_sample__field_indices_by_name, 1, sts__survey__survey_sample__number_ranges, (ProtobufCMessageInit) sts__survey__survey_sample__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor sts__survey__survey_avg__field_descriptors[6] = +static const ProtobufCFieldDescriptor sts__survey__survey_avg__field_descriptors[7] = { { "channel", @@ -2141,6 +2300,18 @@ static const ProtobufCFieldDescriptor sts__survey__survey_avg__field_descriptors 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "noise_floor", + 7, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(Sts__Survey__SurveyAvg, noise_floor), + &sts__avg_type_signed__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned sts__survey__survey_avg__field_indices_by_name[] = { 1, /* field[1] = busy */ @@ -2149,11 +2320,12 @@ static const unsigned sts__survey__survey_avg__field_indices_by_name[] = { 4, /* field[4] = busy_self */ 2, /* field[2] = busy_tx */ 0, /* field[0] = channel */ + 6, /* field[6] = noise_floor */ }; static const ProtobufCIntRange sts__survey__survey_avg__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 6 } + { 0, 7 } }; const ProtobufCMessageDescriptor sts__survey__survey_avg__descriptor = { @@ -2163,7 +2335,7 @@ const ProtobufCMessageDescriptor sts__survey__survey_avg__descriptor = "Sts__Survey__SurveyAvg", "sts", sizeof(Sts__Survey__SurveyAvg), - 6, + 7, sts__survey__survey_avg__field_descriptors, sts__survey__survey_avg__field_indices_by_name, 1, sts__survey__survey_avg__number_ranges, diff --git a/src/lib/dns_parse/inc/dns_parse.h b/src/lib/dns_parse/inc/dns_parse.h index 33cc3549..0f7a8021 100644 --- a/src/lib/dns_parse/inc/dns_parse.h +++ b/src/lib/dns_parse/inc/dns_parse.h @@ -21,7 +21,8 @@ struct web_cat_offline uint32_t connection_failures; }; - +#define MAX_TAG_VALUES_LEN 64 +#define MAX_TAG_NAME_LEN 64 #define MAX_EXCLUDES 100 struct dns_session { @@ -61,10 +62,6 @@ struct dns_session int32_t remote_lookup_retries; ds_tree_node_t session_node; ds_tree_t session_devices; - struct fsm_policy_client policy_client; - char *provider; - struct fsm_session *provider_plugin; - struct fsm_web_cat_ops *provider_ops; long health_stats_report_interval; char *health_stats_report_topic; struct fsm_url_stats health_stats; @@ -127,6 +124,7 @@ struct dns_cache int req_cache_ttl; int (*set_forward_context)(struct fsm_session *); void (*forward)(struct dns_session *, dns_info *, uint8_t *, int); + void (*update_tag)(struct fqdn_pending_req *); void (*policy_init)(void); void (*policy_check)(struct dns_device *, struct fqdn_pending_req *); }; @@ -171,17 +169,18 @@ dns_remove_req(struct dns_session *dns_session, os_macaddr_t *mac, /** - * @brief create updated row for Openflow_Tag with newly matched IPs + * @brief create updated row for OF Tag with newly matched IPs * - * @param req request with update fields loaded - * @param[out] output row to be written to Openflow_Tag + * @param req request with update fields loaded + * @parami[out] values buffer to update values. + * @param[out] values_len length of the values updated. * * @return true loaded correctly built struct into output * @return false output struct not built */ bool -dns_generate_update_tag( struct fqdn_pending_req *req, - struct schema_Openflow_Tag *output); +dns_generate_update_tag(struct fqdn_pending_req *req, + char values[][MAX_TAG_VALUES_LEN], int *values_len, int ip_ver); typedef bool (*dns_ovsdb_updater)(const char *, const char *, const char *, json_t *, ovs_uuid_t *); @@ -195,12 +194,27 @@ typedef bool (*dns_ovsdb_updater)(const char *, const char *, * @return false failed to update */ bool -dns_upsert_tag(struct schema_Openflow_Tag *row, dns_ovsdb_updater updater); +dns_upsert_regular_tag(struct schema_Openflow_Tag *row, dns_ovsdb_updater updater); + +/** + * @brief update Openflow_Tag to map to new row + * + * @param row new row to be written to Openflow_Tag + * @param updater dependency injection for updating + * + * @return true succeeded in update + * @return false failed to update + */ +bool +dns_upsert_local_tag(struct schema_Openflow_Local_Tag *row, dns_ovsdb_updater updater); void dns_forward(struct dns_session *dns_session, dns_info *dns, uint8_t *packet, int len); +void +dns_update_tag(struct fqdn_pending_req *req); + void dns_periodic(struct fsm_session *session); diff --git a/src/lib/dns_parse/src/dns_parse.c b/src/lib/dns_parse/src/dns_parse.c index b92449ad..2c48e343 100644 --- a/src/lib/dns_parse/src/dns_parse.c +++ b/src/lib/dns_parse/src/dns_parse.c @@ -20,6 +20,7 @@ #include "rtypes.h" #include "strutils.h" #include "policy_tags.h" +#include "os_util.h" #include "fsm.h" #include "fsm_policy.h" @@ -84,43 +85,6 @@ dns_dev_id_cmp(void *a, void *b) } -static void -dns_process_provider(struct fsm_session *session) -{ - struct dns_session *dns_session; - struct fsm_session *service; - bool reset; - - dns_session = session->handler_ctxt; - /* If no provider plugin yet, attempt update */ - if (dns_session->provider_plugin == NULL) - { - service = session->service; - dns_session->provider_plugin = service; - if (service != NULL) - { - dns_session->provider = strdup(service->name); - dns_session->provider_ops = &service->p_ops->web_cat_ops; - } - return; - } - - LOGT("%s: original provider %s, new provider %s", __func__, - dns_session->provider, - session->service ? session->service->name : "unknown"); - - /* Provider was set, check if it changed */ - reset = (dns_session->provider_plugin != session->service); - - if (reset) - { - sleep(2); - LOGEM("%s: provider change detected. Restarting", __func__); - exit(EXIT_SUCCESS); - } -} - - static void dns_parse_update(struct fsm_session *session) { @@ -128,15 +92,11 @@ dns_parse_update(struct fsm_session *session) char *dbg_str = session->ops.get_config(session, "debug"); char *cache_ip_str = session->ops.get_config(session, "cache_ip"); char *mqtt_blocker_topic = session->ops.get_config(session, "blk_mqtt"); - char *policy_table = session->ops.get_config(session, "policy_table"); char *hs_report_interval; char *hs_report_topic; long interval; int val; - dns_session->policy_client.name = policy_table; - dns_process_provider(session); - dns_session->health_stats_report_interval = (long)INT_MAX; hs_report_interval = session->ops.get_config(session, "wc_health_stats_interval_secs"); @@ -317,7 +277,6 @@ dns_free_session(struct dns_session *d_session) ds_tree_remove(tree, remove); dns_free_device(remove); } - free(d_session->provider); free(d_session); } @@ -341,7 +300,6 @@ dns_delete_session(struct fsm_session *session) if (d_session == NULL) return; LOGD("%s: removing session %s", __func__, session->name); - fsm_policy_deregister_client(&d_session->policy_client); ds_tree_remove(sessions, d_session); dns_free_session(d_session); @@ -361,24 +319,6 @@ dns_plugin_exit(struct fsm_session *session) } -void -dns_update_client(struct fsm_session *session, - struct policy_table *table) -{ - struct dns_session * dns_session; - struct fsm_policy_client *client; - - if (session == NULL) return; - if (table == NULL) return; - - dns_session = dns_lookup_session(session); - if (dns_session == NULL) return; - - client = &dns_session->policy_client; - client->table = table; -} - - void dns_set_provider(struct fsm_session *session) { @@ -463,6 +403,7 @@ dns_mgr_init(void) struct dns_session, session_node); mgr->set_forward_context = dns_set_forward_context; mgr->forward = dns_forward; + mgr->update_tag = dns_update_tag; mgr->policy_init = fsm_policy_init; mgr->policy_check = fqdn_policy_check; mgr->req_cache_ttl = REQ_CACHE_TTL; @@ -475,9 +416,7 @@ dns_plugin_init(struct fsm_session *session) { struct dns_cache *mgr; struct dns_session *dns_session; - struct fsm_policy_client *client; struct fsm_parser_ops *parser_ops; - struct fsm_session *service; time_t now; int rc; @@ -521,22 +460,11 @@ dns_plugin_init(struct fsm_session *session) dns_session->stat_log_ts = now; dns_session->debug = false; dns_set_provider(session); - dns_parse_update(session); mgr->policy_init(); - client = &dns_session->policy_client; - client->session = session; - client->update_client = dns_update_client; - fsm_policy_register_client(&dns_session->policy_client); - ds_tree_init(&dns_session->session_devices, dns_dev_id_cmp, struct dns_device, device_node); - service = session->service; - if (session->service) - { - dns_session->provider_ops = &service->p_ops->web_cat_ops; - } dns_session->cat_offline.check_offline = 30; dns_session->cat_offline.provider_offline = false; dns_session->initialized = true; @@ -696,6 +624,162 @@ dns_forward(struct dns_session *dns_session, dns_info *dns, } +bool +dns_updatev4_tag(struct fqdn_pending_req *req) +{ + bool result = false; + int tle_flag; + size_t len = 0; + + struct schema_Openflow_Tag regular_tag; + struct schema_Openflow_Local_Tag local_tag; + + memset(®ular_tag, 0, sizeof(struct schema_Openflow_Tag)); + memset(&local_tag, 0, sizeof(struct schema_Openflow_Local_Tag)); + + if (req->action != FSM_UPDATE_TAG) return false; + + tle_flag = om_get_type_of_tag(req->updatev4_tag); + + if (tle_flag == OM_TLE_FLAG_DEVICE || + tle_flag == OM_TLE_FLAG_CLOUD) + { + len = strlen(req->updatev4_tag); + os_util_strncpy(regular_tag.name, &req->updatev4_tag[3], len - 3); + regular_tag.name_exists = true; + regular_tag.name_present = true; + + result = dns_generate_update_tag(req, regular_tag.device_value, + ®ular_tag.device_value_len, 4); + if (result) + { + result = dns_upsert_regular_tag(®ular_tag, ovsdb_sync_upsert); + if (!result) + { + LOGT("%s: Openflow_Tag not updated for request.", __func__); + } + } + else + { + LOGT("%s: Openflow_Tag not updated for request.", __func__); + } + } else if(tle_flag == OM_TLE_FLAG_LOCAL) { + + len = strlen(req->updatev4_tag); + os_util_strncpy(local_tag.name, &req->updatev4_tag[3], len - 3); + local_tag.name_exists = true; + local_tag.name_present = true; + + result = dns_generate_update_tag(req, local_tag.values, &local_tag.values_len, 4); + if (result) + { + result = dns_upsert_local_tag(&local_tag, ovsdb_sync_upsert); + if (!result) + { + LOGT("%s: Openflow_Local_Tag not updated for request.", __func__); + } + } + else + { + LOGT("%s: Openflow_Local_Tag not updated for request.", __func__); + } + } + + return result; +} + + +bool +dns_updatev6_tag(struct fqdn_pending_req *req) +{ + bool result = false; + int tle_flag; + size_t len = 0; + struct schema_Openflow_Tag regular_tag; + struct schema_Openflow_Local_Tag local_tag; + + memset(®ular_tag, 0, sizeof(struct schema_Openflow_Tag)); + memset(&local_tag, 0, sizeof(struct schema_Openflow_Local_Tag)); + if (req->action != FSM_UPDATE_TAG) return false; + + tle_flag = om_get_type_of_tag(req->updatev6_tag); + + if (tle_flag == OM_TLE_FLAG_DEVICE || + tle_flag == OM_TLE_FLAG_CLOUD) + { + len = strlen(req->updatev6_tag); + os_util_strncpy(regular_tag.name, &req->updatev6_tag[3], len - 3); + regular_tag.name_exists = true; + regular_tag.name_present = true; + + result = dns_generate_update_tag(req, regular_tag.device_value, ®ular_tag.device_value_len, 6); + if (result) + { + result = dns_upsert_regular_tag(®ular_tag, ovsdb_sync_upsert); + if (!result) + { + LOGT("%s: Openflow_Tag not updated for request.", __func__); + } + } + else + { + LOGT("%s: Openflow_Tag not updated for request.", __func__); + } + } else if(tle_flag == OM_TLE_FLAG_LOCAL) { + + len = strlen(req->updatev6_tag); + os_util_strncpy(local_tag.name, &req->updatev6_tag[3], len - 3); + local_tag.name_exists = true; + local_tag.name_present = true; + + result = dns_generate_update_tag(req, local_tag.values, &local_tag.values_len, 6); + if (result) + { + result = dns_upsert_local_tag(&local_tag, ovsdb_sync_upsert); + if (!result) + { + LOGT("%s: Openflow_Local_Tag not updated for request.", __func__); + } + } + else + { + LOGT("%s: Openflow_Local_Tag not updated for request.", __func__); + } + } + + return result; +} + + +void +dns_update_tag(struct fqdn_pending_req *req) +{ + bool rc = false; + + if (!req) return; + + if (req->updatev4_tag) + { + rc = dns_updatev4_tag(req); + if (!rc) + { + LOGT("%s: Failed to update ipv4 OpenFlow tags.",__func__); + } + } + + if (req->updatev6_tag) + { + rc = dns_updatev6_tag(req); + if (!rc) + { + LOGT("%s: Failed to update ipv6 OpenFlow tags.",__func__); + } + } + + return; +} + + static char redirect_prefix[RD_SZ][4] = { "A-", "4A-", "C-" @@ -831,8 +915,17 @@ dns_handle_reply(struct dns_session *dns_session, dns_info *dns, dns_session->req = req; process_response_ips(dns, packet, req); + if (req->action == FSM_UPDATE_TAG) + { + /* + * Update Tag if we are interested + * in the IPs returned. + */ + mgr->update_tag(req); + } + /* forward the DNS response if the session has no categorization provider */ - if (dns_session->provider_ops == NULL) + if (session->provider_ops == NULL) { LOGT("%s: %s session : no provider available", __func__, session->name); @@ -842,11 +935,11 @@ dns_handle_reply(struct dns_session *dns_session, dns_info *dns, } /* forward DNS response to category filter */ - if (dns_session->provider_ops->dns_response) + if (session->provider_ops->dns_response) { LOGT("%s: dns reply: forwarding to category provider %s", __func__, - dns_session->provider); - dns_session->provider_ops->dns_response(session, req); + session->provider); + session->provider_ops->dns_response(session, req); } if (req->action == FSM_FORWARD) @@ -863,44 +956,17 @@ dns_handle_reply(struct dns_session *dns_session, dns_info *dns, mgr->forward(dns_session, dns, packet, header->caplen); dns_remove_req(dns_session, ð->dstmac, req->req_id); } - else if (req->action == FSM_UPDATE_TAG) - { - /* - * Update Openflow_Tag if we are interested - * in the IPs returned. - */ - struct schema_Openflow_Tag updated; - bool result; - - result = dns_generate_update_tag(req, &updated); - if (result) - { - result = dns_upsert_tag(&updated, ovsdb_sync_upsert); - if (!result) - { - LOGT("%s: Openflow_Tag not updated for request.", __func__); - } - } - else - { - LOGT("%s: No update tag generated for OVSDB transaction.", __func__); - } - - dns_forward(dns_session, dns, packet, header->caplen); - dns_remove_req(dns_session, ð->dstmac, req->req_id); - } - else if (req->action == FSM_BLOCK) { char reason[128] = { 0 }; char risk[128] = { 0 }; if (req->categorized == FSM_FQDN_CAT_SUCCESS) { - if (dns_session->provider_ops->cat2str && (req->cat_match != -1)) + if (session->provider_ops->cat2str && (req->cat_match != -1)) { snprintf(reason, sizeof(reason), "categorized as %s", - dns_session->provider_ops->cat2str(session, - req->cat_match)); + session->provider_ops->cat2str(session, + req->cat_match)); } if (req->risk_level != -1) { @@ -977,9 +1043,12 @@ set_provider_ops(struct dns_session *dns_session, struct fqdn_pending_req *req) { struct web_cat_offline *offline; + struct fsm_session *session; + + session = dns_session->fsm_context; /* No backend available. Bail */ - if (dns_session->provider_ops == NULL) return; + if (session->provider_ops == NULL) return; /* Check if the backend provider is offline */ offline = &dns_session->cat_offline; @@ -998,8 +1067,8 @@ set_provider_ops(struct dns_session *dns_session, } /* Set the backend provider ops */ - req->categories_check = dns_session->provider_ops->categories_check; - req->risk_level_check = dns_session->provider_ops->risk_level_check; + req->categories_check = session->provider_ops->categories_check; + req->risk_level_check = session->provider_ops->risk_level_check; } @@ -1130,10 +1199,10 @@ dns_handler(struct fsm_session *session, struct net_header_parser *net_header) req->fsm_checked = false; req->risk_level = -1; req->cat_match = -1; - req->policy_table = dns_session->policy_client.table; + req->policy_table = session->policy_client.table; set_provider_ops(dns_session, req); - req->provider = dns_session->provider; + req->provider = session->provider; req_info = req->req_info; qnext = dns.queries; for (i = 0; i < dns.qdcount; i++) @@ -1580,14 +1649,14 @@ dns_remove_req(struct dns_session *dns_session, os_macaddr_t *mac, bool -is_in_device_set(struct schema_Openflow_Tag *row, char *checking) +is_in_device_set(char values[][MAX_TAG_VALUES_LEN], int values_len, char *checking) { int ret; int i; - for(i = 0; i < row->device_value_len; i++) + for(i = 0; i < values_len; i++) { - ret = strcmp(row->device_value[i], checking); + ret = strcmp(values[i], checking); if (!ret) return true; } return false; @@ -1596,72 +1665,90 @@ is_in_device_set(struct schema_Openflow_Tag *row, char *checking) bool dns_generate_update_tag(struct fqdn_pending_req *req, - struct schema_Openflow_Tag *output) + char values[][MAX_TAG_VALUES_LEN], + int *values_len, int ip_ver) { bool added_information; - int device_value_len; + int orig_values_len; om_tag_t *tag; char *adding; + char name[MAX_TAG_NAME_LEN] = {0}; + int name_len = 0; bool rc; int i; if (req->action != FSM_UPDATE_TAG) return false; added_information = false; - device_value_len = output->device_value_len; + orig_values_len = *values_len; + - STRSCPY(output->name, req->update_tag); - output->name_exists = true; - output->name_present = true; + if (ip_ver == 4) + { + name_len = strlen(req->updatev4_tag); + os_util_strncpy(name, &req->updatev4_tag[3], name_len - 3); + tag = om_tag_find_by_name(name, false); + } + else if (ip_ver == 6) + { + name_len = strlen(req->updatev6_tag); + os_util_strncpy(name, &req->updatev6_tag[3], name_len - 3); + tag = om_tag_find_by_name(name, false); + } + else + { + return false; + } /* Load in current in memory tag state */ - tag = om_tag_find_by_name(req->update_tag, false); if (tag != NULL) { om_tag_list_entry_t *iter; - ds_tree_foreach(&tag->values, iter) { adding = iter->value; - rc = is_in_device_set(output, adding); + rc = is_in_device_set(values, *values_len, adding); if (!rc) { - STRSCPY(output->device_value[output->device_value_len], adding); - output->device_value_len++; + STRSCPY(values[*values_len], adding); + *values_len = *values_len + 1; } } } - /* Add new IPv4 and IPv6 responses to tag */ - for (i = 0; i < req->ipv4_cnt; i++) + if (ip_ver == 4) { - adding = req->ipv4_addrs[i]; - rc = is_in_device_set(output, adding); - if (!rc) + for (i = 0; i < req->ipv4_cnt; i++) { - STRSCPY(output->device_value[output->device_value_len], adding); - output->device_value_len++; + adding = req->ipv4_addrs[i]; + rc = is_in_device_set(values, *values_len, adding); + if (!rc) + { + STRSCPY(values[*values_len], adding); + *values_len = *values_len + 1; + } } - } + } else if (ip_ver == 6) { - for (i = 0; i < req->ipv6_cnt; i++) - { - adding = req->ipv6_addrs[i]; - rc = is_in_device_set(output, adding); - if (!rc) + for (i = 0; i < req->ipv6_cnt; i++) { - STRSCPY(output->device_value[output->device_value_len], adding); - output->device_value_len++; + adding = req->ipv6_addrs[i]; + rc = is_in_device_set(values, *values_len, adding); + if (!rc) + { + STRSCPY(values[*values_len], adding); + *values_len = *values_len + 1; + } } } - added_information = (output->device_value_len != device_value_len); - output->device_value_present = added_information; + added_information = (*values_len != orig_values_len); return added_information; } -bool dns_upsert_tag(struct schema_Openflow_Tag *row, dns_ovsdb_updater updater) + +bool dns_upsert_regular_tag(struct schema_Openflow_Tag *row, dns_ovsdb_updater updater) { pjs_errmsg_t err; json_t *jrow; @@ -1689,6 +1776,36 @@ bool dns_upsert_tag(struct schema_Openflow_Tag *row, dns_ovsdb_updater updater) return false; } + +bool dns_upsert_local_tag(struct schema_Openflow_Local_Tag *row, dns_ovsdb_updater updater) +{ + pjs_errmsg_t err; + json_t *jrow; + bool ret; + + jrow = schema_Openflow_Local_Tag_to_json(row, err); + if (jrow == NULL) + { + LOGD("%s: failed to generate JSON for upsert: %s", __func__, err); + + return false; + } + + ret = updater(SCHEMA_TABLE(Openflow_Local_Tag), SCHEMA_COLUMN(Openflow_Local_Tag, name), + row->name, jrow, NULL); + json_decref(jrow); + if (ret) + { + LOGD("%s: Updated Openflow_Local_Tag: %s with new IP set.", __func__, + row->name); + return true; + } + LOGD("%s: Return value from OVSDB update was: %d", __func__, ret); + + return false; +} + + /* Local log interval */ #define DNS_LOG_PERIODIC 120 @@ -1815,7 +1932,7 @@ dns_report_health_stats(struct dns_session *dns_session, hs.cache_size = count; /* Prepare report */ - report.provider = dns_session->provider; + report.provider = session->provider; report.op = &op; report.ow = &ow; report.health_stats = &hs; @@ -1902,8 +2019,8 @@ dns_periodic(struct fsm_session *session) /* Check if web categorization stats are available */ if (session->service == NULL) return; - if (dns_session->provider_ops == NULL) return; - if (dns_session->provider_ops->get_stats == NULL) return; + if (session->provider_ops == NULL) return; + if (session->provider_ops->get_stats == NULL) return; /* Check if the time has come to log the health stats locally */ cmp_log = now - dns_session->stat_log_ts; @@ -1919,7 +2036,7 @@ dns_periodic(struct fsm_session *session) /* Get the stats */ memset(&stats, 0, sizeof(stats)); - dns_session->provider_ops->get_stats(session, &stats); + session->provider_ops->get_stats(session, &stats); /* Log locally if the time has come */ if (cmp_log >= DNS_LOG_PERIODIC) dns_log_stats(dns_session, &stats, now); @@ -1958,7 +2075,8 @@ fqdn_policy_check(struct dns_device *ds, req->fsm_checked = false; fsm_apply_policies(session, &preq); req->action = preq.reply.action; - req->update_tag = preq.reply.update_tag; + req->updatev4_tag = preq.reply.updatev4_tag; + req->updatev6_tag = preq.reply.updatev6_tag; req->policy = preq.reply.policy; req->policy_idx = preq.reply.policy_idx; req->rule_name = preq.reply.rule_name; diff --git a/src/lib/dns_parse/tests/fut/create_dns_plugin.sh b/src/lib/dns_parse/tests/fut/create_dns_plugin.sh index 5622c068..ddf8dd4d 100755 --- a/src/lib/dns_parse/tests/fut/create_dns_plugin.sh +++ b/src/lib/dns_parse/tests/fut/create_dns_plugin.sh @@ -159,6 +159,34 @@ gen_dev_webpulse_policy() { EOF } +gen_dev_update_tag_policy() { + cat <updatev4_tag, "upd_v4_tag"); +} + + void test_dns_policy_init(void) { @@ -278,7 +302,6 @@ void setUp(void) { struct schema_Flow_Service_Manager_Config *conf; struct schema_FSM_Policy *spolicy; - struct dns_session *dns_session; struct fsm_policy_session *mgr; ds_tree_t *sessions; size_t nelems; @@ -321,11 +344,10 @@ void setUp(void) g_dns_mgr = dns_get_mgr(); g_dns_mgr->set_forward_context = test_set_fwd_context; g_dns_mgr->forward = test_dns_forward; + g_dns_mgr->update_tag = test_dns_update_tag; g_dns_mgr->policy_init = test_dns_policy_init; dns_plugin_init(g_fsm_parser); - dns_session = (struct dns_session *)(g_fsm_parser->handler_ctxt); - dns_session->provider_ops = &g_plugin_ops.web_cat_ops; g_ipv4_cnt = 0; @@ -476,6 +498,47 @@ test_type_A_query_response(void) free(net_parser); } +/** + * @brief test type A dns query and response + */ +void +test_type_A_query_response_update_tag(void) +{ + struct net_header_parser *net_parser; + struct dns_session *dns_session; + size_t len; + + dns_session = dns_lookup_session(g_fsm_parser); + TEST_ASSERT_NOT_NULL(dns_session); + + net_parser = calloc(1, sizeof(*net_parser)); + TEST_ASSERT_NOT_NULL(net_parser); + + /* Process query */ + PREPARE_UT(pkt46, net_parser); + len = net_header_parse(net_parser); + TEST_ASSERT_TRUE(len != 0); + dns_handler(g_fsm_parser, net_parser); + + /* + * The captured dns answer has 8 resolved IP addresses. + * Set validation expectations + */ + g_ipv4_cnt = 8; + + /* Process response */ + memset(net_parser, 0, sizeof(*net_parser)); + PREPARE_UT(pkt47, net_parser); + len = net_header_parse(net_parser); + TEST_ASSERT_TRUE(len != 0); + dns_handler(g_fsm_parser, net_parser); + + g_dns_mgr->req_cache_ttl = 0; + dns_retire_reqs(g_fsm_parser); + + free(net_parser); +} + /** * @brief test type A duplicate dns query single response */ @@ -586,6 +649,7 @@ int main(int argc, char *argv[]) RUN_TEST(test_type_A_query); RUN_TEST(test_type_PTR_query); RUN_TEST(test_type_A_query_response); + RUN_TEST(test_type_A_query_response_update_tag); RUN_TEST(test_type_A_duplicate_query_response); RUN_TEST(test_type_A_duplicate_query_duplicate_response); diff --git a/src/lib/dns_parse/tests/ut/unit.mk b/src/lib/dns_parse/tests/ut/unit.mk index e2ee2c65..1b91efb9 100644 --- a/src/lib/dns_parse/tests/ut/unit.mk +++ b/src/lib/dns_parse/tests/ut/unit.mk @@ -13,6 +13,7 @@ UNIT_SRC += ../../../../fsm/src/fsm_pcap.c UNIT_SRC += ../../../../fsm/src/fsm_event.c UNIT_SRC += ../../../../fsm/src/fsm_service.c UNIT_SRC += ../../../../fsm/src/fsm_dpi.c +UNIT_SRC += ../../../../fsm/src/fsm_oms.c UNIT_DEPS := src/lib/log UNIT_DEPS += src/lib/common @@ -22,3 +23,4 @@ UNIT_DEPS += src/lib/dns_parse UNIT_DEPS += src/lib/unity UNIT_DEPS += src/lib/fsm_utils UNIT_DEPS += src/lib/fsm_policy +UNIT_DEPS += src/lib/oms diff --git a/src/lib/dns_parse/unit.mk b/src/lib/dns_parse/unit.mk index 1a2b70b8..379d9bb4 100644 --- a/src/lib/dns_parse/unit.mk +++ b/src/lib/dns_parse/unit.mk @@ -34,3 +34,4 @@ UNIT_DEPS += src/lib/osa UNIT_DEPS += src/lib/fsm_policy UNIT_DEPS += src/lib/network_telemetry UNIT_DEPS += src/lib/json_mqtt +UNIT_DEPS += src/lib/common diff --git a/src/lib/evx/kconfig/Kconfig.libs b/src/lib/evx/kconfig/Kconfig.libs index ad9ceae6..ef2edf34 100644 --- a/src/lib/evx/kconfig/Kconfig.libs +++ b/src/lib/evx/kconfig/Kconfig.libs @@ -1,6 +1,6 @@ menu "libevx Configuration" config LIBEVX_USE_CARES - bool "Asnychronous DNS resolution support" + bool "Asynchronous DNS resolution support" default n help Enable support for asynchronous DNS resolution. diff --git a/src/lib/fcm_filter/src/fcm_report_filter.c b/src/lib/fcm_filter/src/fcm_report_filter.c index a4198b43..37b36607 100644 --- a/src/lib/fcm_filter/src/fcm_report_filter.c +++ b/src/lib/fcm_filter/src/fcm_report_filter.c @@ -48,9 +48,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static fcm_plugin_filter_t filtername; -static -void net_md_print_net_md_flow_key_and_flow_key(struct net_md_flow_key *key, - struct flow_key *fkey); /** * @brief initialization function filter name. * @@ -76,116 +73,7 @@ static void print_md_acc_key(struct net_md_stats_accumulator *md_acc) LOGT("net_md_stats_accumulator=%p key=%p fkey=%p", md_acc, md_acc->key, md_acc->fkey); - net_md_print_net_md_flow_key_and_flow_key(md_acc->key, md_acc->fkey); - - LOGT("report_counter packets_count = %" PRIu64 "bytes_count = %"PRIu64, - md_acc->report_counters.packets_count, - md_acc->report_counters.bytes_count); -} - - -/** - * @brief print function net_md_stats_accumulator's key and fkey. - * - * receive net_md_stats_accumulator and fill the structure for report filter. - * - * @param valid pointer to net_md_flow_key and flow_key. - * @return void. - */ -static -void net_md_print_net_md_flow_key_and_flow_key(struct net_md_flow_key *key, - struct flow_key *fkey) -{ - char src_ip[INET6_ADDRSTRLEN] = {0}; - char dst_ip[INET6_ADDRSTRLEN] = {0}; - struct flow_tags *ftag; - os_macaddr_t null_mac; - os_macaddr_t *smac; - os_macaddr_t *dmac; - size_t i, j; - int af; - - memset(&null_mac, 0, sizeof(null_mac)); - - if (key != NULL) - { - af = key->ip_version == 4 ? AF_INET : AF_INET6; - inet_ntop(af, key->src_ip, src_ip, INET6_ADDRSTRLEN); - inet_ntop(af, key->dst_ip, dst_ip, INET6_ADDRSTRLEN); - - smac = (key->smac != NULL ? key->smac : &null_mac); - dmac = (key->dmac != NULL ? key->dmac : &null_mac); - - LOGD("%s: Printing key => net_md_flow_key :: fkey => flow_key", - __func__); - LOGD("------------"); - LOGD(" smac:" PRI_os_macaddr_lower_t \ - " dmac:" PRI_os_macaddr_lower_t \ - " vlanid: %d" \ - " ethertype: %d" \ - " ip_version: %d" \ - " src_ip: %s" \ - " dst_ip: %s" \ - " ipprotocol: %d" \ - " sport: %d" \ - " dport: %d", - FMT_os_macaddr_pt(smac), - FMT_os_macaddr_pt(dmac), - key->vlan_id, - key->ethertype, - key->ip_version, - src_ip, - dst_ip, - key->ipprotocol, - ntohs(key->sport), - ntohs(key->dport)); - if (key->fstart) LOGD(" Flow Starts"); - if (key->fend) LOGD(" Flow Ends"); - LOGD("------------"); - } - if (fkey != NULL) - { - /* LOGD("%s: Printing fkey => flow_key", __func__); */ - LOGD(" smac: %s" \ - " dmac: %s" \ - " vlanid: %d" \ - " ethertype: %d" \ - " ip_version: %d"\ - " src_ip: %s" \ - " dst_ip: %s" \ - " protocol: %d" \ - " sport: %d" \ - " dport: %d", - fkey->smac, - fkey->dmac, - fkey->vlan_id, - fkey->ethertype, - fkey->ip_version, - fkey->src_ip, - fkey->dst_ip, - fkey->protocol, - fkey->sport, - fkey->dport); - LOGD(" Flow State:"); - LOGD(" First observed : %s", ctime(&fkey->state.first_obs)); - LOGD(" Last observed : %s", ctime(&fkey->state.last_obs)); - if (fkey->state.fstart) LOGD(" Flow Starts"); - if (fkey->state.fend) LOGD(" Flow Ends"); - for (i = 0; i < fkey->num_tags; i++) - { - ftag = fkey->tags[i]; - LOGD(" vendor: %s" \ - " app_name: %s", - ftag->vendor, - ftag->app_name); - for (j = 0; j < ftag->nelems; j++) - { - LOGD(" tag[%zu]: %s", - j, ftag->tags[j]); - } - } - LOGD("------------"); - } + net_md_log_acc(md_acc); } diff --git a/src/lib/fsm_policy/inc/fsm_policy.h b/src/lib/fsm_policy/inc/fsm_policy.h index 40b63f95..343c3d58 100644 --- a/src/lib/fsm_policy/inc/fsm_policy.h +++ b/src/lib/fsm_policy/inc/fsm_policy.h @@ -184,7 +184,8 @@ struct fqdn_pending_req int cat_match; int risk_level; int action; - char *update_tag; + char *updatev4_tag; + char *updatev6_tag; bool redirect; int rd_ttl; char *policy; @@ -226,7 +227,8 @@ struct fsm_policy_reply char *policy; /* the last matching policy */ int policy_idx; /* the policy index */ char *rule_name; /* the last matching rule name with the policy */ - char *update_tag; /* Tag to store results with if any */ + char *updatev4_tag; /* Tag to store ipv4 dns results with if any */ + char *updatev6_tag; /* Tag to store ipv6 dns results with if any */ }; @@ -349,7 +351,7 @@ void fsm_add_policy(struct schema_FSM_Policy *spolicy); void fsm_delete_policy(struct schema_FSM_Policy *spolicy); void fsm_update_policy(struct schema_FSM_Policy *spolicy); void fsm_free_policy(struct fsm_policy *fpolicy); -struct policy_table *fsm_policy_select_table(void); +struct policy_table *fsm_policy_find_table(char *name); void fsm_apply_policies(struct fsm_session *session, struct fsm_policy_req *req); bool fsm_fqdncats_in_set(struct fsm_policy_req *req, struct fsm_policy *p); diff --git a/src/lib/fsm_policy/src/fsm_policy.c b/src/lib/fsm_policy/src/fsm_policy.c index f9b2f029..60b8e8c6 100644 --- a/src/lib/fsm_policy/src/fsm_policy.c +++ b/src/lib/fsm_policy/src/fsm_policy.c @@ -113,6 +113,7 @@ void fsm_walk_policy_macs(struct fsm_policy *p) /* pass tag values marker */ tag_has_marker = (*tag_s == TEMPLATE_DEVICE_CHAR); tag_has_marker |= (*tag_s == TEMPLATE_CLOUD_CHAR); + tag_has_marker |= (*tag_s == TEMPLATE_LOCAL_CHAR); if (tag_has_marker) tag_s += 1; /* Copy tag name, remove end marker */ @@ -448,7 +449,8 @@ static void set_action(struct fsm_policy_req *req, struct fsm_policy *p) req->reply.action = p->action; } -#define UPDATE_TAG "tag_name" +#define UPDATEv4_TAG "tagv4_name" +#define UPDATEv6_TAG "tagv6_name" /** * @brief set_tag_update: set whether the request is flagged to update tag @@ -465,11 +467,15 @@ void set_tag_update(struct fsm_policy_req *req, struct fsm_policy *p) tree = p->other_config; if (tree == NULL) return; + pair = ds_tree_find(tree, UPDATEv4_TAG); + if (pair == NULL) return; + + req->reply.updatev4_tag = pair->value; - pair = ds_tree_find(tree, UPDATE_TAG); + pair = ds_tree_find(tree, UPDATEv6_TAG); if (pair == NULL) return; - req->reply.update_tag = pair->value; + req->reply.updatev6_tag = pair->value; } /** diff --git a/src/lib/fsm_policy/src/fsm_policy_client.c b/src/lib/fsm_policy/src/fsm_policy_client.c index 5e401561..0b966fe5 100644 --- a/src/lib/fsm_policy/src/fsm_policy_client.c +++ b/src/lib/fsm_policy/src/fsm_policy_client.c @@ -94,7 +94,7 @@ void fsm_policy_register_client(struct fsm_policy_client *client) /* Update the internal client */ p_client->update_client = client->update_client; - LOGD("%s: updating client %s", __func__, p_client->name); + LOGI("%s: updating client %s", __func__, p_client->name); return; } @@ -113,7 +113,7 @@ void fsm_policy_register_client(struct fsm_policy_client *client) client->table = table; ds_tree_insert(tree, p_client, p_client); - LOGD("%s: registered client %s", __func__, p_client->name); + LOGI("%s: registered client %s", __func__, p_client->name); return; @@ -153,6 +153,9 @@ void fsm_policy_update_clients(struct policy_table *table) tree = &mgr->clients; client = ds_tree_head(tree); + LOGI("%s: Updating clients of table: %s", __func__, + table->name == NULL ? default_name : table->name); + while (client != NULL) { char *name; @@ -162,8 +165,11 @@ void fsm_policy_update_clients(struct policy_table *table) name = (client->name == NULL ? default_name : client->name); cmp = strcmp(name, table->name); update = ((cmp == 0) && (client->update_client != NULL)); - if (update) client->update_client(client->session, table); - + if (update) + { + LOGI("%s: updating client %s", __func__, client->name); + client->update_client(client->session, table); + } client = ds_tree_next(tree, client); } } diff --git a/src/lib/fsm_policy/src/fsm_policy_ovsdb.c b/src/lib/fsm_policy/src/fsm_policy_ovsdb.c index 2d691e02..7b7c7bca 100644 --- a/src/lib/fsm_policy/src/fsm_policy_ovsdb.c +++ b/src/lib/fsm_policy/src/fsm_policy_ovsdb.c @@ -690,10 +690,6 @@ struct fsm_policy * fsm_policy_get(struct schema_FSM_Policy *spolicy) ds_tree_insert(tree, table, table->name); LOGN("%s: Loading policy table %s", __func__, name); - - /* Update policy clients */ - fsm_policy_update_clients(table); - } idx = spolicy->idx; @@ -701,6 +697,10 @@ struct fsm_policy * fsm_policy_get(struct schema_FSM_Policy *spolicy) if (*fpolicy != NULL) return *fpolicy; *fpolicy = fsm_policy_insert_schema_p(table, spolicy); + + /* Update policy clients */ + fsm_policy_update_clients(table); + return *fpolicy; } @@ -820,6 +820,21 @@ void callback_FSM_Policy(ovsdb_update_monitor_t *mon, } } +struct policy_table * fsm_policy_find_table(char *name) +{ + struct fsm_policy_session *mgr; + struct policy_table *table; + ds_tree_t *tree; + + if (name == NULL) return NULL; + + mgr = fsm_policy_get_mgr(); + tree = &mgr->policy_tables; + table = ds_tree_find(tree, name); + + return table; +} + int table_name_cmp(void *a, void *b) { diff --git a/src/lib/fsm_policy/ut/fsm_policy/test_fsm_policy.c b/src/lib/fsm_policy/ut/fsm_policy/test_fsm_policy.c index b68dbc00..f10a0c45 100644 --- a/src/lib/fsm_policy/ut/fsm_policy/test_fsm_policy.c +++ b/src/lib/fsm_policy/ut/fsm_policy/test_fsm_policy.c @@ -274,9 +274,9 @@ struct schema_FSM_Policy spolicies[] = .ipaddrs_len = 0, .action_exists = true, .action = "update_tag", - .other_config_len = 1, - .other_config_keys = { "tag_name", }, - .other_config = { "my_tag" }, + .other_config_len = 2, + .other_config_keys = { "tagv4_name", "tagv6_name",}, + .other_config = { "my_v4_tag", "my_v6_tag"}, }, }; @@ -715,7 +715,8 @@ void test_apply_wildcard_policy_match_in(void) reply = &req.reply; /* Verify reply struct has been properly built */ - TEST_ASSERT_EQUAL_STRING("my_tag", reply->update_tag); + TEST_ASSERT_EQUAL_STRING("my_v4_tag", reply->updatev4_tag); + TEST_ASSERT_EQUAL_STRING("my_v6_tag", reply->updatev6_tag); TEST_ASSERT_EQUAL_INT(FSM_UPDATE_TAG, reply->action); free(reply->rule_name); diff --git a/src/lib/hostap/inc/opensync-hapd.h b/src/lib/hostap/inc/opensync-hapd.h index 7c8d1e9c..24949ae0 100644 --- a/src/lib/hostap/inc/opensync-hapd.h +++ b/src/lib/hostap/inc/opensync-hapd.h @@ -36,6 +36,7 @@ struct hapd { char confpath[PATH_MAX]; char conf[4096]; char psks[4096]; + char country[3]; int respect_multi_ap; int skip_probe_response; void (*sta_connected)(struct hapd *hapd, const char *mac, const char *keyid); diff --git a/src/lib/hostap/src/hapd.c b/src/lib/hostap/src/hapd.c index 4bc1517d..d6d47238 100644 --- a/src/lib/hostap/src/hapd.c +++ b/src/lib/hostap/src/hapd.c @@ -389,7 +389,11 @@ hapd_conf_gen(struct hapd *hapd, { const char *wpa_pairwise; const char *wpa_key_mgmt; + const char *radius_server_ip; + const char *radius_server_port; + const char *radius_server_secret; size_t len = sizeof(hapd->conf); + bool suppress_wps = false; char *buf = hapd->conf; char keys[32]; int closed; @@ -418,6 +422,12 @@ hapd_conf_gen(struct hapd *hapd, csnprintf(&buf, &len, "multi_ap=%d\n", hapd_map_str2int(vconf)); csnprintf(&buf, &len, "send_probe_response=%d\n", hapd->skip_probe_response ? 0 : 1); + if (strlen(hapd->country) > 0) { + csnprintf(&buf, &len, "country_code=%s\n", hapd->country); + csnprintf(&buf, &len, "ieee80211d=1\n"); + csnprintf(&buf, &len, "ieee80211h=1\n"); + } + /* FIXME: ieee80211n, iee80211ac, ieee80211ax is missing, also min_hw_mode.. * perhaps some of this needs to be scheduled for wireless api rework */ @@ -465,13 +475,49 @@ hapd_conf_gen(struct hapd *hapd, csnprintf(&buf, &len, "wpa_psk_file=%s\n", hapd->pskspath); csnprintf(&buf, &len, "wpa=%d\n", wpa); csnprintf(&buf, &len, "wpa_pairwise=%s\n", wpa_pairwise); + } else if (!strcmp(wpa_key_mgmt, "WPA-EAP")) { + csnprintf(&buf, &len, "auth_algs=1\n"); + csnprintf(&buf, &len, "ieee8021x=1\n"); + csnprintf(&buf, &len, "own_ip_addr=127.0.0.1\n"); + csnprintf(&buf, &len, "wpa_key_mgmt=WPA-EAP\n"); + /* WPA-EAP supports solely WPA2 */ + csnprintf(&buf, &len, "wpa=2\n"); + csnprintf(&buf, &len, "wpa_pairwise=CCMP\n"); + + radius_server_ip = SCHEMA_KEY_VAL(vconf->security, "radius_server_ip"); + radius_server_port = SCHEMA_KEY_VAL(vconf->security, "radius_server_port"); + radius_server_secret = SCHEMA_KEY_VAL(vconf->security, "radius_server_secret"); + + csnprintf(&buf, &len, "auth_server_addr=%s\n", radius_server_ip); + csnprintf(&buf, &len, "auth_server_port=%s\n", radius_server_port); + csnprintf(&buf, &len, "auth_server_shared_secret=%s\n", radius_server_secret); + } else if (!strcmp(wpa_key_mgmt, "OPEN")) { + csnprintf(&buf, &len, "wpa=0\n"); + csnprintf(&buf, &len, "auth_algs=1\n"); } else { LOGW("%s: key mgmt '%s' not supported", vconf->if_name, wpa_key_mgmt); errno = ENOTSUP; return -1; } - if (kconfig_enabled(CONFIG_HOSTAP_PSK_FILE_WPS)) { + /* + * WPA-EAP + remote RADIUS excludes WPS on single VAP (hostapd doesn't support + * such configuration). + */ + if (!strcmp(wpa_key_mgmt, "WPA-EAP") && vconf->wps) { + suppress_wps |= true; + LOGW("%s: Disabling WPS because WPA-EAP is enabled", vconf->if_name); + } + + /* + * OPEN mode and WPS cannot be configred on single VAP. + */ + if (!strcmp(wpa_key_mgmt, "OPEN") && vconf->wps) { + suppress_wps |= true; + LOGW("%s: Disabling WPS because OPEN mode is enabled", vconf->if_name); + } + + if (kconfig_enabled(CONFIG_HOSTAP_PSK_FILE_WPS) && !suppress_wps) { csnprintf(&buf, &len, "wps_state=%d\n", vconf->wps ? 2 : 0); csnprintf(&buf, &len, "eap_server=%d\n", vconf->wps ? 1 : 0); csnprintf(&buf, &len, "config_methods=virtual_push_button\n"); @@ -489,17 +535,31 @@ hapd_bss_get_security(struct schema_Wifi_VIF_State *vstate, const char *status) { const char *keys = ini_geta(status, "key_mgmt") ?: ""; - const char *wpa = ini_geta(status, "wpa"); - const char *mode = hapd_util_get_mode_str(atoi(wpa ?: "")); - /* `keys` can be also: 'FT-PSK WPA-PSK' */ - if (WARN_ON(!strstr(keys, "WPA-PSK"))) - return; + if (strstr(keys, "WPA-PSK")) { + const char *wpa = ini_geta(status, "wpa"); + const char *mode = hapd_util_get_mode_str(atoi(wpa ?: "")); - SCHEMA_KEY_VAL_APPEND(vstate->security, "encryption", "WPA-PSK"); - SCHEMA_KEY_VAL_APPEND(vstate->security, "mode", mode ?: "no_mode"); + /* `keys` can be also: 'FT-PSK WPA-PSK' */ + SCHEMA_KEY_VAL_APPEND(vstate->security, "encryption", "WPA-PSK"); + SCHEMA_KEY_VAL_APPEND(vstate->security, "mode", mode ?: "no_mode"); + } + else if (strcmp(keys, "WPA-EAP") == 0) { + const char *auth_server_addr = ini_geta(conf, "auth_server_addr"); + const char *auth_server_port = ini_geta(conf, "auth_server_port"); + const char *auth_server_shared_secret = ini_geta(conf, "auth_server_shared_secret"); + + SCHEMA_KEY_VAL_APPEND(vstate->security, "encryption", "WPA-EAP"); + SCHEMA_KEY_VAL_APPEND(vstate->security, "radius_server_ip", auth_server_addr); + SCHEMA_KEY_VAL_APPEND(vstate->security, "radius_server_port", auth_server_port); + SCHEMA_KEY_VAL_APPEND(vstate->security, "radius_server_secret", auth_server_shared_secret); + } + else if (strcmp(keys, "") == 0) { + /* OPEN mode */ + SCHEMA_KEY_VAL_APPEND(vstate->security, "encryption", "OPEN"); + } - /* FIXME: OPEN, WPA-EAP? */ + /* FIXME: WPA3? */ } static void @@ -628,6 +688,7 @@ hapd_bss_get(struct hapd *hapd, const char *status = HAPD_CLI(hapd, "get_config"); const char *conf = R(hapd->confpath) ?: ""; const char *psks = R(hapd->pskspath) ?: ""; + const char *map = ini_geta(conf, "multi_ap"); char *p; /* FIXME: return non-zero if interface doesnt exist? */ @@ -645,8 +706,8 @@ hapd_bss_get(struct hapd *hapd, vstate->ft_psk = atoi(p); if ((vstate->btm_exists = (p = ini_geta(conf, "bss_transition")))) vstate->btm = atoi(p); - if ((p = ini_geta(conf, "multi_ap"))) - SCHEMA_SET_STR(vstate->multi_ap, hapd_map_int2str(atoi(p))); + + SCHEMA_SET_STR(vstate->multi_ap, hapd_map_int2str(atoi(map ?: "0"))); if (status) { hapd_bss_get_security(vstate, conf, status); diff --git a/src/lib/hostap/src/wpas.c b/src/lib/hostap/src/wpas.c index a120468c..2eaacb73 100644 --- a/src/lib/hostap/src/wpas.c +++ b/src/lib/hostap/src/wpas.c @@ -460,11 +460,10 @@ wpas_bss_get_network(struct schema_Wifi_VIF_State *vstate, STRSCPY_WARN(vstate->parent, bssid); if ((vstate->ssid_exists = (ssid != NULL))) STRSCPY_WARN(vstate->ssid, ssid); - if (map) - SCHEMA_SET_STR(vstate->multi_ap, wpas_map_int2str(atoi(map))); SCHEMA_KEY_VAL_APPEND(vstate->security, "encryption", "WPA-PSK"); SCHEMA_KEY_VAL_APPEND(vstate->security, "key", psk); + SCHEMA_SET_STR(vstate->multi_ap, wpas_map_int2str(atoi(map ?: "0"))); SCHEMA_SET_STR(vstate->bridge, bridge); } diff --git a/src/lib/inet/inc/inet.h b/src/lib/inet/inc/inet.h index b7682e8e..ccb908e9 100644 --- a/src/lib/inet/inc/inet.h +++ b/src/lib/inet/inc/inet.h @@ -212,6 +212,11 @@ struct __inet /* Set MTU */ bool (*in_mtu_set_fn)(inet_t *self, int mtu); + /* Set parent interface */ + bool (*in_parent_ifname_set_fn)(inet_t *self, const char *parent_ifname); + + /* Set credentials for interface. PPP or VPN links need this */ + bool (*in_credential_set_fn)(inet_t *self, const char *username, const char *password); /** * Set IP assignment scheme: * - INET_ASSIGN_NONE - Interface does not have any IPv4 configuration @@ -276,7 +281,7 @@ struct __inet osn_ip_addr_t remote, osn_mac_addr_t macaddr); /* VLANs */ - bool (*in_vlan_set_fn)(inet_t *self, const char *ifparent, int vlanid); + bool (*in_vlanid_set_fn)(inet_t *self, int vlanid); /* DHCP sniffing - register callback for DHCP sniffing - if set to NULL sniffing is disabled */ bool (*in_dhsnif_lease_notify_fn)(inet_t *self, inet_dhcp_lease_fn_t *func); @@ -431,6 +436,41 @@ static inline bool inet_mtu_set(inet_t *self, int mtu) return self->in_mtu_set_fn(self, mtu); } +static inline bool inet_parent_ifname_set(inet_t *self, const char *parent_ifname) +{ + /* + * If the parent_ifname_set method is not set and the parent interface is + * being cleared (parent_ifname == NULL), it is valid to return success + * (true). + * + * This also ensures backward compatibility. + */ + if (self->in_parent_ifname_set_fn == NULL) + { + return (parent_ifname == NULL ? true : false); + } + + return self->in_parent_ifname_set_fn(self, parent_ifname); +} + +static inline bool inet_credential_set( + inet_t *self, + const char *username, + const char *password) +{ + if (self->in_credential_set_fn == NULL) + { + /* + * If the no in_credential_set method is defined, it is valid to unset + * the username as it was not possible to set it in the first place. + */ + + return (username == NULL ? true : false); + } + + return self->in_credential_set_fn(self, username, password); +} + static inline bool inet_assign_scheme_set(inet_t *self, enum inet_assign_scheme scheme) { if (self->in_assign_scheme_set_fn == NULL) return false; @@ -598,17 +638,15 @@ static inline bool inet_ip4tunnel_set( /* * VLAN settings * - * ifparent - parent interface * vlanid - the VLAN id */ -static inline bool inet_vlan_set( +static inline bool inet_vlanid_set( inet_t *self, - const char *ifparent, int vlanid) { - if (self->in_vlan_set_fn == NULL) return false; + if (self->in_vlanid_set_fn == NULL) return false; - return self->in_vlan_set_fn(self, ifparent, vlanid); + return self->in_vlanid_set_fn(self, vlanid); } /* diff --git a/src/lib/inet/inc/inet_base.h b/src/lib/inet/inc/inet_base.h index fd037d24..f7c1cebe 100644 --- a/src/lib/inet/inc/inet_base.h +++ b/src/lib/inet/inc/inet_base.h @@ -42,8 +42,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "synclist.h" #define INET_BASE_SERVICE_LIST(M) \ + M(INET_BASE_IF_ENABLE, "Ineterface Enable") \ M(INET_BASE_IF_CREATE, "Interface Creation") \ - M(INET_BASE_IF_EXISTS, "Interface Ready") \ + M(INET_BASE_IF_READY, "Interface Ready") \ M(INET_BASE_FIREWALL, "Firewall") \ M(INET_BASE_UPNP, "UPnP") \ M(INET_BASE_IGMP, "IGMP") \ diff --git a/src/lib/inet/inc/inet_eth.h b/src/lib/inet/inc/inet_eth.h index 642af5a8..3cf069f1 100644 --- a/src/lib/inet/inc/inet_eth.h +++ b/src/lib/inet/inc/inet_eth.h @@ -51,6 +51,7 @@ struct __inet_eth extern inet_t *inet_eth_new(const char *ifname); extern bool inet_eth_init(inet_eth_t *self, const char *ifname); +extern bool inet_eth_fini(inet_eth_t *self); extern bool inet_eth_mtu_set(inet_t *super, int mtu); extern bool inet_eth_service_commit(inet_base_t *super, enum inet_base_services srv, bool enable); diff --git a/src/lib/inet/inc/inet_pppoe.h b/src/lib/inet/inc/inet_pppoe.h new file mode 100644 index 00000000..0ac7e1b7 --- /dev/null +++ b/src/lib/inet/inc/inet_pppoe.h @@ -0,0 +1,59 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef INET_PPPOE_H_INCLUDED +#define INET_PPPOE_H_INCLUDED + +#include "const.h" +#include "osn_pppoe.h" + +#include "inet.h" +#include "inet_base.h" + +typedef struct inet_pppoe inet_pppoe_t; + +struct inet_pppoe +{ + /* Subclass inet_base_t */ + union + { + inet_t inet; + inet_base_t base; + }; + osn_pppoe_t *in_pppoe; /**< Instance of osn_pppoe_t */ + osn_netif_t *in_parent_netif; /**< Parent interface monitoring */ + char in_parent_ifname[C_IFNAME_LEN]; + char in_ppp_username[128]; /**< The PPP username */ + char in_ppp_password[128]; /**< The PPP password */ +}; + +inet_t *inet_pppoe_new(const char *ifname); +bool inet_pppoe_dtor(inet_t *super); + +bool inet_pppoe_init(inet_pppoe_t *self, const char *ifname); +bool inet_pppoe_fini(inet_pppoe_t *self); + +#endif /* INET_PPPOE_H_INCLUDED */ diff --git a/src/lib/inet/inc/inet_vlan.h b/src/lib/inet/inc/inet_vlan.h index 4a5a3926..be47f17c 100644 --- a/src/lib/inet/inc/inet_vlan.h +++ b/src/lib/inet/inc/inet_vlan.h @@ -24,13 +24,16 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(INET_VLAN_H_INCLUDED) +#ifndef INET_VLAN_H_INCLUDED #define INET_VLAN_H_INCLUDED #include "inet.h" #include "inet_base.h" #include "inet_eth.h" +#include "osn_netif.h" +#include "osn_vlan.h" + typedef struct __inet_vlan inet_vlan_t; /* Subclass inet_eth */ @@ -43,22 +46,16 @@ struct __inet_vlan inet_eth_t eth; }; - char vlan_parent[C_IFNAME_LEN]; /* Parent interface name */ - int vlan_id; /* VLAN ID */ + char in_parent_ifname[C_IFNAME_LEN]; /* Parent interface name */ + osn_netif_t *in_parent_netif; /* Parent interface */ + char in_l2s_ifname[C_IFNAME_LEN]; /* Interface name used for l2switch config */ + int in_l2s_vlanid; /* Currently configure l2switch vlan id */ + osn_vlan_t *in_vlan; /* OSN VLAN object */ + int in_vlanid; /* VLAN ID */ }; -#if defined(CONFIG_INET_VLAN_LINUX) -extern inet_t *inet_vlan_new(const char *ifname); -extern bool inet_vlan_init(inet_vlan_t *self, const char *ifname); -#else -static inline inet_t *inet_vlan_new(const char *ifname) -{ - return NULL; -} -static inline bool inet_vlan_init(inet_vlan_t *self, const char *ifname) -{ - return false; -} -#endif +inet_t *inet_vlan_new(const char *ifname); +bool inet_vlan_init(inet_vlan_t *self, const char *ifname); +bool inet_vlan_fini(inet_vlan_t *self); #endif /* INET_VLAN_H_INCLUDED */ diff --git a/src/lib/inet/kconfig/Kconfig.libs b/src/lib/inet/kconfig/Kconfig.libs index a3783938..bb27cc29 100644 --- a/src/lib/inet/kconfig/Kconfig.libs +++ b/src/lib/inet/kconfig/Kconfig.libs @@ -45,18 +45,6 @@ menu "libinet Configuration" specific code should define inet_gre_new() function which returns a suitable interface object that implements a tunneling protocol. - config INET_VLAN_LINUX - bool "Linux VLAN interfaces" - depends on INET_ETH_LINUX - default y - help - Select to include generic Linux VLAN interface support. - - Applicable to most Linux platforms. If not selected, the - platform/device specific code should provide its own implementation. - - This option implements the inet_vlan_t class. - menuconfig INET_FW_ENABLED bool "Firewall" default y diff --git a/src/lib/inet/src/inet_base.c b/src/lib/inet/src/inet_base.c index a93cefc6..565839ee 100644 --- a/src/lib/inet/src/inet_base.c +++ b/src/lib/inet/src/inet_base.c @@ -405,11 +405,12 @@ bool inet_base_init(inet_base_t *self, const char *ifname) * Define the unit dependency tree structure */ self->in_units = - inet_unit_s(INET_BASE_IF_CREATE, + inet_unit(INET_BASE_IF_ENABLE, + inet_unit(INET_BASE_IF_CREATE, inet_unit(INET_BASE_FIREWALL, NULL), - inet_unit_s(INET_BASE_IF_EXISTS, + inet_unit(INET_BASE_IF_READY, inet_unit(INET_BASE_MTU, NULL), - inet_unit_s(INET_BASE_NETWORK, + inet_unit(INET_BASE_NETWORK, inet_unit_s(INET_BASE_SCHEME_NONE, NULL), inet_unit(INET_BASE_SCHEME_STATIC, inet_unit(INET_BASE_DHCP_SERVER, NULL), @@ -426,7 +427,8 @@ bool inet_base_init(inet_base_t *self, const char *ifname) inet_unit(INET_BASE_DHCP6_CLIENT, NULL), inet_unit(INET_BASE_UPNP, NULL), NULL), - NULL); + NULL), + NULL); if (self->in_units == NULL) { @@ -434,6 +436,11 @@ bool inet_base_init(inet_base_t *self, const char *ifname) goto error; } + /* By default always create the interface */ + inet_unit_start(self->in_units, INET_BASE_IF_CREATE); + /* Assume interface exists by default */ + inet_unit_start(self->in_units, INET_BASE_IF_READY); + static bool once = true; if (once) @@ -466,18 +473,23 @@ bool inet_base_init(inet_base_t *self, const char *ifname) } bool inet_base_dtor(inet_t *super) +{ + inet_base_t *self = CONTAINER_OF(super, inet_base_t, inet); + + return inet_base_fini(self); +} + +bool inet_base_fini(inet_base_t *self) { ds_tree_iter_t iter; int ii; bool retval = true; - inet_base_t *self = (inet_base_t *)super; - if (self->in_units != NULL) { - /* Stop the top service (INET_BASE_IF_CREATE) -- this will effectively shut down ALL services */ - inet_unit_stop(self->in_units, INET_BASE_IF_CREATE); + /* Stop the top service (INET_BASE_IF_ENABLE) -- this will effectively shut down ALL services */ + inet_unit_stop(self->in_units, INET_BASE_IF_ENABLE); if (!inet_commit(&self->inet)) { LOG(WARN, "inet_base: %s: Error shutting down services.", self->inet.in_ifname); @@ -710,7 +722,7 @@ bool inet_base_interface_enable(inet_t *super, bool enabled) LOG(INFO, "inet_base: %s: %s interface.", self->inet.in_ifname, enabled ? "Starting" : "Stopping"); - return inet_unit_enable(self->in_units, INET_BASE_IF_CREATE, enabled); + return inet_unit_enable(self->in_units, INET_BASE_IF_ENABLE, enabled); } /* @@ -1483,8 +1495,7 @@ bool inet_base_commit(inet_t *super) /* * Update various statuses when we finish committing the new configuration */ - self->in_state.in_interface_enabled = inet_unit_status(self->in_units, - INET_BASE_IF_CREATE); + self->in_state.in_interface_enabled = inet_unit_status(self->in_units, INET_BASE_IF_ENABLE); self->in_state.in_network_enabled = inet_unit_status(self->in_units, INET_BASE_NETWORK); self->in_state.in_nat_enabled = false; self->in_state.in_upnp_mode = UPNP_MODE_NONE; @@ -1535,7 +1546,16 @@ bool inet_base_service_commit( switch (srv) { - case INET_BASE_IF_EXISTS: + case INET_BASE_IF_ENABLE: + return true; + + case INET_BASE_IF_CREATE: + return true; + + case INET_BASE_IF_READY: + return true; + + case INET_BASE_NETWORK: return true; case INET_BASE_FIREWALL: @@ -1575,11 +1595,11 @@ bool inet_base_service_commit( return inet_base_dhcp6_server_commit(self, start); default: - LOG(INFO, "inet_base: %s: Ignoring service start/stop request: %s -> %d", + LOG(DEBUG, "inet_base: %s: Ignoring non-implemented service start/stop request: %s -> %d", self->inet.in_ifname, inet_base_service_str(srv), start); - break; + return true; } return false; diff --git a/src/lib/inet/src/inet_eth.c b/src/lib/inet/src/inet_eth.c index 1f677197..73dc2b68 100644 --- a/src/lib/inet/src/inet_eth.c +++ b/src/lib/inet/src/inet_eth.c @@ -44,13 +44,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* * =========================================================================== - * Inet Ethernet implementation for Linux + * Inet Ethernet implementation * =========================================================================== */ static bool inet_eth_dtor(inet_t *super); static osn_netif_status_fn_t inet_eth_netif_status_fn; static osn_ip_status_fn_t inet_eth_ip4_status_fn; -static void inet_eth_netif_async_fn(struct ev_loop *loop, ev_async *w, int revents); +static bool inet_eth_service_IF_READY(inet_eth_t *self, bool enable); +static bool inet_eth_network_start(inet_eth_t *self, bool enable); /* * =========================================================================== @@ -65,7 +66,7 @@ inet_t *inet_eth_new(const char *ifname) { inet_eth_t *self; - self = calloc(1, sizeof(*self)); + self = malloc(sizeof(*self)); if (self == NULL) { goto error; @@ -95,15 +96,12 @@ bool inet_eth_init(inet_eth_t *self, const char *ifname) } /* Interface existence will be detected, assume it doesn't exist for now */ - inet_unit_stop(self->base.in_units, INET_BASE_IF_EXISTS); + inet_unit_stop(self->base.in_units, INET_BASE_IF_READY); /* Override inet_t class methods */ self->inet.in_dtor_fn = inet_eth_dtor; self->base.in_service_commit_fn = inet_eth_service_commit; - ev_async_init(&self->in_netif_async, inet_eth_netif_async_fn); - ev_async_start(EV_DEFAULT, &self->in_netif_async); - /* * Initialize osn_netif_t -- L2 interface for ethernet-like interfaces */ @@ -111,7 +109,6 @@ bool inet_eth_init(inet_eth_t *self, const char *ifname) osn_netif_data_set(self->in_netif, self); osn_netif_status_notify(self->in_netif, inet_eth_netif_status_fn); - /* * Initialize osn_ip_t -- IPv4 interface configuration */ @@ -124,27 +121,32 @@ bool inet_eth_init(inet_eth_t *self, const char *ifname) bool inet_eth_dtor(inet_t *super) { - bool retval; - inet_eth_t *self = (void *)super; - /* Stop async status updater */ - ev_async_stop(EV_DEFAULT, &self->in_netif_async); + return inet_eth_fini(self); +} - retval = inet_base_dtor(super); +bool inet_eth_fini(inet_eth_t *self) +{ + bool retval = true; + + if (!inet_base_dtor(&self->inet)) + { + retval = false; + } /* Dispose of the osn_netif_t class */ if (self->in_netif != NULL && !osn_netif_del(self->in_netif)) { LOG(WARN, "inet_eth: %s: Error detected during deletion of osn_netif_t instance.", - super->in_ifname); + self->inet.in_ifname); retval = false; } if (self->in_ip != NULL && !osn_ip_del(self->in_ip)) { LOG(WARN, "inet_eth: %s: Error detected during deletion of osn_ip_t instance.", - super->in_ifname); + self->inet.in_ifname); retval = false; } @@ -157,24 +159,16 @@ bool inet_eth_dtor(inet_t *super) * Commit and service start & stop functions * =========================================================================== */ -bool inet_eth_interface_start(inet_eth_t *self, bool enable) + + +bool inet_eth_service_IF_READY(inet_eth_t *self, bool enable) { - /* If the interface has not been started yet, return */ - if (!enable) return true; + (void)enable; /* - * Just check if the interface exists -- report an error otherwise so no - * other services will be started. + * By default just bring the interface down */ - if (!self->base.in_state.in_interface_exists) - { - LOG(NOTICE, "inet_eth: %s: Interface does not exists. Stopping.", - self->inet.in_ifname); - - return false; - } - - return true; + return inet_eth_network_start(self, false); } /** @@ -401,8 +395,12 @@ bool inet_eth_service_commit(inet_base_t *super, enum inet_base_services srv, bo switch (srv) { - case INET_BASE_IF_CREATE: - return inet_eth_interface_start(self, enable); + case INET_BASE_IF_READY: + if (!inet_eth_service_IF_READY(self, enable)) + { + return false; + } + break; case INET_BASE_NETWORK: return inet_eth_network_start(self, enable); @@ -417,16 +415,11 @@ bool inet_eth_service_commit(inet_base_t *super, enum inet_base_services srv, bo return inet_eth_mtu_start(self, enable); default: - LOG(DEBUG, "inet_eth: %s: Delegating service %s %s to inet_base.", - self->inet.in_ifname, - inet_base_service_str(srv), - enable ? "start" : "stop"); - - /* Delegate everything else to inet_base() */ - return inet_base_service_commit(super, srv, enable); + break; } - return true; + /* Delegate the service handling to the parent class */ + return inet_base_service_commit(super, srv, enable); } /* @@ -456,7 +449,7 @@ void inet_eth_netif_status_fn(osn_netif_t *netif, struct osn_netif_status *statu inet_base_state_update(&self->base); - enabled = inet_unit_is_enabled(self->base.in_units, INET_BASE_IF_EXISTS); + enabled = inet_unit_is_enabled(self->base.in_units, INET_BASE_IF_READY); if (enabled != self->base.in_state.in_interface_exists) { if (self->base.in_state.in_interface_exists) @@ -476,17 +469,10 @@ void inet_eth_netif_status_fn(osn_netif_t *netif, struct osn_netif_status *statu */ inet_unit_enable( self->base.in_units, - INET_BASE_IF_EXISTS, + INET_BASE_IF_READY, self->base.in_state.in_interface_exists); - /* - * Since this function is called soon after a osn_netif_notify() call, it - * can happen that this function is called within a inet_commit() code path. - * - * If we want to stop an non-existing interface, schedule an async event - * to do a delayed inet_commit(). - */ - ev_async_send(EV_DEFAULT, &self->in_netif_async); + inet_commit(&self->inet); } } @@ -512,18 +498,3 @@ void inet_eth_ip4_status_fn(osn_ip_t *ip, struct osn_ip_status *status) inet_base_state_update(&self->base); } - -/* - * Asynchronously process some netif events. - * - * Specifically, handle the interface exists flag here. Since the original netif - * status handler can be called from inside a inet_commit(), defer processing - * of some events to the main event loop. - */ -void inet_eth_netif_async_fn(struct ev_loop *loop, ev_async *w, int revents) -{ - inet_eth_t *self = CONTAINER_OF(w, inet_eth_t, in_netif_async); - - inet_commit(&self->inet); -} - diff --git a/src/lib/inet/src/inet_pppoe.c b/src/lib/inet/src/inet_pppoe.c new file mode 100644 index 00000000..829b3143 --- /dev/null +++ b/src/lib/inet/src/inet_pppoe.c @@ -0,0 +1,372 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "log.h" +#include "util.h" + +#include "inet.h" +#include "inet_base.h" +#include "inet_pppoe.h" + +static bool inet_pppoe_parent_ifname_set(inet_t *super, const char *parent_ifname); +static bool inet_pppoe_service_commit(inet_base_t *super, enum inet_base_services srv, bool enable); +static bool inet_pppoe_service_IF_ENABLE(inet_pppoe_t *self, bool enable); +static bool inet_pppoe_service_IF_CREATE(inet_pppoe_t *self, bool enable); +static osn_pppoe_status_fn_t inet_pppoe_status_fn; +static osn_netif_status_fn_t inet_pppoe_netif_status_fn; +static bool inet_pppoe_credential_set(inet_t *self, const char *username, const char *password); + +/* + * Default inet_pppoe class constructor + */ +inet_t *inet_pppoe_new(const char *ifname) +{ + inet_pppoe_t *self; + + self = calloc(1, sizeof(*self)); + if (self == NULL) + { + LOG(ERR, "inet_pppoe: %s: Unable to allocate inet_pppoe object.", ifname); + return NULL; + } + + if (!inet_pppoe_init(self, ifname)) + { + LOG(ERR, "inet_pppoe: %s: Failed to initialize inet_pppoe instance.", ifname); + free(self); + return NULL; + } + + return &self->inet; +} + +/* + * Destructor, called by inet_del() + */ +bool inet_pppoe_dtor(inet_t *super) +{ + inet_pppoe_t *self = CONTAINER_OF(super, inet_pppoe_t, inet); + + return inet_pppoe_fini(self); +} + +/* + * inet_pppoe class initializer + */ +bool inet_pppoe_init(inet_pppoe_t *self, const char *ifname) +{ + memset(self, 0, sizeof(*self)); + + if (!inet_base_init(&self->base, ifname)) + { + LOG(ERR, "inet_pppoe: %s: Failed to instantiate inet_base class.", ifname); + return false; + } + + /* + * Override inet_t methods + */ + self->inet.in_dtor_fn = inet_pppoe_dtor; + self->inet.in_parent_ifname_set_fn = inet_pppoe_parent_ifname_set; + self->inet.in_credential_set_fn = inet_pppoe_credential_set; + + /* + * Override inet_base_t methods + */ + self->base.in_service_commit_fn = inet_pppoe_service_commit; + + /* + * The pppd daemon creates the interface only when there's a successful + * connection to the peer. But in order to run pppd, the parent interface + * must exists. + * + * To handle these cases, we use the following services: + * - INET_BASE_IF_ENABLE: starts monitoring the parent interface + * - INET_BASE_IF_CREATE: is enabled when the parent interface exists and + * starts the PPP daemon + * - INET_BASE_IF_READY: is enabled when the PPPoE interface is created + * by pppoe + * + * Disable all these services by default. + */ + inet_unit_stop(self->base.in_units, INET_BASE_IF_CREATE); + inet_unit_stop(self->base.in_units, INET_BASE_IF_READY); + + /* + * Start an instance of the PPPoE object right away by artificially + * triggering the IF_CREATE service + */ + inet_pppoe_service_IF_CREATE(self, false); + + return true; +} + +/** + * inet_pppoe class finalizer + */ +bool inet_pppoe_fini(inet_pppoe_t *self) +{ + bool retval = true; + + if (!inet_base_fini(&self->base)) + { + LOG(ERR, "inet_pppoe: %s: Error shutting down base class.", self->inet.in_ifname); + retval = false; + } + + if (self->in_parent_netif != NULL) + { + osn_netif_del(self->in_parent_netif); + retval = false; + } + + if (self->in_pppoe != NULL) + { + osn_pppoe_del(self->in_pppoe); + retval = false; + } + + return retval; +} + +bool inet_pppoe_service_commit(inet_base_t *super, enum inet_base_services srv, bool enable) +{ + bool retval; + + inet_pppoe_t *self = CONTAINER_OF(super, inet_pppoe_t, base); + + switch (srv) + { + case INET_BASE_IF_ENABLE: + retval = inet_pppoe_service_IF_ENABLE(self, enable); + break; + + case INET_BASE_IF_CREATE: + retval = inet_pppoe_service_IF_CREATE(self, enable); + break; + + default: + return inet_base_service_commit(super, srv, enable); + } + + return retval; +} + +bool inet_pppoe_service_IF_ENABLE(inet_pppoe_t *self, bool enable) +{ + /* + * Enable monitoring of the parent interface + */ + if (self->in_parent_netif != NULL) + { + osn_netif_del(self->in_parent_netif); + self->in_parent_netif = NULL; + } + + if (!enable) return true; + + if (self->in_parent_ifname[0] == '\0') + { + LOG(NOTICE, "inet_pppoe: %s: Parent interface not set.", self->inet.in_ifname); + return false; + } + + /* + * IF_CREATE will be enabled from the parent interface status monitor + */ + inet_unit_stop(self->base.in_units, INET_BASE_IF_CREATE); + + /* + * If the interface is enabled start monitoring the parent interface + */ + self->in_parent_netif = osn_netif_new(self->in_parent_ifname); + if (self->in_parent_netif == NULL) + { + LOG(ERR, "inet_pppoe: %s: Error creating parent interface %s OSN netif object.", + self->inet.in_ifname, self->in_parent_ifname); + return false; + } + + /* + * The osn_netif object is used only for monitoring the parent's interface status + */ + osn_netif_data_set(self->in_parent_netif, self); + osn_netif_status_notify(self->in_parent_netif, inet_pppoe_netif_status_fn); + + return true; +} + + +bool inet_pppoe_service_IF_CREATE(inet_pppoe_t *self, bool enable) +{ + /* + * Always recreate the PPPoE interface -- the osn_pppoe_t instance must + * be always active in order to support monitoring mode. + */ + if (self->in_pppoe != NULL) + { + osn_pppoe_del(self->in_pppoe); + } + + self->in_pppoe = osn_pppoe_new(self->inet.in_ifname); + if (self->in_pppoe == NULL) + { + LOG(ERR, "inet_pppoe: %s: Error creating PPPoE OSN object.", self->inet.in_ifname); + return false; + } + + /* Register status callbacks */ + osn_pppoe_data_set(self->in_pppoe, self); + osn_pppoe_status_notify(self->in_pppoe, inet_pppoe_status_fn); + + /* + * Set the configuration + */ + if (self->in_parent_ifname[0] != '\0') + { + osn_pppoe_parent_set(self->in_pppoe, self->in_parent_ifname); + } + + if (self->in_ppp_username[0] != '\0') + { + osn_pppoe_secret_set(self->in_pppoe, self->in_ppp_username, self->in_ppp_password); + } + + if (!enable) return true; + + if (!osn_pppoe_apply(self->in_pppoe)) + { + LOG(ERR, "inet_pppoe: %s: Error applying PPPoE configuration.", + self->inet.in_ifname); + return false; + } + + return true; +} + +bool inet_pppoe_parent_ifname_set(inet_t *super, const char *parent_ifname) +{ + inet_pppoe_t *self = CONTAINER_OF(super, inet_pppoe_t, inet); + + if (parent_ifname == NULL) + { + if (self->in_parent_ifname[0] == '\0') + { + return true; + } + + self->in_parent_ifname[0] = '\0'; + } + else if (strcmp(self->in_parent_ifname, parent_ifname) == 0) + { + return true; + } + else + { + STRSCPY(self->in_parent_ifname, parent_ifname); + } + + /* + * Restart the top-level service when the parent interface -- we essentially + * need to recreate the PPP link from scratch + */ + return inet_unit_restart(self->base.in_units, INET_BASE_IF_ENABLE, false); +} + +bool inet_pppoe_credential_set(inet_t *super, const char *username, const char *password) +{ + inet_pppoe_t *self = CONTAINER_OF(super, inet_pppoe_t, inet); + + if (username == NULL) username = ""; + if (password == NULL) password = ""; + + if (strcmp(self->in_ppp_username, username) == 0 && + strcmp(self->in_ppp_password, password) == 0) + { + return true; + } + + STRSCPY(self->in_ppp_username, username); + STRSCPY(self->in_ppp_password, password); + + /* Trigger PPP interface recreation */ + return inet_unit_restart(self->base.in_units, INET_BASE_IF_CREATE, false); +} + +void inet_pppoe_status_fn(osn_pppoe_t *pppoe, struct osn_pppoe_status *status) +{ + inet_pppoe_t *self = osn_pppoe_data_get(pppoe); + + self->base.in_state.in_assign_scheme = INET_ASSIGN_NONE; + self->base.in_state.in_bcaddr = OSN_IP_ADDR_INIT; + memset(&self->base.in_state.in_macaddr, 0, sizeof(self->base.in_state.in_macaddr)); + osn_ip_addr_from_str(&self->base.in_state.in_netmask, "255.255.255.255"); + + self->base.in_state.in_port_status = status->ps_carrier; + self->base.in_state.in_mtu = status->ps_mtu; + self->base.in_state.in_ipaddr = status->ps_local_ip; + self->base.in_state.in_gateway = status->ps_remote_ip; + + inet_base_state_update(&self->base); + + if (inet_unit_is_enabled(self->base.in_units, INET_BASE_IF_READY) != status->ps_exists) + { + inet_unit_enable(self->base.in_units, INET_BASE_IF_READY, status->ps_exists); + inet_commit(&self->inet); + } +} + +/* + * Check if the criteria for enabling the interface has been met and enable it. + * The criteria is as follows: + */ +void inet_pppoe_netif_status_fn(osn_netif_t *netif, struct osn_netif_status *status) +{ + inet_pppoe_t *self = osn_netif_data_get(netif); + + if (inet_unit_is_enabled(self->base.in_units, INET_BASE_IF_CREATE) == status->ns_exists) + { + return; + } + + if (status->ns_exists) + { + LOG(INFO, "inet_pppoe: %s: Parent interface %s exists, initiating PPPoE.", + self->inet.in_ifname, self->in_parent_ifname); + } + else + { + LOG(INFO, "inet_pppoe: %s: Parent interface %s ceased to exist, terminating PPPoE", + self->inet.in_ifname, self->in_parent_ifname); + } + + if (!inet_unit_enable(self->base.in_units, INET_BASE_IF_CREATE, status->ns_exists)) + { + LOG(ERR, "inet_pppoe: %s: Error starting PPPoE interface creation.", self->inet.in_ifname); + } + + inet_commit(&self->inet); +} diff --git a/src/lib/inet/src/inet_vif.c b/src/lib/inet/src/inet_vif.c index b547a52d..f2ab3c98 100644 --- a/src/lib/inet/src/inet_vif.c +++ b/src/lib/inet/src/inet_vif.c @@ -89,6 +89,12 @@ bool inet_vif_service_commit(inet_base_t *super, enum inet_base_services srv, bo switch (srv) { + /* + * In the parent's implementation (inet_eth) these two services are + * responsible for interface up/down sequences. We need to override them + * here as up/down of interfaces is handled by WM. + */ + case INET_BASE_IF_READY: case INET_BASE_NETWORK: break; diff --git a/src/lib/inet/src/inet_vlan.c b/src/lib/inet/src/inet_vlan.c new file mode 100644 index 00000000..6ce7a06b --- /dev/null +++ b/src/lib/inet/src/inet_vlan.c @@ -0,0 +1,372 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "execsh.h" +#include "log.h" +#include "osp_l2switch.h" +#include "util.h" + +#include "inet.h" +#include "inet_base.h" +#include "inet_vlan.h" + +static bool inet_vlan_vlanid_set(inet_t *super, int vlanid); +static bool inet_vlan_parent_ifname_set(inet_t *super, const char *ifname); +static bool inet_vlan_service_commit(inet_base_t *super, enum inet_base_services srv, bool enable); +static bool inet_vlan_service_IF_ENABLE(inet_vlan_t *self, bool enable); +static bool inet_vlan_service_IF_CREATE(inet_vlan_t *self, bool enable); +static osn_netif_status_fn_t inet_vlan_netif_status_fn; + +/* + * =========================================================================== + * Initialization + * =========================================================================== + */ +inet_t *inet_vlan_new(const char *ifname) +{ + inet_vlan_t *self = NULL; + + self = malloc(sizeof(*self)); + if (self == NULL) + { + goto error; + } + + if (!inet_vlan_init(self, ifname)) + { + LOG(ERR, "inet_vif: %s: Failed to initialize interface instance.", ifname); + goto error; + } + + return &self->inet; + +error: + if (self != NULL) + { + free(self); + } + + return NULL; +} + +/* + * Destructor, called by inet_del() + */ +bool inet_vlan_dtor(inet_t *super) +{ + inet_vlan_t *self = CONTAINER_OF(super, inet_vlan_t, inet); + + return inet_vlan_fini(self); +} + +bool inet_vlan_init(inet_vlan_t *self, const char *ifname) +{ + memset(self, 0, sizeof(*self)); + + /* Initialize the parent class -- inet_eth */ + if (!inet_eth_init(&self->eth, ifname)) + { + LOG(ERR, "inet_vlan: %s: Failed to instantiate class, parent class inet_eth_init() failed.", ifname); + return false; + } + + self->inet.in_vlanid_set_fn = inet_vlan_vlanid_set; + self->inet.in_parent_ifname_set_fn = inet_vlan_parent_ifname_set; + self->base.in_service_commit_fn = inet_vlan_service_commit; + + return true; +} + +bool inet_vlan_fini(inet_vlan_t *self) +{ + bool retval = true; + + if (!inet_eth_fini(&self->eth)) + { + LOG(ERR, "inet_vlan: Error in parent constructor."); + retval = false; + } + + if (self->in_parent_netif != NULL) + { + osn_netif_del(self->in_parent_netif); + } + + if (self->in_vlan != NULL) + { + osn_vlan_del(self->in_vlan); + } + + return retval; +} + +/* + * =========================================================================== + * VLAN class methods + * =========================================================================== + */ +bool inet_vlan_vlanid_set( + inet_t *super, + int vlanid) +{ + inet_vlan_t *self = CONTAINER_OF(super, inet_vlan_t, inet); + + if (vlanid == self->in_vlanid) return true; + + self->in_vlanid = vlanid; + + /* Interface must be recreated, therefore restart the IF_CREATE service */ + return inet_unit_restart(self->base.in_units, INET_BASE_IF_CREATE, false); +} + +bool inet_vlan_parent_ifname_set(inet_t *super, const char *parent_ifname) +{ + inet_vlan_t *self = CONTAINER_OF(super, inet_vlan_t, inet); + + if (strcmp(self->in_parent_ifname, parent_ifname) == 0) return true; + + if (strlen(parent_ifname) >= sizeof(self->in_parent_ifname)) + { + LOG(ERR, "inet_vlan: %s: Parent interface name too long: %s", + self->inet.in_ifname, parent_ifname); + return false; + } + + STRSCPY(self->in_parent_ifname, parent_ifname); + + return inet_unit_restart(self->base.in_units, INET_BASE_IF_CREATE, false); +} + +bool inet_vlan_service_commit( + inet_base_t *super, + enum inet_base_services srv, + bool enable) +{ + inet_vlan_t *self = CONTAINER_OF(super, inet_vlan_t, base); + + LOG(DEBUG, "inet_vlan: %s: Service %s -> %s.", + self->inet.in_ifname, + inet_base_service_str(srv), + enable ? "start" : "stop"); + + switch (srv) + { + case INET_BASE_IF_ENABLE: + if (!inet_vlan_service_IF_ENABLE(self, enable)) + { + return false; + } + break; + + case INET_BASE_IF_CREATE: + if (!inet_vlan_service_IF_CREATE(self, enable)) + { + return false; + } + break; + + default: + break; + } + + /* Delegate to the parent service */ + return inet_eth_service_commit(super, srv, enable); +} + +/* + * =========================================================================== + * Commit and start/stop services + * =========================================================================== + */ + +/* + * Implement the IF_ENABLE service which is responsible for parent monitoring + */ +bool inet_vlan_service_IF_ENABLE(inet_vlan_t *self, bool enable) +{ + (void)self; + (void)enable; + + if (self->in_l2s_ifname[0] != '\0') + { + osp_l2switch_del(self->in_l2s_ifname); + self->in_l2s_ifname[0] = '\0'; + self->in_l2s_vlanid = 0; + } + + if (self->in_parent_netif != NULL) + { + osn_netif_del(self->in_parent_netif); + self->in_parent_netif = NULL; + } + + if (!enable) return true; + + if (self->in_parent_ifname[0] == '\0') + { + LOG(NOTICE, "inet_vlan: %s: Parent interface not set.", self->inet.in_ifname); + return false; + } + + if (osp_l2switch_new(self->in_parent_ifname)) + { + /* Remember the interface name used by the l2switch API */ + STRSCPY_WARN(self->in_l2s_ifname, self->in_parent_ifname); + } + + /* + * IF_CREATE will be enabled from the parent interface status monitor + */ + inet_unit_stop(self->base.in_units, INET_BASE_IF_CREATE); + + self->in_parent_netif = osn_netif_new(self->in_parent_ifname); + if (self->in_parent_netif == NULL) + { + LOG(ERR, "inet_vlan: %s: Error creating parent interface %s OSN netif object.", + self->inet.in_ifname, self->in_parent_ifname); + return false; + } + + /* + * The osn_netif object is used only for monitoring the parent's interface status + */ + osn_netif_data_set(self->in_parent_netif, self); + osn_netif_status_notify(self->in_parent_netif, inet_vlan_netif_status_fn); + + return true; +} + +/* + * Implement the INET_UNIT_IF_CREATE service; this is responsible for + * creating/destroying the interface + */ +bool inet_vlan_service_IF_CREATE(inet_vlan_t *self, bool enable) +{ + if (self->in_l2s_ifname[0] != '\0' && self->in_l2s_vlanid != 0) + { + if (!osp_l2switch_vlan_unset(self->in_l2s_ifname, self->in_l2s_vlanid)) + { + LOG(WARN, "inet_vlan: %s: Error unsetting VLAN %d on interface %s.", + self->inet.in_ifname, self->in_l2s_vlanid, self->in_l2s_ifname); + } + self->in_l2s_vlanid = 0; + } + + if (self->in_vlan != NULL) + { + osn_vlan_del(self->in_vlan); + } + + self->in_vlan = osn_vlan_new(self->inet.in_ifname); + if (self->in_vlan == NULL) + { + LOG(ERR, "inet_vlan: %s: Error creating VLAN OSN object.", self->inet.in_ifname); + return false; + } + + /* + * Set the configuration + */ + if (self->in_parent_ifname[0] != '\0') + { + osn_vlan_parent_set(self->in_vlan, self->in_parent_ifname); + } + + if (self->in_vlanid >= 1 && self->in_vlanid <= 4095) + { + osn_vlan_vid_set(self->in_vlan, self->in_vlanid); + } + + if (!enable) return true; + + if (!osn_vlan_apply(self->in_vlan)) + { + LOG(ERR, "inet_vlan: %s: Error applying VLAN configuration.", + self->inet.in_ifname); + return false; + } + + if (self->in_l2s_ifname[0] == '\0') return true; + + if (!osp_l2switch_vlan_set(self->in_l2s_ifname, self->in_vlanid, true)) + { + LOG(ERR, "inet_vlan: %s: Error setting L2Switch VLAN tag for interface %s.", + self->inet.in_ifname, self->in_l2s_ifname); + return false; + } + + self->in_l2s_vlanid = self->in_vlanid; + + if (!osp_l2switch_apply(self->in_l2s_ifname)) + { + LOG(ERR, "inet_vlan: %s: Error applying L2Switch configuration for interface %s.", + self->inet.in_ifname, self->in_l2s_ifname); + return false; + } + + return true; +} + +/* + * Check if the criteria for enabling the interface has been met and enable it. + * The criteria is as follows: + */ +void inet_vlan_netif_status_fn(osn_netif_t *netif, struct osn_netif_status *status) +{ + inet_vlan_t *self = osn_netif_data_get(netif); + + if (inet_unit_is_enabled(self->base.in_units, INET_BASE_IF_CREATE) == status->ns_exists) + { + return; + } + + if (status->ns_exists) + { + LOG(INFO, "inet_vlan: %s: Parent interface %s exists, creating VLAN interface.", + self->inet.in_ifname, self->in_parent_ifname); + } + else + { + LOG(INFO, "inet_vlan: %s: Parent interface %s ceased to exist, deleting VLAN interface.", + self->inet.in_ifname, self->in_parent_ifname); + } + + if (!inet_unit_enable(self->base.in_units, INET_BASE_IF_CREATE, status->ns_exists)) + { + LOG(ERR, "inet_vlan: %s: Error starting VLAN interface creation.", self->inet.in_ifname); + } + + inet_commit(&self->inet); +} diff --git a/src/lib/inet/src/linux/inet_gretap.c b/src/lib/inet/src/linux/inet_gretap.c index 899608ea..ba99e7cf 100644 --- a/src/lib/inet/src/linux/inet_gretap.c +++ b/src/lib/inet/src/linux/inet_gretap.c @@ -183,7 +183,7 @@ bool inet_gretap_ip4tunnel_set( self->in_remote_addr = raddr; /* Interface must be recreated, therefore restart the top service */ - return inet_unit_restart(self->base.in_units, INET_BASE_IF_CREATE, false); + return inet_unit_restart(self->base.in_units, INET_BASE_IF_ENABLE, false); } /* @@ -262,7 +262,7 @@ bool inet_gretap_service_commit(inet_base_t *super, enum inet_base_services srv, switch (srv) { - case INET_BASE_IF_CREATE: + case INET_BASE_IF_ENABLE: return inet_gretap_interface_start(self, enable); default: diff --git a/src/lib/inet/src/linux/inet_vlan.c b/src/lib/inet/src/linux/inet_vlan.c deleted file mode 100644 index 463dc1c7..00000000 --- a/src/lib/inet/src/linux/inet_vlan.c +++ /dev/null @@ -1,249 +0,0 @@ -/* -Copyright (c) 2015, Plume Design Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the Plume Design Inc. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include -#include -#include -#include -#include - -#include - -#include "log.h" -#include "util.h" - -#include "inet_unit.h" - -#include "inet.h" -#include "inet_base.h" -#include "inet_vlan.h" - -#include "execsh.h" - - -static bool inet_vlan_set_impl( - inet_t *super, - const char *ifparent, - int vlanid); - -bool inet_vlan_service_commit_impl( - inet_base_t *super, - enum inet_base_services srv, - bool enable); - -bool inet_vlan_interface_start(inet_vlan_t *self, bool enable); - -/* - * =========================================================================== - * Initialization - * =========================================================================== - */ -inet_t *inet_vlan_new(const char *ifname) -{ - inet_vlan_t *self = NULL; - - self = malloc(sizeof(*self)); - if (self == NULL) - { - goto error; - } - - if (!inet_vlan_init(self, ifname)) - { - LOG(ERR, "inet_vif: %s: Failed to initialize interface instance.", ifname); - goto error; - } - - return (inet_t *)self; - -error: - if (self != NULL) free(self); - return NULL; -} - -bool inet_vlan_init(inet_vlan_t *self, const char *ifname) -{ - /* Initialize the parent class -- inet_eth */ - if (!inet_eth_init(&self->eth, ifname)) - { - LOG(ERR, "inet_vlan: %s: Failed to instantiate class, parent class inet_eth_init() failed.", ifname); - return false; - } - - self->inet.in_vlan_set_fn = inet_vlan_set_impl; - self->base.in_service_commit_fn = inet_vlan_service_commit_impl; - - return true; -} - -/* - * =========================================================================== - * VLAN class methods - * =========================================================================== - */ -bool inet_vlan_set_impl( - inet_t *super, - const char *ifparent, - int vlanid) -{ - inet_vlan_t *self = (void *)super; - - if ((strcmp(ifparent, self->vlan_parent) == 0) && - (self->vlan_id == vlanid)) - { - return true; - } - - if (strscpy(self->vlan_parent, ifparent, sizeof(self->vlan_parent)) < 0) - { - LOG(ERR, "inet_vlan: %s: Parent interface name too long: %s.", - self->inet.in_ifname, - ifparent); - - return false; - } - - self->vlan_id = vlanid; - - /* Interface must be recreated, therefore restart the top service */ - return inet_unit_restart(self->base.in_units, INET_BASE_IF_CREATE, false); -} - -bool inet_vlan_service_commit_impl( - inet_base_t *super, - enum inet_base_services srv, - bool enable) -{ - inet_vlan_t *self = (inet_vlan_t *)super; - - LOG(DEBUG, "inet_vlan: %s: Service %s -> %s.", - self->inet.in_ifname, - inet_base_service_str(srv), - enable ? "start" : "stop"); - - switch (srv) - { - case INET_BASE_IF_CREATE: - return inet_vlan_interface_start(self, enable); - - default: - /* Delegate everything else to the parent class inet_eth() */ - return inet_eth_service_commit(super, srv, enable); - } - - return true; -} - -/* - * =========================================================================== - * Commit and start/stop services - * =========================================================================== - */ - -/* - * Built-in shell script for creating VLAN interfaces - * - * $1 - interface name - * $2 - parent interface name - * $3 - vlanid - */ -static char vlan_create_interface[] = -_S( - if [ -e "/sys/class/net/$1" ]; - then - ip link del "$1"; - fi; - ip link add link "$2" name "$1" type vlan id "$3" -); - -/* - * Built-in shell script for deleting VLAN interfaces - * - * $1 - interface name, always return success - */ -static char vlan_delete_interface[] = -_S( - [ ! -e "/sys/class/net/$1" ] && exit 0; - ip link del "$1" -); - - -/* - * Implement the INET_UNIT_INTERFACE service; this is responsible for - * creating/destroying the interface - */ -bool inet_vlan_interface_start(inet_vlan_t *self, bool enable) -{ - int status; - char svlanid[11]; /* Number of characters to represent an int */ - - if (enable) - { - if (self->vlan_parent[0] == '\0') - { - LOG(INFO, "inet_vlan: %s: No parent interface was specified.", self->inet.in_ifname); - return false; - } - - if (self->vlan_id == 0) - { - LOG(INFO, "inet_vlan: %s: No vlan ID was specified.", self->inet.in_ifname); - return false; - } - - snprintf(svlanid, sizeof(svlanid), "%d", self->vlan_id); - - status = execsh_log( - LOG_SEVERITY_INFO, - vlan_create_interface, - self->inet.in_ifname, - self->vlan_parent, - svlanid); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - { - LOG(ERR, "inet_vlan: %s: Error creating VLAN interface.", self->inet.in_ifname); - return false; - } - - LOG(INFO, "inet_vlan: %s: VLAN interface was successfully created.", self->inet.in_ifname); - } - else - { - status = execsh_log( - LOG_SEVERITY_INFO, - vlan_delete_interface, - self->inet.in_ifname); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - { - LOG(ERR, "inet_vlan: %s: Error deleting VLAN interface.", self->inet.in_ifname); - } - - LOG(INFO, "inet_vlan: %s: VLAN interface was successfully deleted.", self->inet.in_ifname); - } - - return true; -} diff --git a/src/lib/inet/unit.mk b/src/lib/inet/unit.mk index 9a341c64..45c78968 100644 --- a/src/lib/inet/unit.mk +++ b/src/lib/inet/unit.mk @@ -32,10 +32,12 @@ UNIT_NAME := inet # Template type: UNIT_TYPE := LIB -UNIT_SRC := src/inet_base.c -UNIT_SRC += src/inet_unit.c UNIT_SRC += src/inet_eth.c +UNIT_SRC += src/inet_unit.c UNIT_SRC += src/inet_vif.c +UNIT_SRC += src/inet_base.c +UNIT_SRC += src/inet_pppoe.c +UNIT_SRC += src/inet_vlan.c UNIT_EXPORT_CFLAGS := -I$(UNIT_PATH)/inc UNIT_CFLAGS := $(UNIT_EXPORT_CFLAGS) @@ -51,6 +53,7 @@ UNIT_DEPS += src/lib/kconfig UNIT_DEPS += src/lib/read_until UNIT_DEPS += src/lib/schema UNIT_DEPS += src/lib/osn +UNIT_DEPS += src/lib/osp UNIT_DEPS += src/lib/synclist UNIT_DEPS += src/lib/log UNIT_DEPS_CFLAGS += src/lib/version @@ -60,7 +63,6 @@ UNIT_DEPS_CFLAGS += src/lib/version # $(eval $(if $(CONFIG_INET_GRETAP), UNIT_SRC += src/linux/inet_gretap.c)) -$(eval $(if $(CONFIG_INET_VLAN_LINUX), UNIT_SRC += src/linux/inet_vlan.c)) $(eval $(if $(CONFIG_INET_FW_NULL), UNIT_SRC += src/null/inet_fw_null.c)) $(eval $(if $(CONFIG_INET_FW_IPTABLES), UNIT_SRC += src/linux/inet_fw_iptables.c)) diff --git a/src/lib/intf_stats/inc/interface_stats.pb-c.h b/src/lib/intf_stats/inc/interface_stats.pb-c.h new file mode 100644 index 00000000..10f5967b --- /dev/null +++ b/src/lib/intf_stats/inc/interface_stats.pb-c.h @@ -0,0 +1,218 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: interface_stats.proto */ + +#ifndef PROTOBUF_C_interface_5fstats_2eproto__INCLUDED +#define PROTOBUF_C_interface_5fstats_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1000000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1002001 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct _Intf__Stats__ObservationPoint Intf__Stats__ObservationPoint; +typedef struct _Intf__Stats__IntfStats Intf__Stats__IntfStats; +typedef struct _Intf__Stats__ObservationWindow Intf__Stats__ObservationWindow; +typedef struct _Intf__Stats__IntfReport Intf__Stats__IntfReport; + + +/* --- enums --- */ + + +/* --- messages --- */ + +struct _Intf__Stats__ObservationPoint +{ + ProtobufCMessage base; + char *nodeid; + char *locationid; +}; +#define INTF__STATS__OBSERVATION_POINT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intf__stats__observation_point__descriptor) \ + , NULL, NULL } + + +struct _Intf__Stats__IntfStats +{ + ProtobufCMessage base; + char *ifname; + protobuf_c_boolean has_txbytes; + uint64_t txbytes; + protobuf_c_boolean has_rxbytes; + uint64_t rxbytes; + protobuf_c_boolean has_txpackets; + uint64_t txpackets; + protobuf_c_boolean has_rxpackets; + uint64_t rxpackets; + char *role; +}; +#define INTF__STATS__INTF_STATS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intf__stats__intf_stats__descriptor) \ + , NULL, 0,0, 0,0, 0,0, 0,0, NULL } + + +struct _Intf__Stats__ObservationWindow +{ + ProtobufCMessage base; + protobuf_c_boolean has_startedat; + uint64_t startedat; + protobuf_c_boolean has_endedat; + uint64_t endedat; + size_t n_intfstats; + Intf__Stats__IntfStats **intfstats; +}; +#define INTF__STATS__OBSERVATION_WINDOW__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intf__stats__observation_window__descriptor) \ + , 0,0, 0,0, 0,NULL } + + +struct _Intf__Stats__IntfReport +{ + ProtobufCMessage base; + protobuf_c_boolean has_reportedat; + uint64_t reportedat; + Intf__Stats__ObservationPoint *observationpoint; + size_t n_observationwindow; + Intf__Stats__ObservationWindow **observationwindow; +}; +#define INTF__STATS__INTF_REPORT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&intf__stats__intf_report__descriptor) \ + , 0,0, NULL, 0,NULL } + + +/* Intf__Stats__ObservationPoint methods */ +void intf__stats__observation_point__init + (Intf__Stats__ObservationPoint *message); +size_t intf__stats__observation_point__get_packed_size + (const Intf__Stats__ObservationPoint *message); +size_t intf__stats__observation_point__pack + (const Intf__Stats__ObservationPoint *message, + uint8_t *out); +size_t intf__stats__observation_point__pack_to_buffer + (const Intf__Stats__ObservationPoint *message, + ProtobufCBuffer *buffer); +Intf__Stats__ObservationPoint * + intf__stats__observation_point__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intf__stats__observation_point__free_unpacked + (Intf__Stats__ObservationPoint *message, + ProtobufCAllocator *allocator); +/* Intf__Stats__IntfStats methods */ +void intf__stats__intf_stats__init + (Intf__Stats__IntfStats *message); +size_t intf__stats__intf_stats__get_packed_size + (const Intf__Stats__IntfStats *message); +size_t intf__stats__intf_stats__pack + (const Intf__Stats__IntfStats *message, + uint8_t *out); +size_t intf__stats__intf_stats__pack_to_buffer + (const Intf__Stats__IntfStats *message, + ProtobufCBuffer *buffer); +Intf__Stats__IntfStats * + intf__stats__intf_stats__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intf__stats__intf_stats__free_unpacked + (Intf__Stats__IntfStats *message, + ProtobufCAllocator *allocator); +/* Intf__Stats__ObservationWindow methods */ +void intf__stats__observation_window__init + (Intf__Stats__ObservationWindow *message); +size_t intf__stats__observation_window__get_packed_size + (const Intf__Stats__ObservationWindow *message); +size_t intf__stats__observation_window__pack + (const Intf__Stats__ObservationWindow *message, + uint8_t *out); +size_t intf__stats__observation_window__pack_to_buffer + (const Intf__Stats__ObservationWindow *message, + ProtobufCBuffer *buffer); +Intf__Stats__ObservationWindow * + intf__stats__observation_window__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intf__stats__observation_window__free_unpacked + (Intf__Stats__ObservationWindow *message, + ProtobufCAllocator *allocator); +/* Intf__Stats__IntfReport methods */ +void intf__stats__intf_report__init + (Intf__Stats__IntfReport *message); +size_t intf__stats__intf_report__get_packed_size + (const Intf__Stats__IntfReport *message); +size_t intf__stats__intf_report__pack + (const Intf__Stats__IntfReport *message, + uint8_t *out); +size_t intf__stats__intf_report__pack_to_buffer + (const Intf__Stats__IntfReport *message, + ProtobufCBuffer *buffer); +Intf__Stats__IntfReport * + intf__stats__intf_report__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void intf__stats__intf_report__free_unpacked + (Intf__Stats__IntfReport *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*Intf__Stats__ObservationPoint_Closure) + (const Intf__Stats__ObservationPoint *message, + void *closure_data); +typedef void (*Intf__Stats__IntfStats_Closure) + (const Intf__Stats__IntfStats *message, + void *closure_data); +typedef void (*Intf__Stats__ObservationWindow_Closure) + (const Intf__Stats__ObservationWindow *message, + void *closure_data); +typedef void (*Intf__Stats__IntfReport_Closure) + (const Intf__Stats__IntfReport *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor intf__stats__observation_point__descriptor; +extern const ProtobufCMessageDescriptor intf__stats__intf_stats__descriptor; +extern const ProtobufCMessageDescriptor intf__stats__observation_window__descriptor; +extern const ProtobufCMessageDescriptor intf__stats__intf_report__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_interface_5fstats_2eproto__INCLUDED */ diff --git a/src/lib/intf_stats/inc/intf_stats.h b/src/lib/intf_stats/inc/intf_stats.h new file mode 100644 index 00000000..13f6f119 --- /dev/null +++ b/src/lib/intf_stats/inc/intf_stats.h @@ -0,0 +1,174 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef INTF_STATS_H_INCLUDED +#define INTF_STATS_H_INCLUDED + +#define IFNAME_LEN (17) +#define INTF_ROLE_LEN (64) +#define MAX_STRLEN (256) + +#include "ds.h" +#include "ds_dlist.h" +#include "interface_stats.pb-c.h" + +/** + * @brief container of information needed to set Intf Stats protobuf + * + * Stashes information relation to stats of an interface + */ +typedef struct +{ + char ifname[IFNAME_LEN]; + char role[INTF_ROLE_LEN]; + + uint64_t tx_bytes; + uint64_t rx_bytes; + + uint64_t tx_packets; + uint64_t rx_packets; + + ds_dlist_node_t node; +} intf_stats_t; + +/** + * @brief container of information needed to set an observation point protobuf. + * + * Stashes a pod's serial number and deployment location id. + */ +typedef struct +{ + char *node_id; + char *location_id; +} node_info_t; + +typedef ds_dlist_t intf_stats_list_t; + +/** + * @brief container of information needed to set a ObservationWindow protobuf + * + * Stashes information related to acitivity on interfaces within a time window + * The per-interface stats are presented as an double-link list of intf stat nodes + */ +typedef struct +{ + size_t window_idx; + uint64_t started_at; + uint64_t ended_at; + size_t num_intfs; + + intf_stats_list_t intf_list; +} intf_stats_window_t; + +/** + * @brief container to desribe each element of a Observation Window list + * + */ +typedef struct +{ + intf_stats_window_t entry; + ds_dlist_node_t node; +} intf_stats_window_list_t; + +/** + * @brief container of information needed to set a Intf Stats report protobuf + * + * Stashes information related to the activity of multiple interfaces over the + * course of mulitple time windows. + * The observation windows are presented as an double-linked list of Observation + * window nodes. + */ +typedef struct +{ + uint64_t reported_at; + node_info_t node_info; + size_t num_windows; + + intf_stats_list_t window_list; +} intf_stats_report_data_t; + +/** + * @brief Container of protobuf serialization output + * + * Contains the information related to a serialized protobuf + */ +typedef struct +{ + size_t len; /*base.descriptor == &intf__stats__observation_point__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t intf__stats__observation_point__pack + (const Intf__Stats__ObservationPoint *message, + uint8_t *out) +{ + assert(message->base.descriptor == &intf__stats__observation_point__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t intf__stats__observation_point__pack_to_buffer + (const Intf__Stats__ObservationPoint *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &intf__stats__observation_point__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Intf__Stats__ObservationPoint * + intf__stats__observation_point__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Intf__Stats__ObservationPoint *) + protobuf_c_message_unpack (&intf__stats__observation_point__descriptor, + allocator, len, data); +} +void intf__stats__observation_point__free_unpacked + (Intf__Stats__ObservationPoint *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &intf__stats__observation_point__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void intf__stats__intf_stats__init + (Intf__Stats__IntfStats *message) +{ + static Intf__Stats__IntfStats init_value = INTF__STATS__INTF_STATS__INIT; + *message = init_value; +} +size_t intf__stats__intf_stats__get_packed_size + (const Intf__Stats__IntfStats *message) +{ + assert(message->base.descriptor == &intf__stats__intf_stats__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t intf__stats__intf_stats__pack + (const Intf__Stats__IntfStats *message, + uint8_t *out) +{ + assert(message->base.descriptor == &intf__stats__intf_stats__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t intf__stats__intf_stats__pack_to_buffer + (const Intf__Stats__IntfStats *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &intf__stats__intf_stats__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Intf__Stats__IntfStats * + intf__stats__intf_stats__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Intf__Stats__IntfStats *) + protobuf_c_message_unpack (&intf__stats__intf_stats__descriptor, + allocator, len, data); +} +void intf__stats__intf_stats__free_unpacked + (Intf__Stats__IntfStats *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &intf__stats__intf_stats__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void intf__stats__observation_window__init + (Intf__Stats__ObservationWindow *message) +{ + static Intf__Stats__ObservationWindow init_value = INTF__STATS__OBSERVATION_WINDOW__INIT; + *message = init_value; +} +size_t intf__stats__observation_window__get_packed_size + (const Intf__Stats__ObservationWindow *message) +{ + assert(message->base.descriptor == &intf__stats__observation_window__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t intf__stats__observation_window__pack + (const Intf__Stats__ObservationWindow *message, + uint8_t *out) +{ + assert(message->base.descriptor == &intf__stats__observation_window__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t intf__stats__observation_window__pack_to_buffer + (const Intf__Stats__ObservationWindow *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &intf__stats__observation_window__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Intf__Stats__ObservationWindow * + intf__stats__observation_window__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Intf__Stats__ObservationWindow *) + protobuf_c_message_unpack (&intf__stats__observation_window__descriptor, + allocator, len, data); +} +void intf__stats__observation_window__free_unpacked + (Intf__Stats__ObservationWindow *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &intf__stats__observation_window__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void intf__stats__intf_report__init + (Intf__Stats__IntfReport *message) +{ + static Intf__Stats__IntfReport init_value = INTF__STATS__INTF_REPORT__INIT; + *message = init_value; +} +size_t intf__stats__intf_report__get_packed_size + (const Intf__Stats__IntfReport *message) +{ + assert(message->base.descriptor == &intf__stats__intf_report__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t intf__stats__intf_report__pack + (const Intf__Stats__IntfReport *message, + uint8_t *out) +{ + assert(message->base.descriptor == &intf__stats__intf_report__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t intf__stats__intf_report__pack_to_buffer + (const Intf__Stats__IntfReport *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &intf__stats__intf_report__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +Intf__Stats__IntfReport * + intf__stats__intf_report__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (Intf__Stats__IntfReport *) + protobuf_c_message_unpack (&intf__stats__intf_report__descriptor, + allocator, len, data); +} +void intf__stats__intf_report__free_unpacked + (Intf__Stats__IntfReport *message, + ProtobufCAllocator *allocator) +{ + assert(message->base.descriptor == &intf__stats__intf_report__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor intf__stats__observation_point__field_descriptors[2] = +{ + { + "nodeId", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Intf__Stats__ObservationPoint, nodeid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "locationId", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Intf__Stats__ObservationPoint, locationid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned intf__stats__observation_point__field_indices_by_name[] = { + 1, /* field[1] = locationId */ + 0, /* field[0] = nodeId */ +}; +static const ProtobufCIntRange intf__stats__observation_point__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor intf__stats__observation_point__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "intf.stats.ObservationPoint", + "ObservationPoint", + "Intf__Stats__ObservationPoint", + "intf.stats", + sizeof(Intf__Stats__ObservationPoint), + 2, + intf__stats__observation_point__field_descriptors, + intf__stats__observation_point__field_indices_by_name, + 1, intf__stats__observation_point__number_ranges, + (ProtobufCMessageInit) intf__stats__observation_point__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor intf__stats__intf_stats__field_descriptors[6] = +{ + { + "ifName", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Intf__Stats__IntfStats, ifname), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "txBytes", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__IntfStats, has_txbytes), + offsetof(Intf__Stats__IntfStats, txbytes), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "rxBytes", + 3, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__IntfStats, has_rxbytes), + offsetof(Intf__Stats__IntfStats, rxbytes), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "txPackets", + 4, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__IntfStats, has_txpackets), + offsetof(Intf__Stats__IntfStats, txpackets), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "rxPackets", + 5, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__IntfStats, has_rxpackets), + offsetof(Intf__Stats__IntfStats, rxpackets), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "role", + 6, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(Intf__Stats__IntfStats, role), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned intf__stats__intf_stats__field_indices_by_name[] = { + 0, /* field[0] = ifName */ + 5, /* field[5] = role */ + 2, /* field[2] = rxBytes */ + 4, /* field[4] = rxPackets */ + 1, /* field[1] = txBytes */ + 3, /* field[3] = txPackets */ +}; +static const ProtobufCIntRange intf__stats__intf_stats__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor intf__stats__intf_stats__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "intf.stats.IntfStats", + "IntfStats", + "Intf__Stats__IntfStats", + "intf.stats", + sizeof(Intf__Stats__IntfStats), + 6, + intf__stats__intf_stats__field_descriptors, + intf__stats__intf_stats__field_indices_by_name, + 1, intf__stats__intf_stats__number_ranges, + (ProtobufCMessageInit) intf__stats__intf_stats__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor intf__stats__observation_window__field_descriptors[3] = +{ + { + "startedAt", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__ObservationWindow, has_startedat), + offsetof(Intf__Stats__ObservationWindow, startedat), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "endedAt", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__ObservationWindow, has_endedat), + offsetof(Intf__Stats__ObservationWindow, endedat), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "intfStats", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(Intf__Stats__ObservationWindow, n_intfstats), + offsetof(Intf__Stats__ObservationWindow, intfstats), + &intf__stats__intf_stats__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned intf__stats__observation_window__field_indices_by_name[] = { + 1, /* field[1] = endedAt */ + 2, /* field[2] = intfStats */ + 0, /* field[0] = startedAt */ +}; +static const ProtobufCIntRange intf__stats__observation_window__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor intf__stats__observation_window__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "intf.stats.ObservationWindow", + "ObservationWindow", + "Intf__Stats__ObservationWindow", + "intf.stats", + sizeof(Intf__Stats__ObservationWindow), + 3, + intf__stats__observation_window__field_descriptors, + intf__stats__observation_window__field_indices_by_name, + 1, intf__stats__observation_window__number_ranges, + (ProtobufCMessageInit) intf__stats__observation_window__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor intf__stats__intf_report__field_descriptors[3] = +{ + { + "reportedAt", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(Intf__Stats__IntfReport, has_reportedat), + offsetof(Intf__Stats__IntfReport, reportedat), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "observationPoint", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(Intf__Stats__IntfReport, observationpoint), + &intf__stats__observation_point__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "observationWindow", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(Intf__Stats__IntfReport, n_observationwindow), + offsetof(Intf__Stats__IntfReport, observationwindow), + &intf__stats__observation_window__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned intf__stats__intf_report__field_indices_by_name[] = { + 1, /* field[1] = observationPoint */ + 2, /* field[2] = observationWindow */ + 0, /* field[0] = reportedAt */ +}; +static const ProtobufCIntRange intf__stats__intf_report__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor intf__stats__intf_report__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "intf.stats.IntfReport", + "IntfReport", + "Intf__Stats__IntfReport", + "intf.stats", + sizeof(Intf__Stats__IntfReport), + 3, + intf__stats__intf_report__field_descriptors, + intf__stats__intf_report__field_indices_by_name, + 1, intf__stats__intf_report__number_ranges, + (ProtobufCMessageInit) intf__stats__intf_report__init, + NULL,NULL,NULL /* reserved[123] */ +}; diff --git a/src/lib/intf_stats/src/intf_stats.c b/src/lib/intf_stats/src/intf_stats.c new file mode 100644 index 00000000..2013002e --- /dev/null +++ b/src/lib/intf_stats/src/intf_stats.c @@ -0,0 +1,632 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "os_types.h" +#include "os.h" +#include "log.h" +#include "ds.h" +#include "network_metadata.h" +#include "fcm.h" + +#include "ovsdb_sync.h" +#include "ovsdb_table.h" + +#include "interface_stats.pb-c.h" +#include "intf_stats.h" +#include "util.h" + +static ds_dlist_t cloud_intf_list; +static intf_stats_report_data_t report; +static int report_type; + +static ovsdb_update_monitor_t intf_stats_inet_config_ovsdb_update; + +/****************************************************************************** + * Helper Functions + ******************************************************************************/ + +static void +intf_stats_remove_all_intfs(ds_dlist_t *list) +{ + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + + for ( intf = ds_dlist_ifirst(&intf_iter, list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + ds_dlist_iremove(&intf_iter); + intf_stats_intf_free(intf); + intf = NULL; + } + + return; +} + +void +intf_stats_reset_report(intf_stats_report_data_t *report) +{ + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + ds_dlist_iter_t win_iter; + + /* Go through each window in the report, and free the + * allocated per-window intf_list + */ + for ( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + window_entry = &window->entry; + intf_stats_remove_all_intfs(&window_entry->intf_list); + } + + /* Free all the allocated windows in the report */ + for ( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + ds_dlist_iremove(&win_iter); + intf_stats_window_free(window); + window = NULL; + } + + /* node_info does not change. No need to reset it */ + report->reported_at = 0; + report->num_windows = 0; + + return; +} + +static void +intf_stats_dump_stats(ds_dlist_t *list) +{ + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + + for ( intf = ds_dlist_ifirst(&intf_iter, list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + LOGD("----------------------------------------------"); + LOGD("Intername : %-8s", intf->ifname); + LOGD("Role : %-8s", intf->role); + LOGD("tx_bytes : %10" PRIu64 "; rx_bytes : %10" PRIu64 "", intf->tx_bytes, intf->rx_bytes); + LOGD("tx_packets: %10" PRIu64 "; rx_packets: %10" PRIu64 "", intf->tx_packets, intf->rx_packets); + LOGD("----------------------------------------------"); + } + + return; +} + +void +intf_stats_dump_report(intf_stats_report_data_t *report) +{ + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + ds_dlist_iter_t win_iter; + + for ( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + window_entry = &window->entry; + LOGD("---- Window Index (%zu) ----", window_entry->window_idx); + LOGD("Started at : %10" PRIu64 "", window_entry->started_at); + LOGD("Ended at : %10" PRIu64 "", window_entry->ended_at); + + intf_stats_dump_stats(&window_entry->intf_list); + } + + return; +} + +static intf_stats_t * +intf_stats_find_by_ifname(ds_dlist_t *list, char *ifname) +{ + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + + for ( intf = ds_dlist_ifirst(&intf_iter, list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + if (!strcmp(intf->ifname, ifname)) return intf; + } + + return NULL; +} + +static int +intf_stats_get_num_intfs(void) +{ + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + int count = 0; + + for ( intf = ds_dlist_ifirst(&intf_iter, &cloud_intf_list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + count ++; + } + + LOGT("Total number of interfaces: '%d'", count); + return count; +} + +intf_stats_window_t * +intf_stats_get_current_window(intf_stats_report_data_t *report) +{ + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + size_t cur_window_idx = report->num_windows - 1; + ds_dlist_iter_t win_iter; + + for ( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + window_entry = &window->entry; + + if (window_entry->window_idx == cur_window_idx) return window_entry; + } + + return NULL; +} + +/******************************************************************************/ + +/* + * Parses the list of interfaces provided by the cloud via the + * "other_config", and builds the tree + */ +static void +intf_stats_get_intf_names(fcm_collect_plugin_t *collector) +{ + intf_stats_t *intf = NULL; + char *interfaces = NULL; + char *list, *tok; + + interfaces = collector->get_other_config(collector, "intf_list"); + if (!interfaces) + { + LOGE("Interface List received from cloud is empty"); + return; + } + + list = strdupa(interfaces); + while ((tok = strsep(&list, ",")) != NULL) + { + intf = intf_stats_intf_alloc(); + if (!intf) + { + LOGE("Interface memory allocation failed"); + return; + } + + STRSCPY(intf->ifname, tok); + + ds_dlist_insert_tail(&cloud_intf_list, intf); + LOGI("Monitoring interface '%s'", intf->ifname); + } + + return; +} + +static void +intf_stats_get_node_info(fcm_collect_plugin_t *collector) +{ + node_info_t *node_info = &report.node_info; + + node_info->node_id = collector->get_mqtt_hdr_node_id(); + node_info->location_id = collector->get_mqtt_hdr_loc_id(); + + return; +} + +static bool +intf_stats_get_role(intf_stats_t *intf) +{ + struct schema_Wifi_Inet_Config inet; + json_t *jrow, *where; + pjs_errmsg_t perr; + + where = ovsdb_where_simple(SCHEMA_COLUMN(Wifi_Inet_Config, if_name), intf->ifname); + jrow = ovsdb_sync_select_where(SCHEMA_TABLE(Wifi_Inet_Config), where); + + if (!schema_Wifi_Inet_Config_from_json(&inet, + json_array_get(jrow, 0), + false, + perr)) + { + LOGE("Unable to parse Wifi_Inet_Config column: '%s'", perr); + json_decref(jrow); + return false; + } + + if ((!inet.role_exists) || (strlen(inet.role) == 0)) + { + LOGN("Role not set for interface '%s', setting 'default'", intf->ifname); + STRSCPY(intf->role, "default"); + } + else + { + LOGI("Interface '%s' has role: '%s'", intf->ifname, inet.role); + STRSCPY(intf->role, inet.role); + } + + + json_decref(jrow); + return true; +} + +static void +intf_stats_get_intf_roles(void) +{ + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + + for ( intf = ds_dlist_ifirst(&intf_iter, &cloud_intf_list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + if (!intf_stats_get_role(intf)) + { + LOGN("Couldn't get role for interface '%s', setting 'default'", intf->ifname); + STRSCPY(intf->role, "default"); + } + } + + return; +} + +static void +intf_stats_inet_config_ovsdb_update_cb(ovsdb_update_monitor_t *self) +{ + struct schema_Wifi_Inet_Config inet; + pjs_errmsg_t perr; + + intf_stats_t *intf = NULL; + + switch (self->mon_type) + { + case OVSDB_UPDATE_NEW: + case OVSDB_UPDATE_MODIFY: + { + if (!schema_Wifi_Inet_Config_from_json(&inet, self->mon_json_new, false, perr)) + { + LOGE("Failed to parse new Wifi_Inet_Config row: %s", perr); + break; + } + + if (!inet.if_name_exists) break; + + intf = intf_stats_find_by_ifname(&cloud_intf_list, inet.if_name); + if (!intf) + { + /* This interface is not being tracked for stats */ + break; + } + + if ((!inet.role_exists) || (strlen(inet.role) == 0)) STRSCPY(intf->role, "default"); + else STRSCPY(intf->role, inet.role); + + break; + } + + case OVSDB_UPDATE_DEL: + default: + break; + } + + return; +} + +/******************************************************************************/ + +static void +intf_stats_calculate_stats(intf_stats_t *stats_old, struct rtnl_link_stats *stats_new) +{ + intf_stats_window_t *window_entry = NULL; + intf_stats_t *intf_entry = NULL; + ds_dlist_t *window_intf_list = NULL; + + window_entry = intf_stats_get_current_window(&report); + if (!window_entry) + { + LOGE("%s: Unable to get current active window", __func__); + return; + } + + window_intf_list = &window_entry->intf_list; + + intf_entry = intf_stats_find_by_ifname(window_intf_list, stats_old->ifname); + if (!intf_entry) + { + // Create an entry for this interface in the window + intf_entry = intf_stats_intf_alloc(); + if (!intf_entry) + { + LOGE("Unable to allocate interface entry"); + return; + } + + STRSCPY(intf_entry->ifname, stats_old->ifname); + STRSCPY(intf_entry->role, stats_old->role); + + ds_dlist_insert_tail(window_intf_list, intf_entry); + LOGD("Adding interface '%s' into window", intf_entry->ifname); + } + + if (report_type == FCM_RPT_FMT_DELTA) + { + // Calculate the stat deltas + intf_entry->tx_bytes = ((stats_new->tx_bytes) - (stats_old->tx_bytes)); + intf_entry->rx_bytes = ((stats_new->rx_bytes) - (stats_old->rx_bytes)); + intf_entry->tx_packets = ((stats_new->tx_packets) - (stats_old->tx_packets)); + intf_entry->rx_packets = ((stats_new->rx_packets) - (stats_old->rx_packets)); + } + else if (report_type == FCM_RPT_FMT_CUMUL) + { + intf_entry->tx_bytes = stats_new->tx_bytes; + intf_entry->rx_bytes = stats_new->rx_bytes; + intf_entry->tx_packets = stats_new->tx_packets; + intf_entry->rx_packets = stats_new->rx_packets; + } + + return; +} + +static void +intf_stats_fetch_stats(bool set_baseline) +{ + intf_stats_t *stats_old = NULL; + struct ifaddrs *ifaddr, *ifa; + int family, s; + char host[NI_MAXHOST]; + + if (getifaddrs(&ifaddr) == -1 ) + { + LOGE("getifaddrs failed, errno = '%d'", errno); + return; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == NULL) continue; + + stats_old = intf_stats_find_by_ifname(&cloud_intf_list, ifa->ifa_name); + if (!stats_old) + { + /* This interface is not being tracked for stats */ + continue; + } + + family = ifa->ifa_addr->sa_family; + LOGT("%-8s %s (%d)", ifa->ifa_name, + (family == AF_PACKET) ? "AF_PACKET" : + (family == AF_INET) ? "AF_INET" : + (family == AF_INET6) ? "AF_INET6" : "??", + family); + + if (family == AF_INET || family == AF_INET6) + { + s = getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + + if (s != 0) + { + LOGE("getnameinfo() failed: %s", gai_strerror(s)); + goto exit; + } + + LOGT("address: <%s>", host); + } + else if (family == AF_PACKET && ifa->ifa_data != NULL) + { + struct rtnl_link_stats *stats_new = ifa->ifa_data; + + LOGT("------Stats retreived from getifaddrs()-------"); + LOGT("tx_packets = %10u; rx_packets = %10u\n", + stats_new->tx_packets, stats_new->rx_packets); + LOGT("tx_bytes = %10u; rx_bytes = %10u\n", + stats_new->tx_bytes, stats_new->rx_bytes); + LOGT("----------------------------------------------"); + + /* Calculate the deltas */ + if (!set_baseline) + { + intf_stats_calculate_stats(stats_old, stats_new); + } + + /* Replace the old stats */ + stats_old->tx_bytes = stats_new->tx_bytes; + stats_old->rx_bytes = stats_new->rx_bytes; + stats_old->tx_packets = stats_new->tx_packets; + stats_old->rx_packets = stats_new->rx_packets; + } + } + +exit: + freeifaddrs(ifaddr); + + return; +} + +void +intf_stats_activate_window(intf_stats_report_data_t *report) +{ + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + intf_stats_list_t *intf_list = NULL; + + window = intf_stats_window_alloc(); + if (!window) + { + LOGE("Interface stats window allocation failed"); + return; + } + + window_entry = &window->entry; + + window_entry->window_idx = report->num_windows; + window_entry->started_at = time(NULL); + window_entry->num_intfs = intf_stats_get_num_intfs(); + + // Initialize the interface list + intf_list = &window_entry->intf_list; + ds_dlist_init(intf_list, intf_stats_t, node); + + LOGD("Adding a new observation window, idx: (%zu)", window_entry->window_idx); + ds_dlist_insert_tail(window_list, window); + + report->num_windows++; + + return; +} + +void +intf_stats_close_window(intf_stats_report_data_t *report) +{ + intf_stats_window_t *window_entry = NULL; + + window_entry = intf_stats_get_current_window(report); + if (!window_entry) + { + LOGE("%s: Unable to get current active window", __func__); + return; + } + + window_entry->ended_at = time(NULL); + LOGD("Closing window index:(%zu)", window_entry->window_idx); + + return; +} + +static void +intf_stats_send_report_cb(fcm_collect_plugin_t *collector) +{ + intf_stats_close_window(&report); + + intf_stats_fetch_stats(false); + intf_stats_dump_report(&report); + + LOGD("Sending Interface Stats Report"); + intf_stats_send_report(&report, collector->mqtt_topic); + + intf_stats_reset_report(&report); + + intf_stats_activate_window(&report); + + return; +} + +void +intf_stats_plugin_close_cb(fcm_collect_plugin_t *collector) +{ + LOGN("Interface Stats plugin shutting down"); + intf_stats_remove_all_intfs(&cloud_intf_list); + intf_stats_reset_report(&report); + + return; +} + +int intf_stats_plugin_init(fcm_collect_plugin_t *collector) +{ + LOGN("Interface Stats plugin intialization"); + + if (!collector) + { + LOGE("FCM collector instance is NULL"); + return 0; + } + + if (!ovsdb_update_monitor(&intf_stats_inet_config_ovsdb_update, + intf_stats_inet_config_ovsdb_update_cb, + SCHEMA_TABLE(Wifi_Inet_Config), + OMT_ALL)) + { + LOGE("Failed to monitor OVSDB table %s", SCHEMA_TABLE(Wifi_Inet_Config)); + return 0; + } + + collector->collect_periodic = NULL; + collector->send_report = intf_stats_send_report_cb; + collector->close_plugin = intf_stats_plugin_close_cb; + + /* Initialize the list to hold the interfaces provided by the cloud */ + ds_dlist_init(&cloud_intf_list, intf_stats_t, node); + intf_stats_get_intf_names(collector); + + /* Get the interface roles from Wifi_Inet_Config */ + intf_stats_get_intf_roles(); + + /* Initialize the report list */ + memset(&report, 0, sizeof(report)); + ds_dlist_init(&report.window_list, intf_stats_window_list_t, node); + report.num_windows = 0; + + intf_stats_get_node_info(collector); + + /* Get the report type */ + report_type = collector->fmt; + + /* Set the baseline stats for delta computation */ + intf_stats_fetch_stats(true); + + /* Activate the current observation window */ + intf_stats_activate_window(&report); + + return 0; +} diff --git a/src/lib/intf_stats/src/intf_stats_report.c b/src/lib/intf_stats/src/intf_stats_report.c new file mode 100644 index 00000000..a12b7c60 --- /dev/null +++ b/src/lib/intf_stats/src/intf_stats_report.c @@ -0,0 +1,831 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define __GNU_SOURCE +#include +#include +#include + +#include "log.h" +#include "qm_conn.h" +#include "intf_stats.h" + +/***************************************************************************** + * Helper functions + ****************************************************************************/ + +/** + * @brief duplicates a string and returns true if successful + * + * wrapper around string duplication when the source string might be + * a null pointer. + * + * @param src source string to duplicate. Might be NULL. + * @param dst destination string pointer + * @return true if duplicated, false otherwise + */ +static bool +intf_stats_str_duplicate(char *src, char **dst) +{ + if (src == NULL) + { + *dst = NULL; + return true; + } + + *dst = strndup(src, MAX_STRLEN); + if (*dst == NULL) + { + LOGE("%s: could not duplicate %s", __func__, src); + return false; + } + + return true; +} + +/***************************************************************************** + * Observation Point(Node Info) + ****************************************************************************/ + +/** + * @brief Allocates and sets an observation point protobuf. + * + * Uses the node info to fill a dynamically allocated + * observation point protobuf. + * The caller is responsible for freeing the returned pointer, + * @see intf_stats_free_pb_op() for this purpose. + * + * @param node info used to fill up the protobuf. + * @return a pointer to a observation point protobuf structure + */ +static Intf__Stats__ObservationPoint * +intf_stats_set_node_info(node_info_t *node) +{ + Intf__Stats__ObservationPoint *pb = NULL; + bool ret; + + // Allocate the protobuf structure + pb = calloc(1, sizeof(Intf__Stats__ObservationPoint)); + if (!pb) + { + LOGE("%s: ObservationPoint protobuf struct allocation" + " failed", __func__); + return NULL; + } + + /* Initialize the protobuf structure */ + intf__stats__observation_point__init(pb); + + /* Set the protobuf fields */ + ret = intf_stats_str_duplicate(node->node_id, &pb->nodeid); + if (!ret) goto err_free_pb; + + ret = intf_stats_str_duplicate(node->location_id, &pb->locationid); + if (!ret) goto err_free_node_id; + + return pb; + +err_free_node_id: + free(pb->nodeid); + +err_free_pb: + free(pb); + + return NULL; +} + +/** + * @brief Free an observation point protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb observation point structure to free + * @return none + */ +static void +intf_stats_free_pb_op(Intf__Stats__ObservationPoint *pb) +{ + if (!pb) return; + + free(pb->nodeid); + free(pb->locationid); + + free(pb); + + return; +} + +/** + * @brief Generates an observation point serialized protobuf + * + * Uses the information pointed by the info parameter to generate + * a serialized obervation point buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see free_packed_buffer() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to the serialized data. + */ +packed_buffer_t * +intf_stats_serialize_node_info(node_info_t *node) +{ + Intf__Stats__ObservationPoint *pb; + packed_buffer_t *serialized; + void *buf; + size_t len; + + if (!node) return NULL; + + /* Allocate serialization output container */ + serialized = calloc(1, sizeof(packed_buffer_t)); + if (!serialized) return NULL; + + /* Allocate and set observation point protobuf */ + pb = intf_stats_set_node_info(node); + if (!pb) goto err_free_serialized; + + /* Get serialization length */ + len = intf__stats__observation_point__get_packed_size(pb); + if (len == 0) goto err_free_pb; + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + if (!buf) goto err_free_pb; + + /* Serialize protobuf */ + serialized->len = intf__stats__observation_point__pack(pb, buf); + serialized->buf = buf; + + /* Free the protobuf structure */ + intf_stats_free_pb_op(pb); + + return serialized; + +err_free_pb: + intf_stats_free_pb_op(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + +/***************************************************************************** + * Interface associated stats + ****************************************************************************/ +/** + * @brief Allocates and sets a intf stats protobuf. + * + * Uses the intfstats info to fill a dynamically allocated + * intf stats protobuf. + * The caller is responsible for freeing the returned pointer, + * @see free_pb_stats() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to a Intf Stats protobuf structure + */ +static Intf__Stats__IntfStats * +intf_stats_set_intf_stats(intf_stats_t *intf) +{ + Intf__Stats__IntfStats *pb = NULL; + bool ret = false; + + // Allocate the protobuf structure + pb = calloc(1, sizeof(Intf__Stats__IntfStats)); + if (!pb) + { + LOGE("%s:intferface struct allocation failed", __func__); + return NULL; + } + + // Initialize the protobuf structure + intf__stats__intf_stats__init(pb); + + // Set the protobuf fields + ret = intf_stats_str_duplicate(intf->ifname, &pb->ifname); + if (!ret) goto err_free_pb; + + ret = intf_stats_str_duplicate(intf->role, &pb->role); + if (!ret) goto err_free_ifname; + + pb->txbytes = intf->tx_bytes; + pb->has_txbytes = true; + + pb->rxbytes = intf->rx_bytes; + pb->has_rxbytes = true; + + pb->txpackets = intf->tx_packets; + pb->has_txpackets = true; + + pb->rxpackets = intf->rx_packets; + pb->has_rxpackets = true; + + return pb; + +err_free_ifname: + free(pb->ifname); + +err_free_pb: + free(pb); + + return NULL; +} + +/** + * @brief Free a intf stats protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb flow stats structure to free + * @return none + */ +void +intf_stats_free_pb_intf_stats(Intf__Stats__IntfStats *pb) +{ + if (!pb) return; + + free(pb->ifname); + free(pb->role); + free(pb); +} + +/** + * @brief Generates a intf stats serialized protobuf. + * + * Uses the information pointed by the stats parameter to generate + * a serialized intf stats buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see intf_stats_free_packed_buffer() for this purpose. + * + * @param stats info used to fill up the protobuf. + * @return a pointer to the serialized data. + */ +packed_buffer_t * +intf_stats_serialize_intf_stats(intf_stats_t *intf) +{ + Intf__Stats__IntfStats *pb; + packed_buffer_t *serialized; + void *buf; + size_t len; + + if (!intf) return NULL; + + /* Allocate serialization output container */ + serialized = calloc(1, sizeof(packed_buffer_t)); + if (!serialized) return NULL; + + /* Allocate and set the intf stats container */ + pb = intf_stats_set_intf_stats(intf); + if (!pb) goto err_free_serialized; + + /* get serialization length */ + len = intf__stats__intf_stats__get_packed_size(pb); + if (len == 0) goto err_free_pb; + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + if (!buf) goto err_free_pb; + + /* Serialize protobuf */ + serialized->len = intf__stats__intf_stats__pack(pb, buf); + serialized->buf = buf; + + /* Free the protobuf structure */ + intf_stats_free_pb_intf_stats(pb); + + /* Return the serialized content */ + return serialized; + +err_free_pb: + intf_stats_free_pb_intf_stats(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + +/** + * @brief Allocates and sets table of intf stats protobufs + * + * Uses the window info to fill a dynamically allocated + * table of intf stats protobufs. + * The caller is responsible for freeing the returned pointer + * + * @param window info used to fill up the protobuf table + * @return a flow stats protobuf pointers table + */ +Intf__Stats__IntfStats ** +intf_stats_set_pb_intf_stats(intf_stats_window_t *window) +{ + Intf__Stats__IntfStats **intfs_pb_tbl = NULL; + size_t i, allocated = 0; + + ds_dlist_t *window_intf_list = &window->intf_list; + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + + if (!window) return NULL; + + if (window->num_intfs == 0) return NULL; + + // Allocate the array of interfaces + intfs_pb_tbl = calloc(window->num_intfs, sizeof(Intf__Stats__IntfStats *)); + if (!intfs_pb_tbl) + { + LOGE("%s:intfs_pb_tbl allocation failed", __func__); + return NULL; + } + + for ( intf = ds_dlist_ifirst(&intf_iter, window_intf_list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + if (allocated > window->num_intfs) + { + // This should never happen + LOGE("%s: Excess intfs being allocated", __func__); + goto err_free_pb_intfs; + } + + intfs_pb_tbl[allocated] = intf_stats_set_intf_stats(intf); + if (!intfs_pb_tbl[allocated]) goto err_free_pb_intfs; + + allocated++; + } + + return intfs_pb_tbl; + +err_free_pb_intfs: + for (i = 0; i < allocated; i++) + { + intf_stats_free_pb_intf_stats(intfs_pb_tbl[i]); + } + + free(intfs_pb_tbl); + + return NULL; +} + +/***************************************************************************** + * Observation Window + ****************************************************************************/ + +/** + * @brief Allocates and sets an observation window protobuf. + * + * Uses the stats info to fill a dynamically allocated + * observation window protobuf. + * The caller is responsible for freeing the returned pointer, + * @see intf_stats_free_pb_window() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to a observation point protobuf structure + */ +static Intf__Stats__ObservationWindow * +intf_stats_set_pb_window(intf_stats_window_t *window) +{ + Intf__Stats__ObservationWindow *pb = NULL; + + // Allocate protobuf + pb = calloc(1, sizeof(Intf__Stats__ObservationWindow)); + if (!pb) + { + LOGE("%s: observation window allocation failed", __func__); + return NULL; + } + + intf__stats__observation_window__init(pb); + + // Set protobuf fields + pb->startedat = window->started_at; + pb->has_startedat = true; + + pb->endedat = window->ended_at; + pb->has_endedat = true; + + // Accept window with no interfaces + if (window->num_intfs == 0) return pb; + + // Allocate interface stats container + pb->intfstats = intf_stats_set_pb_intf_stats(window); + if (!pb->intfstats) goto err_free_pb_window; + + pb->n_intfstats = window->num_intfs; + + return pb; + +err_free_pb_window: + free(pb); + + return NULL; +} + +/** + * @brief Free an observation window protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb flows window structure to free + * @return none + */ +void +intf_stats_free_pb_window(Intf__Stats__ObservationWindow *pb) +{ + size_t i; + + if (!pb) return; + + for (i = 0; i < pb->n_intfstats; i++) + { + intf_stats_free_pb_intf_stats(pb->intfstats[i]); + } + + free(pb->intfstats); + free(pb); + + return; +} + +/** + * @brief Generates an observation window serialized protobuf + * + * Uses the information pointed by the window parameter to generate + * a serialized obervation window buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see free_packed_buffer() for this purpose. + * + * @param window info used to fill up the protobuf. + * @return a pointer to the serialized data. + */ +packed_buffer_t * +intf_stats_serialize_window(intf_stats_window_t *window) +{ + Intf__Stats__ObservationWindow *pb; + packed_buffer_t *serialized; + void *buf; + size_t len; + + if (!window) return NULL; + + /* Allocate serialization output container */ + serialized = calloc(1, sizeof(packed_buffer_t)); + if (!serialized) return NULL; + + /* Allocate and set the intf stats protobuf */ + pb = intf_stats_set_pb_window(window); + if (!pb) goto err_free_serialized; + + /* Get serialization length */ + len = intf__stats__observation_window__get_packed_size(pb); + if (len == 0) goto err_free_pb; + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + if (!buf) goto err_free_pb; + + /* Serialize protobuf */ + serialized->len = intf__stats__observation_window__pack(pb, buf); + serialized->buf = buf; + + /* Free the protobuf structure */ + intf_stats_free_pb_window(pb); + + /* Return the serialized content */ + return serialized; + +err_free_pb: + intf_stats_free_pb_window(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + +/** + * @brief Allocates and sets table of observation window protobufs + * + * Uses the report info to fill a dynamically allocated + * table of observation window protobufs. + * The caller is responsible for freeing the returned pointer + * + * @param window info used to fill up the protobuf table + * @return a flow stats protobuf pointers table + */ +Intf__Stats__ObservationWindow ** +intf_stats_set_pb_windows(intf_stats_report_data_t *report) +{ + Intf__Stats__ObservationWindow **windows_pb_tbl; + size_t i, allocated = 0; + + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + ds_dlist_iter_t win_iter; + + if (!report) return NULL; + + if (report->num_windows == 0) return NULL; + + + windows_pb_tbl = calloc(report->num_windows, + sizeof(Intf__Stats__ObservationWindow *)); + if (!windows_pb_tbl) + { + LOGE("%s: windows_pb_tbl allocation failed", __func__); + return NULL; + } + + for ( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + if (allocated > report->num_windows) + { + // This should never happen + LOGE("%s: Excess windows being allocated", __func__); + goto err_free_pb_windows; + } + + window_entry = &window->entry; + + windows_pb_tbl[allocated] = intf_stats_set_pb_window(window_entry); + if (!windows_pb_tbl[allocated]) goto err_free_pb_windows; + + allocated++; + } + + return windows_pb_tbl; + +err_free_pb_windows: + for (i = 0; i < allocated; i++) + { + intf_stats_free_pb_window(windows_pb_tbl[i]); + } + + free(windows_pb_tbl); + + return NULL; +} + +/***************************************************************************** + * Intf Report + ****************************************************************************/ + +/** + * @brief Allocates and sets a flow report protobuf. + * + * Uses the report info to fill a dynamically allocated + * intf stat report protobuf. + * The caller is responsible for freeing the returned pointer, + * @see intf_stats_free_pb_report() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to a observation point protobuf structure + */ +static Intf__Stats__IntfReport * +intf_stats_set_pb_report(intf_stats_report_data_t *report) +{ + Intf__Stats__IntfReport *pb = NULL; + + pb = calloc(1, sizeof(Intf__Stats__IntfReport)); + if (!pb) + { + LOGE("%s: Intf__Stats__IntfReport alloc failed", __func__); + return NULL; + } + + // Initialize protobuf + intf__stats__intf_report__init(pb); + + // Set protobuf fields + pb->reportedat = report->reported_at; + pb->has_reportedat = true; + + pb->observationpoint = intf_stats_set_node_info(&report->node_info); + if (!pb->observationpoint) + { + LOGE("%s: set observationpoint failed", __func__); + goto err_free_pb_report; + } + + // Accept report with no windows + if (report->num_windows == 0) return pb; + + // Allocate observation windows container + pb->observationwindow = intf_stats_set_pb_windows(report); + if (!pb->observationwindow) + { + LOGE("%s: observation windows container allocation failed", __func__); + goto err_free_pb_op; + } + + pb->n_observationwindow = report->num_windows; + + return pb; + +err_free_pb_op: + intf_stats_free_pb_op(pb->observationpoint); + +err_free_pb_report: + free(pb); + + return NULL; +} + +/** + * @brief Free a flow report protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb flow report structure to free + * @return none + */ +static void +intf_stats_free_pb_report(Intf__Stats__IntfReport *pb) +{ + size_t i; + + if (!pb) return; + + intf_stats_free_pb_op(pb->observationpoint); + + for (i = 0; i < pb->n_observationwindow; i++) + { + intf_stats_free_pb_window(pb->observationwindow[i]); + } + + free(pb->observationwindow); + free(pb); + + return; +} + +/***************************************************************************** + * Report serialization + ****************************************************************************/ + +/** + * @brief Generates a flow report serialized protobuf + * + * Uses the information pointed by the report parameter to generate + * a serialized flow report buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see intf_stats_free_packed_buffer() for this purpose. + * + * @param node info used to fill up the protobuf. + * @return a pointer to the serialized data. + */ +packed_buffer_t * +intf_stats_serialize_report(intf_stats_report_data_t *report) +{ + Intf__Stats__IntfReport *pb = NULL; + packed_buffer_t *serialized = NULL; + void *buf; + size_t len; + + if (!report) + { + LOGE("%s: Intf Stats report is NULL", __func__); + return NULL; + } + + // Allocate serialization output structure + serialized = calloc(1,sizeof(packed_buffer_t)); + if (!serialized) + { + LOGE("%s: packed_buffer memory allocation failed", __func__); + return NULL; + } + + // Allocate and set the IntfReport protobuf + pb = intf_stats_set_pb_report(report); + if (!pb) + { + LOGE("%s: set_pb_report failed", __func__); + goto err_free_serialized; + } + + // Get serialized length + len = intf__stats__intf_report__get_packed_size(pb); + if (len == 0) + { + LOGE("%s: Failed to get serialized report len", __func__); + goto err_free_pb; + } + + // Allocate space for the serialized buffer + buf = malloc(len); + if (!buf) + { + LOGE("%s: failed to allocate serialized buf", __func__); + goto err_free_pb; + } + + serialized->len = intf__stats__intf_report__pack(pb, buf); + serialized->buf = buf; + + // Free the protobuf structure + intf_stats_free_pb_report(pb); + + return serialized; + +err_free_pb: + free(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + +/** + * @brief Frees the pointer to serialized data and container + * + * Frees the dynamically allocated pointer to serialized data (pb->buf) + * and the container (pb). + * + * @param pb a pointer to a serialized data container + * @return none + */ +void +intf_stats_free_packed_buffer(packed_buffer_t *pb) +{ + if (!pb) return; + + if (pb->buf) free(pb->buf); + + free(pb); +} + +/** + * @brief Prepares the serialized intf stat report and sends it over mqtt + * + * Converts the intf stat report information into serialized content, and + * sends it over MQTT. + * + * @param report a pointer to intf stats report container + * mqtt_topic a pointer to the mqtt topic + * @return result of mqtt send + */ +bool +intf_stats_send_report(intf_stats_report_data_t *report, char *mqtt_topic) +{ + packed_buffer_t *pb = NULL; + qm_response_t res; + bool ret = false; + + if (!report) + { + LOGE("%s: Intf Stats report is NULL", __func__); + return ret; + } + + if (!mqtt_topic) + { + LOGE("%s: MQTT topic is NULL", __func__); + return ret; + } + + report->reported_at = time(NULL); + + pb = intf_stats_serialize_report(report); + if (!pb) + { + LOGE("%s: Intf Stats report serialization failed", __func__); + return ret; + } + + ret = qm_conn_send_direct(QM_REQ_COMPRESS_IF_CFG, mqtt_topic, + pb->buf, pb->len, &res); + + // Free the serialized container + intf_stats_free_packed_buffer(pb); + + return ret; +} diff --git a/src/lib/intf_stats/tests/ut/test_intf_stats.c b/src/lib/intf_stats/tests/ut/test_intf_stats.c new file mode 100644 index 00000000..f1350a13 --- /dev/null +++ b/src/lib/intf_stats/tests/ut/test_intf_stats.c @@ -0,0 +1,867 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include + +#include "intf_stats.h" +#include "unity.h" +#include "log.h" +#include "target.h" +#include "qm_conn.h" + +struct intf_stats_test_mgr +{ + bool initialized; + bool has_qm; + char *f_name; + intf_stats_report_data_t report; +} g_test_mgr; + +/****************************************************************************** + * Helper functions +******************************************************************************/ + +/** + * @brief sends a serialized buffer over MQTT + * + * @param pb serialized buffer + */ +void +emit_report(packed_buffer_t *pb) +{ + qm_response_t res; + bool ret; + + if (!g_test_mgr.has_qm) return; + + ret = qm_conn_send_direct(QM_REQ_COMPRESS_IF_CFG, + "dev-ut_intf_stats", + pb->buf, pb->len, &res); + TEST_ASSERT_TRUE(ret); +} + +/** + * @brief writes the contents of a serialized buffer in a file + * + * @param pb serialized buffer to be written + * @param fpath target file path + * + * @return returns the number of bytes written + */ +static size_t +pb2file(packed_buffer_t *pb, char *fpath) +{ + FILE *f = fopen(fpath, "w"); + size_t nwrite = fwrite(pb->buf, 1, pb->len, f); + fclose(f); + + return nwrite; +} + +/** + * @brief reads the contents of a serialized buffer from a file + * + * @param fpath target file path + * @param pb serialized buffer to be filled + * + * @return returns the number of bytes written + */ +static size_t +file2pb(char *fpath, packed_buffer_t *pb) +{ + FILE *f = fopen(fpath, "rb"); + size_t nread = fread(pb->buf, 1, pb->len, f); + fclose(f); + + return nread; +} + +/*****************************************************************************/ + +void +test_Intf__Stats__Report(void) +{ + char *location_id = "intf_stats_test_location"; + char *node_id = "4C718002B3"; + + Intf__Stats__ObservationWindow **obs_pb_tbl; + Intf__Stats__ObservationWindow *obs_pb; + Intf__Stats__ObservationPoint *obs_p; + Intf__Stats__IntfStats **stats_pb_tbl; + Intf__Stats__IntfStats *stats_pb; + packed_buffer_t *serialized; + Intf__Stats__IntfReport *report; + + size_t num_intfs_w0; + size_t num_w; + size_t len; + void *buf; + + /* Allocate serialization output structure */ + serialized = calloc(sizeof(packed_buffer_t), 1); + TEST_ASSERT_NOT_NULL(serialized); + + /* Allocate protobuf */ + report = calloc(1, sizeof(*report)); + TEST_ASSERT_NOT_NULL(report); + + /* Initialize protobuf */ + intf__stats__intf_report__init(report); + + /* Set reported field */ + report->has_reportedat = true; + report->reportedat = 10; + + /* Set observation point */ + obs_p = calloc(1, sizeof(*obs_p)); + TEST_ASSERT_NOT_NULL(obs_p); + + /* Initialize the observation point */ + intf__stats__observation_point__init(obs_p); + + /* set observation point node id */ + obs_p->nodeid = strdup(node_id); + TEST_ASSERT_NOT_NULL(obs_p->nodeid); + + /* set observation point location id */ + obs_p->locationid = strdup(location_id); + TEST_ASSERT_NOT_NULL(obs_p->locationid); + + report->observationpoint = obs_p; + + /* Allocate the observation windows table, it will carry one entry */ + num_w = 1; + report->n_observationwindow = num_w; + obs_pb_tbl = calloc(num_w, sizeof(*obs_pb_tbl)); + TEST_ASSERT_NOT_NULL(obs_pb_tbl); + report->observationwindow = obs_pb_tbl; + + /* Allocate the unique entry of the observation windows table */ + obs_pb = calloc(1, sizeof(*obs_pb)); + TEST_ASSERT_NOT_NULL(obs_pb); + + /* Initialize the observation window */ + intf__stats__observation_window__init(obs_pb); + obs_pb_tbl[0] = obs_pb; + + /* Allocate the interface stats table with 2 entries */ + num_intfs_w0 = 2; + obs_pb->n_intfstats = num_intfs_w0; + stats_pb_tbl = calloc(num_intfs_w0, sizeof(*stats_pb_tbl)); + TEST_ASSERT_NOT_NULL(stats_pb_tbl); + + /* Assign the stats table to the observation window */ + obs_pb->intfstats = stats_pb_tbl; + + /* Allocate the first stats entry */ + stats_pb = calloc(1, sizeof(*stats_pb)); + TEST_ASSERT_NOT_NULL(stats_pb); + + /* Initialize the first stats entry */ + intf__stats__intf_stats__init(stats_pb); + + /* Fill up the first stats entry */ + stats_pb->ifname = strdup("test_intf1"); + stats_pb->role = strdup("uplink"); + TEST_ASSERT_NOT_NULL(stats_pb->ifname); + stats_pb->has_txbytes = true; + stats_pb->txbytes = 10; + stats_pb->has_rxbytes = true; + stats_pb->rxbytes = 20; + stats_pb->has_txpackets = true; + stats_pb->txpackets = 1; + stats_pb->has_rxpackets = true; + stats_pb->rxpackets = 1; + + /* Assign the first interface stats to the stats table */ + stats_pb_tbl[0] = stats_pb; + + /* Allocate the second stats entry */ + stats_pb = calloc(1, sizeof(*stats_pb)); + TEST_ASSERT_NOT_NULL(stats_pb); + + /* Initialize the second stats entry */ + intf__stats__intf_stats__init(stats_pb); + + /* Fill up the second stats entry */ + stats_pb->ifname = strdup("test_intf2"); + stats_pb->role = strdup("onboarding"); + TEST_ASSERT_NOT_NULL(stats_pb->ifname); + stats_pb->has_txbytes = true; + stats_pb->txbytes = 100; + stats_pb->has_rxbytes = true; + stats_pb->rxbytes = 200; + stats_pb->has_txpackets = true; + stats_pb->txpackets = 40; + stats_pb->has_rxpackets = true; + stats_pb->rxpackets = 50; + + /* Assign the first interface stats to the stats table */ + stats_pb_tbl[1] = stats_pb; + + /* Get serialization length */ + len = intf__stats__intf_report__get_packed_size(report); + TEST_ASSERT_TRUE(len != 0); + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + TEST_ASSERT_NOT_NULL(buf); + + serialized->len = intf__stats__intf_report__pack(report, buf); + serialized->buf = buf; + + emit_report(serialized); + + /* Free the serialized protobuf after it was emitted */ + intf_stats_free_packed_buffer(serialized); + + /* Free the protobuf resources */ + + /* free first stats resources */ + stats_pb = stats_pb_tbl[0]; + free(stats_pb->ifname); + free(stats_pb->role); + free(stats_pb); + + /* free second stats resources */ + stats_pb = stats_pb_tbl[1]; + free(stats_pb->ifname); + free(stats_pb->role); + free(stats_pb); + + /* free stats table */ + free(stats_pb_tbl); + + /* free the observation window */ + obs_pb = obs_pb_tbl[0]; + free(obs_pb); + + /* free the observation window table */ + free(obs_pb_tbl); + + /* free the observation point */ + free(obs_p->locationid); + free(obs_p->nodeid); + free(obs_p); + + /* free the report */ + free(report); +} + +/** + * @brief validates the contents of an observation point protobuf + * + * @param node expected node info + * @param op observation point protobuf to validate + */ +static void +validate_node_info(node_info_t *node, Intf__Stats__ObservationPoint *op) +{ + TEST_ASSERT_EQUAL_STRING(node->node_id, op->nodeid); + TEST_ASSERT_EQUAL_STRING(node->location_id, op->locationid); +} + +/** + * @brief validates the contents of a intf stat counters protobuf + * + * @param intf stats info + * @param intf stats protobuf to validate + */ +static void +validate_intf_stats(intf_stats_t *intf, Intf__Stats__IntfStats *stats_pb) +{ + TEST_ASSERT_EQUAL_STRING(intf->ifname, stats_pb->ifname); + TEST_ASSERT_EQUAL_STRING(intf->role , stats_pb->role ); + + TEST_ASSERT_EQUAL_UINT(intf->tx_bytes, stats_pb->txbytes); + TEST_ASSERT_EQUAL_UINT(intf->rx_bytes, stats_pb->rxbytes); + + TEST_ASSERT_EQUAL_UINT(intf->tx_packets, stats_pb->txpackets); + TEST_ASSERT_EQUAL_UINT(intf->rx_packets, stats_pb->rxpackets); +} + +/** + * @brief validates the contents of an observation window protobuf + * + * @param node expected node info + * @param op observation point protobuf to validate + */ +static void +validate_observation_window(intf_stats_window_t *window, Intf__Stats__ObservationWindow *window_pb) +{ + TEST_ASSERT_EQUAL_UINT(window->started_at, window_pb->startedat); + TEST_ASSERT_EQUAL_UINT(window->ended_at, window_pb->endedat); + TEST_ASSERT_EQUAL_UINT(window->num_intfs, window_pb->n_intfstats); +} + +/** + * @brief validates the contents of a flow windows protobuf + * + * @param node expected Intf Stat report info + * @param report_pb Intf Stat report protobuf to validate + */ +static void +validate_windows(intf_stats_report_data_t *report, Intf__Stats__IntfReport *report_pb) +{ + Intf__Stats__ObservationWindow **windows_pb_tbl; + Intf__Stats__ObservationWindow **window_pb; + + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + size_t i; + + ds_dlist_iter_t win_iter; + + TEST_ASSERT_EQUAL_UINT(report->num_windows, report_pb->n_observationwindow); + + windows_pb_tbl = intf_stats_set_pb_windows(report); + window_pb = windows_pb_tbl; + + for( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + window_entry = &window->entry; + + validate_observation_window(window_entry, *window_pb); + window_pb++; + } + + /* Free validation structure */ + for (i = 0; i < report->num_windows; i++) + { + intf_stats_free_pb_window(windows_pb_tbl[i]); + } + + free(windows_pb_tbl); +} + +/** + * @brief validates the contents of a flow report protobuf + * + * @param node expected flow report info + * @param report_pb flow report protobuf to validate + */ +static void +validate_report(intf_stats_report_data_t *report, Intf__Stats__IntfReport *report_pb) +{ + TEST_ASSERT_EQUAL_UINT(report->reported_at, report_pb->reportedat); + validate_node_info(&report->node_info, report_pb->observationpoint); + validate_windows(report, report_pb); +} + +/** + * @brief tests serialize_node_info() when passed a NULL pointer + */ +void test_serialize_node_info_null_ptr(void) +{ + node_info_t *node = NULL; + packed_buffer_t *pb; + + pb = intf_stats_serialize_node_info(node); + + /* Basic validation */ + TEST_ASSERT_NULL(pb); +} + +/** + * @brief tests serialize_node_info() when provided an empty node info + */ +void test_serialize_node_info_no_field_set(void) +{ + node_info_t node = { 0 }; + packed_buffer_t *pb; + + /* Serialize the observation point */ + pb = intf_stats_serialize_node_info(&node); + + /* Basic validation */ + TEST_ASSERT_NULL(pb); +} + +/** + * @brief tests serialize_node_info() when provided a valid node info + */ +void +test_serialize_node_info(void) +{ + node_info_t *node; + packed_buffer_t *pb; + packed_buffer_t pb_r = { 0 }; + uint8_t rbuf[4096]; + size_t nread = 0; + Intf__Stats__ObservationPoint *op; + + TEST_ASSERT_TRUE(g_test_mgr.initialized); + + node = &g_test_mgr.report.node_info; + + /* Serialize the observation point */ + pb = intf_stats_serialize_node_info(node); + + + /* Basic Validation */ + TEST_ASSERT_NOT_NULL(pb); + TEST_ASSERT_NOT_NULL(pb->buf); + + /* Save the serialized protobuf to file*/ + pb2file(pb, g_test_mgr.f_name); + + /* Free the serialied container */ + intf_stats_free_packed_buffer(pb); + + /* Read back the serialized protobuf */ + pb_r.buf = rbuf; + pb_r.len = sizeof(rbuf); + nread = file2pb(g_test_mgr.f_name, &pb_r); + op = intf__stats__observation_point__unpack(NULL, nread, rbuf); + + /* Validate the deserialized content */ + TEST_ASSERT_NOT_NULL(op); + validate_node_info(node, op); + + /* Free the deserialized content */ + intf__stats__observation_point__free_unpacked(op, NULL); +} + +/** + * @brief tests intf_stats_serialize_intf_stats() when provided with a valid stats pointer + */ +void +test_intf_stats(intf_stats_t *intf) +{ + packed_buffer_t *pb; + packed_buffer_t pb_r = { 0 }; + uint8_t rbuf[4096]; + size_t nread = 0; + Intf__Stats__IntfStats *stats_pb; + + /* Serialize the intf stats data */ + pb = intf_stats_serialize_intf_stats(intf); + + /* Basic validation */ + TEST_ASSERT_NOT_NULL(pb); + TEST_ASSERT_NOT_NULL(pb->buf); + + /* Save the serialized protobuf to file */ + pb2file(pb, g_test_mgr.f_name); + + /* Free the serialized container */ + intf_stats_free_packed_buffer(pb); + + /* Read back the serialized protobuf */ + pb_r.buf = rbuf; + pb_r.len = sizeof(rbuf); + nread = file2pb(g_test_mgr.f_name, &pb_r); + stats_pb = intf__stats__intf_stats__unpack(NULL, nread, rbuf); + + /* Validate the deserialzed content */ + TEST_ASSERT_NOT_NULL(stats_pb); + validate_intf_stats(intf, stats_pb); + + /* Free the deserialized content */ + intf__stats__intf_stats__free_unpacked(stats_pb, NULL); +} + +/** + * @brief tests intf_stats_serialize_intf_stats() when provided a valid single stats pointer + */ +void +test_serialize_intf_stats(void) +{ + intf_stats_report_data_t *report = &g_test_mgr.report; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + intf_stats_t *intf_entry = NULL; + + window = ds_dlist_head(&report->window_list); + TEST_ASSERT_NOT_NULL(window); + + window_entry = &window->entry; + TEST_ASSERT_NOT_NULL(window_entry); + + intf_entry = ds_dlist_head(&window_entry->intf_list); + TEST_ASSERT_NOT_NULL(intf_entry); + + test_intf_stats(intf_entry); +} + +/** + * @brief tests intf_stats_serialize_intf_stats() when provided a table of stats pointers + */ +void +test_set_intf_stats(void) +{ + intf_stats_report_data_t *report = &g_test_mgr.report; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + intf_stats_t *intf = NULL; + ds_dlist_iter_t intf_iter; + + Intf__Stats__IntfStats **stats_pb_tbl; + Intf__Stats__IntfStats **stats_pb; + + window = ds_dlist_head(&report->window_list); + TEST_ASSERT_NOT_NULL(window); + + window_entry = &window->entry; + TEST_ASSERT_NOT_NULL(window_entry); + + /* Generate the table of intf stat pointers */ + stats_pb_tbl = intf_stats_set_pb_intf_stats(window_entry); + + /* Basic validation */ + TEST_ASSERT_NOT_NULL(stats_pb_tbl); + + /* Validate each of the intf stats entries */ + stats_pb = stats_pb_tbl; + for ( intf = ds_dlist_ifirst(&intf_iter, &window_entry->intf_list); + intf != NULL; + intf = ds_dlist_inext(&intf_iter)) + { + /* Validate the intf stats protobuf content */ + validate_intf_stats(intf, *stats_pb); + + /* Free the current intf entry */ + intf_stats_free_pb_intf_stats(*stats_pb); + + stats_pb++; + } + + /* Free the pointers table */ + free(stats_pb_tbl); +} + +/** + * @brief tests intf_stats_serialize__window() when provided a single window pointer + */ +void +test_observation_window(intf_stats_window_t *window) +{ + packed_buffer_t *pb; + packed_buffer_t pb_r = { 0 }; + uint8_t rbuf[4096]; + size_t nread = 0; + Intf__Stats__ObservationWindow *window_pb; + + /* Serialize the observation window */ + pb = intf_stats_serialize_window(window); + + /* Basic validation */ + TEST_ASSERT_NOT_NULL(pb); + TEST_ASSERT_NOT_NULL(pb->buf); + + /* Save the serialized protobuf to file */ + pb2file(pb, g_test_mgr.f_name); + + /* Free the serialized container */ + intf_stats_free_packed_buffer(pb); + + /* Read back the serialized protobuf */ + pb_r.buf = rbuf; + pb_r.len = sizeof(rbuf); + nread = file2pb(g_test_mgr.f_name, &pb_r); + window_pb = intf__stats__observation_window__unpack(NULL, nread, rbuf); + + /* Validate the deserialized contetn */ + TEST_ASSERT_NOT_NULL(window_pb); + validate_observation_window(window, window_pb); + + /* Free the deserialized content */ + intf__stats__observation_window__free_unpacked(window_pb, NULL); +} + +/** + * @brief tests intf_stats_serialize_window() when provided a valid window pointer + */ +void +test_serialize_observation_windows(void) +{ + intf_stats_report_data_t *report = &g_test_mgr.report; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + window = ds_dlist_head(&report->window_list); + TEST_ASSERT_NOT_NULL(window); + + window_entry = &window->entry; + TEST_ASSERT_NOT_NULL(window_entry); + + test_observation_window(window_entry); +} + +/** + * @brief tests intf_stats_set_pb_windows() when provided a table of window pointers + */ +void +test_set_serialization_windows(void) +{ + intf_stats_report_data_t *report = &g_test_mgr.report; + Intf__Stats__ObservationWindow **windows_pb_tbl; + Intf__Stats__ObservationWindow **window_pb; + + intf_stats_list_t *window_list = &report->window_list; + intf_stats_window_list_t *window = NULL; + intf_stats_window_t *window_entry = NULL; + + ds_dlist_iter_t win_iter; + + /* Generate a table of observation window pointers */ + windows_pb_tbl = intf_stats_set_pb_windows(report); + + /* Basic validation */ + TEST_ASSERT_NOT_NULL(windows_pb_tbl); + + /* Validate each of the intf stats entries */ + window_pb = windows_pb_tbl; + + for( window = ds_dlist_ifirst(&win_iter, window_list); + window != NULL; + window = ds_dlist_inext(&win_iter)) + { + window_entry = &window->entry; + + /* Validate the observation window protobuf content */ + validate_observation_window(window_entry, *window_pb); + + /* Free the current window entry */ + intf_stats_free_pb_window(*window_pb); + + window_pb++; + } + + /* Free the windows pointers tbl */ + free(windows_pb_tbl); +} + +/** + * test_serialize_flow_report: tests + * intf_stats_serialize_flow_report() behavior when provided a valid node info + */ +void +test_serialize_report(void) +{ + intf_stats_report_data_t *report = &g_test_mgr.report; + packed_buffer_t *pb = NULL; + packed_buffer_t pb_r = { 0 }; + uint8_t rbuf[4096]; + size_t nread = 0; + Intf__Stats__IntfReport *pb_report = NULL; + + /* Validate the serialized content */ + pb = intf_stats_serialize_report(report); + +#ifndef ARCH_X86 + emit_report(pb); +#endif + + /* Basic validation */ + TEST_ASSERT_NOT_NULL(pb); + TEST_ASSERT_NOT_NULL(pb->buf); + + /* Save the serialized protobuf to file */ + pb2file(pb, g_test_mgr.f_name); + + /* Free the serialized container */ + intf_stats_free_packed_buffer(pb); + + /* Read back the serialized protobuf */ + pb_r.buf = rbuf; + pb_r.len = sizeof(rbuf); + nread = file2pb(g_test_mgr.f_name, &pb_r); + pb_report = intf__stats__intf_report__unpack(NULL, nread, rbuf); + TEST_ASSERT_NOT_NULL(pb_report); + + /* Validate the de-serialized content */ + validate_report(report, pb_report); + + /* Free the dserialized content */ + intf__stats__intf_report__free_unpacked(pb_report, NULL); + + return; +} + +/****************************************************************************** + * Test setup and tear down +******************************************************************************/ +static void +intf_stats_test_setup_window(intf_stats_window_t *window) +{ + intf_stats_t *intf_entry = NULL; + ds_dlist_t *window_intf_list = NULL; + + if (!window) return; + + window_intf_list = &window->intf_list; + + /* Allocate first interface */ + intf_entry = intf_stats_intf_alloc(); + TEST_ASSERT_NOT_NULL(intf_entry); + + /* Fill up the interface entry */ + STRSCPY(intf_entry->ifname, "test_intf1"); + STRSCPY(intf_entry->role, "uplink"); + + intf_entry->tx_bytes = 100; + intf_entry->rx_bytes = 200; + + intf_entry->tx_packets = 40; + intf_entry->rx_packets = 50; + + ds_dlist_insert_tail(window_intf_list, intf_entry); + + /* Allocate second interface */ + intf_entry = intf_stats_intf_alloc(); + TEST_ASSERT_NOT_NULL(intf_entry); + + /* Fill up the interface entry */ + STRSCPY(intf_entry->ifname, "test_intf2"); + STRSCPY(intf_entry->role, "onboarding"); + + intf_entry->tx_bytes = 300; + intf_entry->rx_bytes = 400; + + intf_entry->tx_packets = 10; + intf_entry->rx_packets = 20; + + ds_dlist_insert_tail(window_intf_list, intf_entry); + + /* Fill up the remaining window details */ + window->num_intfs = 2; + + return; +} + +/** + * @brief See unity documentation/exmaples + */ +void +setUp(void) +{ + intf_stats_report_data_t *report = NULL; + intf_stats_window_t *window_entry = NULL; + node_info_t *node_info = NULL; + + LOGI("%s: setting up the test", __func__); + + memset(&g_test_mgr, 0, sizeof(g_test_mgr)); + g_test_mgr.f_name = strdup("/tmp//serial_proto"); + TEST_ASSERT_NOT_NULL(g_test_mgr.f_name); + +#if !defined(ARCH_X86) + g_test_mgr.has_qm = true; +#else + g_test_mgr.has_qm = false; +#endif + + report = &g_test_mgr.report; + node_info = &report->node_info; + + /* Initilize the report */ + ds_dlist_init(&report->window_list, intf_stats_window_list_t, node); + report->num_windows = 0; + + /* Activate an observation window */ + intf_stats_activate_window(report); + window_entry = intf_stats_get_current_window(report); + if (!window_entry) + { + LOGE("%s: Unable to get current active window", __func__); + return; + } + + intf_stats_test_setup_window(window_entry); + intf_stats_close_window(report); + + report->reported_at = time(NULL); + + /* Set the node_info */ + node_info->node_id = strdup("1S6D808DB4"); + node_info->location_id = strdup("5bf5fc908a4eeb5622aa1217"); + TEST_ASSERT_NOT_NULL(node_info->node_id); + TEST_ASSERT_NOT_NULL(node_info->location_id); + + intf_stats_dump_report(report); + + g_test_mgr.initialized = true; +} + +/** + * @brief See unity documentation/exmaples + */ +void +tearDown(void) +{ + node_info_t *node_info = &g_test_mgr.report.node_info; + + LOGI("%s: tearing down the test", __func__); + + intf_stats_reset_report(&g_test_mgr.report); + if (g_test_mgr.f_name) free(g_test_mgr.f_name); + + free(node_info->node_id); + free(node_info->location_id); + + g_test_mgr.initialized = false; +} + +/*****************************************************************************/ +int +main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + target_log_open("TEST", LOG_OPEN_STDOUT); + log_severity_set(LOG_SEVERITY_DEBUG); + + UnityBegin("intf_stats"); + + /* Node Info(Observation Point) tests */ + RUN_TEST(test_serialize_node_info); + RUN_TEST(test_serialize_node_info_null_ptr); + RUN_TEST(test_serialize_node_info_no_field_set); + + /* Intf Stats tests */ + RUN_TEST(test_serialize_intf_stats); + RUN_TEST(test_set_intf_stats); + + /* Observation Window tests */ + RUN_TEST(test_serialize_observation_windows); + RUN_TEST(test_set_serialization_windows); + + /* Complete Intf Stat report test */ + RUN_TEST(test_serialize_report); + RUN_TEST(test_Intf__Stats__Report); + + return UNITY_END(); +} diff --git a/src/lib/intf_stats/tests/ut/unit.mk b/src/lib/intf_stats/tests/ut/unit.mk new file mode 100644 index 00000000..962f9096 --- /dev/null +++ b/src/lib/intf_stats/tests/ut/unit.mk @@ -0,0 +1,37 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_FCM),n,y) +UNIT_NAME := test_intf_stats + +UNIT_TYPE := TEST_BIN + +UNIT_SRC := test_intf_stats.c + +UNIT_DEPS := src/lib/intf_stats +UNIT_DEPS += src/lib/log +UNIT_DEPS += src/lib/common +UNIT_DEPS += src/lib/osa +UNIT_DEPS += src/qm/qm_conn +UNIT_DEPS += src/lib/unity diff --git a/src/lib/intf_stats/unit.mk b/src/lib/intf_stats/unit.mk new file mode 100644 index 00000000..f6741796 --- /dev/null +++ b/src/lib/intf_stats/unit.mk @@ -0,0 +1,56 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################### +# +# Interface stats library +# +############################################################################### +UNIT_NAME := fcm_intfstats + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_FCM),n,y) + +ifneq (,$(findstring clang,$(CC))) + UNIT_TYPE := LIB +else + UNIT_TYPE := SHLIB + UNIT_DIR := lib +endif + +UNIT_SRC := src/intf_stats.c +UNIT_SRC += src/interface_stats.pb-c.c +UNIT_SRC += src/intf_stats_report.c + +UNIT_CFLAGS := -I$(UNIT_PATH)/inc +UNIT_CFLAGS += -Isrc/fcm/inc +UNIT_CFLAGS += -I3rdparty/plume/src/lib/fcm_filter/inc +UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS) +UNIT_LDFLAGS := -lprotobuf-c + +UNIT_DEPS := src/lib/const +UNIT_DEPS += src/lib/log +UNIT_DEPS += src/qm/qm_conn +UNIT_DEPS += src/lib/ovsdb +UNIT_DEPS += src/lib/network_metadata +UNIT_DEPS += src/lib/fcm_filter diff --git a/src/lib/intf_stats/update_proto.sh b/src/lib/intf_stats/update_proto.sh new file mode 100755 index 00000000..d5817c11 --- /dev/null +++ b/src/lib/intf_stats/update_proto.sh @@ -0,0 +1,49 @@ + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################### +# update protobuf c files based on interface_stats protobuf description +############################################################################### + +RELDIR=$(basename $(dirname $PWD))/$(basename $PWD) +PROTOCC=`which protoc-c` + +if [ $RELDIR != "lib/intf_stats" ] +then + echo "Please cd to src/lib/intf_stats folder" + exit 1 +fi + +FNAME=interface_stats +$PROTOCC --c_out=. --proto_path=../../../interfaces ../../../interfaces/${FNAME}.proto +mv "${FNAME}.pb-c.c" src/ +mv "${FNAME}.pb-c.h" inc/ + +if [ $? -ne 0 ] +then + echo "Error generating protobuf c files" +else + echo "protobuf update successfully completed" +fi diff --git a/src/lib/ndp_parse/inc/ndp_parse.h b/src/lib/ndp_parse/inc/ndp_parse.h index 0ea155bc..97a95a86 100644 --- a/src/lib/ndp_parse/inc/ndp_parse.h +++ b/src/lib/ndp_parse/inc/ndp_parse.h @@ -73,6 +73,8 @@ struct ndp_session { struct fsm_session *session; bool initialized; + time_t timestamp; + uint64_t ttl; struct ndp_parser parser; ds_tree_node_t session_node; }; @@ -111,6 +113,24 @@ void ndp_plugin_exit(struct fsm_session *session); +/** + * @brief periodic routine + * + * @param session the fsm session keying the ndp session to process + */ +void +ndp_plugin_periodic(struct fsm_session *session); + + +/** + * @brief update routine + * + * @param session the fsm session keying the ndp session to update + */ +void +ndp_plugin_update(struct fsm_session *session); + + /** * @brief session packet processing entry point * diff --git a/src/lib/ndp_parse/src/ndp_parse.c b/src/lib/ndp_parse/src/ndp_parse.c index dfcbf524..16e6e1f3 100644 --- a/src/lib/ndp_parse/src/ndp_parse.c +++ b/src/lib/ndp_parse/src/ndp_parse.c @@ -24,6 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -129,6 +130,8 @@ ndp_plugin_init(struct fsm_session *session) } /* Set the fsm session */ + session->ops.update = ndp_plugin_update; + session->ops.periodic = ndp_plugin_periodic; session->ops.exit = ndp_plugin_exit; session->handler_ctxt = ndp_session; @@ -138,6 +141,8 @@ ndp_plugin_init(struct fsm_session *session) /* Wrap up the session initialization */ ndp_session->session = session; + ndp_session->timestamp = time(NULL); + ndp_plugin_update(session); ndp_session->initialized = true; LOGD("%s: added session %s", __func__, session->name); @@ -446,6 +451,7 @@ ndp_process_message(struct ndp_session *n_session) parser->entry.ifname = conf->if_name; parser->entry.source = FSM_NDP; + parser->entry.cache_valid_ts = n_session->timestamp; /* Record the IP mac mapping */ neigh_table_add(&parser->entry); @@ -528,3 +534,72 @@ ndp_delete_session(struct fsm_session *session) return; } + +#define FSM_NDP_CHECK_TTL (2*60) +/** + * @brief periodic routine + * + * @param session the fsm session keying the arp session to delete + */ +void +ndp_plugin_periodic(struct fsm_session *session) +{ + struct ndp_session *n_session; + struct ndp_cache *mgr; + ds_tree_t *sessions; + double cmp_clean; + time_t now; + + mgr = ndp_get_mgr(); + sessions = &mgr->fsm_sessions; + + n_session = ds_tree_find(sessions, session); + if (n_session == NULL) return; + + now = time(NULL); + cmp_clean = now - n_session->timestamp; + if (cmp_clean < FSM_NDP_CHECK_TTL) return; + + neigh_table_ttl_cleanup(n_session->ttl, OVSDB_NDP); + n_session->timestamp = now; +} + + +#define FSM_NDP_DEFAULT_TTL (36*60*60) +/** + * @brief update routine + * + * @param session the fsm session keying the ndp session to update + */ +void +ndp_plugin_update(struct fsm_session *session) +{ + struct ndp_session *n_session; + struct ndp_cache *mgr; + ds_tree_t *sessions; + unsigned long ttl; + char *str_ttl; + + mgr = ndp_get_mgr(); + sessions = &mgr->fsm_sessions; + + n_session = ds_tree_find(sessions, session); + if (n_session == NULL) return; + + /* set the default timer */ + n_session->ttl = FSM_NDP_DEFAULT_TTL; + str_ttl = session->ops.get_config(session, "ttl"); + if (str_ttl == NULL) goto log_settings; + + ttl = strtoul(str_ttl, NULL, 10); + if (ttl == 0 || ttl == ULONG_MAX) + { + LOGE("%s: conversion of %s failed: %d", __func__, str_ttl, errno); + goto log_settings; + } + n_session->ttl = (uint64_t)ttl; + +log_settings: + LOGI("%s: %s: setting neighbor entry ttl to %" PRIu64 " secs", __func__, + session->name, n_session->ttl); +} diff --git a/src/lib/ndp_parse/tests/futs/create_ndp_plugin.sh b/src/lib/ndp_parse/tests/futs/create_ndp_plugin.sh index 6cb095fe..51ca7f6f 100755 --- a/src/lib/ndp_parse/tests/futs/create_ndp_plugin.sh +++ b/src/lib/ndp_parse/tests/futs/create_ndp_plugin.sh @@ -156,6 +156,11 @@ location_id=$(get_location_id) node_id=$(get_node_id) mqtt_v="dev-test/${fsm_handler}/${node_id}/${location_id}" +n="$(ovsh s Flow_Service_Manager_Config -w handler==${fsm_handler} -r | wc -l)" +if [ ${n} -ne 0 ]; then + echo "${fsm_handler} already configured. Exiting" +fi + $(gen_tap_cmd) $(tap_up_cmd) $(gen_no_flood_cmd) diff --git a/src/lib/neigh_table/inc/neigh_table.h b/src/lib/neigh_table/inc/neigh_table.h index 95ff8ed1..2a6c606d 100644 --- a/src/lib/neigh_table/inc/neigh_table.h +++ b/src/lib/neigh_table/inc/neigh_table.h @@ -51,6 +51,7 @@ struct neighbour_entry char *ifname; int ifindex; uint32_t source; + time_t cache_valid_ts; uint8_t *ip_tbl; // for fast lookups int af_family; // for fast lookups ds_tree_node_t entry_node; // tree node structure @@ -174,6 +175,15 @@ neigh_table_cache_lookup(struct neighbour_entry *key); bool neigh_table_cache_update(struct neighbour_entry *entry); + +/** + * @brief remove old cache entres added by fsm + * + * @param ttl the cache entry time to live + */ +void neigh_table_ttl_cleanup(int64_t ttl, uint32_t source_mask); + + /** * @brief return the source based on its enum value * diff --git a/src/lib/neigh_table/src/neigh_src_ovsdb.c b/src/lib/neigh_table/src/neigh_src_ovsdb.c index d0e9a23c..f3d0878e 100644 --- a/src/lib/neigh_table/src/neigh_src_ovsdb.c +++ b/src/lib/neigh_table/src/neigh_src_ovsdb.c @@ -53,6 +53,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "json_util.h" ovsdb_table_t table_DHCP_leased_IP; +ovsdb_table_t table_IPv4_Neighbors; ovsdb_table_t table_IPv6_Neighbors; ovsdb_table_t table_Wifi_Inet_State; @@ -207,6 +208,121 @@ neigh_table_get_source(int source_enum) return NULL; } +static bool +neigh_entry_to_ipv4_neighbor_schema(struct neighbour_entry *key, + struct schema_IPv4_Neighbors *ipv4entry) +{ + struct sockaddr_storage *ipaddr; + os_macaddr_t *mac; + char *ifname; + char *source; + int err; + + if (!key || !ipv4entry) return false; + + ipaddr = key->ipaddr; + ifname = key->ifname; + mac = key->mac; + + if (!mac || !ipaddr || !ifname) return false; + + memset(ipv4entry, 0, sizeof(struct schema_IPv4_Neighbors)); + + snprintf(ipv4entry->hwaddr, + sizeof(ipv4entry->hwaddr), + PRI_os_macaddr_t, FMT_os_macaddr_pt(key->mac)); + + err = getnameinfo((struct sockaddr *)key->ipaddr, + sizeof(struct sockaddr_storage), + ipv4entry->address, sizeof(ipv4entry->address), + 0, 0, NI_NUMERICHOST); + if (err < 0) + { + LOGD("%s: Failed to get the ip: err[%s]", __func__, strerror(err)); + return false; + } + + memcpy(ipv4entry->if_name, key->ifname, sizeof(ipv4entry->if_name)); + + source = neigh_table_get_source(key->source); + if (source == NULL) return true; + + memcpy(ipv4entry->source, source, sizeof(ipv4entry->source)); + + return true; +} + +static bool +update_ipv4_neigh_in_ovsdb(struct neighbour_entry *key, bool remove) +{ + struct schema_IPv4_Neighbors ipv4entry; + pjs_errmsg_t perr; + json_t *cond; + json_t *where; + json_t *row; + bool ret; + + if (!key) return false; + + where = json_array(); + + ret = neigh_entry_to_ipv4_neighbor_schema(key, &ipv4entry); + if (!ret) + { + LOGD("%s: Couldn't convert neighbor_entry to schema.", __func__); + return false; + } + + cond = ovsdb_tran_cond_single("address", OFUNC_EQ, ipv4entry.address); + json_array_append_new(where, cond); + + if (key->ifname) + { + cond = ovsdb_tran_cond_single("if_name", OFUNC_EQ, key->ifname); + json_array_append_new(where, cond); + } + + if (strlen(ipv4entry.source) != 0) + { + cond = ovsdb_tran_cond_single("source", OFUNC_EQ, + (char *)ipv4entry.source); + json_array_append_new(where, cond); + } + + if (remove) + { + ret = ovsdb_sync_delete_where(SCHEMA_TABLE(IPv4_Neighbors), where); + if (!ret) + { + LOGE("%s: Failed to remove entry from IPv4_Neighbors.", __func__); + json_decref(where); + return false; + } + LOGD("%s: Removing ip[%s]-mac[%s] mapping in IPv4_Neighbors table." + ,__func__, ipv4entry.address, ipv4entry.hwaddr); + } + else + { + row = schema_IPv4_Neighbors_to_json(&ipv4entry, perr); + if (row == NULL) + { + LOGE("%s: Error convert schema structure to JSON.", __func__); + return false; + } + + ret = ovsdb_sync_upsert_where(SCHEMA_TABLE(IPv4_Neighbors), + where, row, NULL); + if (!ret) + { + LOGE("%s: Failed to upsert entry into IPv4_Neighbors.", __func__); + return false; + } + LOGD("%s: Adding ip[%s]-mac[%s] mapping in IPv4_Neighbors table." + ,__func__, ipv4entry.address, ipv4entry.hwaddr); + } + + return true; +} bool update_ip_in_ovsdb_table(struct neighbour_entry *key, bool remove) @@ -219,7 +335,10 @@ update_ip_in_ovsdb_table(struct neighbour_entry *key, bool remove) { rc = update_ipv6_neigh_in_ovsdb(key, remove); } - + else if (key->ipaddr->ss_family == AF_INET) + { + rc = update_ipv4_neigh_in_ovsdb(key, remove); + } return rc; } @@ -347,6 +466,132 @@ callback_DHCP_leased_IP(ovsdb_update_monitor_t *mon, } +/** + * @brief add or update a IPv4_Neighbor cache entry + * + * @param dhcp_lease the ovsdb IPv4_Neighbor info about the entry to add/update + * If any of the entry's field but its IP address is marked as changed, + * consider the entry as an update. + * Otherwise add the entry. + */ +static void +neigh_table_add_v4_entry(struct schema_IPv4_Neighbors *neigh) +{ + struct neighbour_entry entry; + os_macaddr_t mac; + uint8_t addr[4]; + bool update; + bool rc; + int ret; + + memset(&entry, 0, sizeof(entry)); + entry.af_family = AF_INET; + ret = inet_pton(entry.af_family, neigh->address, addr); + if (ret != 1) + { + LOGD("%s: conversion of %s failed", __func__, neigh->address); + return; + } + entry.ip_tbl = addr; + entry.source = OVSDB_ARP; + hwaddr_aton(neigh->hwaddr, mac.addr); + entry.mac = &mac; + + update = neigh->hwaddr_changed; + update |= neigh->source_changed; + update |= neigh->if_name_changed; + if (update) + { + rc = neigh_table_cache_update(&entry); + if (!rc) LOGD("%s: cache update failed", __func__); + } + else + { + rc = neigh_table_add_to_cache(&entry); + if (!rc) LOGD("%s: cache addition failed", __func__); + } +} + +/** + * @brief delete a IPv4_Neighbor cached entry + * + * @brief neigh the IPv4_Neighbor info about the entry to delete + */ +static void +neigh_table_delete_v4_entry(struct schema_IPv4_Neighbors *neigh) +{ + struct neighbour_entry entry; + os_macaddr_t mac; + uint8_t addr[4]; + int ret; + + memset(&entry, 0, sizeof(entry)); + entry.af_family = AF_INET; + ret = inet_pton(entry.af_family, neigh->address, addr); + if (ret != 1) + { + LOGD("%s: conversion of %s failed", __func__, neigh->address); + return; + } + entry.ip_tbl = addr; + entry.source = OVSDB_ARP; + hwaddr_aton(neigh->hwaddr, mac.addr); + entry.mac = &mac; + neigh_table_delete_from_cache(&entry); +} + +/** + * @brief add or update a IPv4_Neighbor cache entry + * + * @param old_rec the previous ovsdb IPv4_Neighbor info about the entry + * to add/update + * @param v4_neigh the ovsdb IPv4_Neighbor info about the entry to add/update + * + * If the entry's ip address is flagged as changed, remove the old entry + * and add a new one. + * Else update the entry. + */ +static void +neigh_table_update_v4_entry(struct schema_IPv4_Neighbors *old_rec, + struct schema_IPv4_Neighbors *v4_neigh) +{ + if (v4_neigh->address_changed) + { + /* Remove the old record from the cache */ + neigh_table_delete_v4_entry(old_rec); + } + + /* Add/update the new record */ + neigh_table_add_v4_entry(v4_neigh); +} + +/** + * @brief IPv4_Neighbors' event callbacks + */ +void +callback_IPv4_Neighbors(ovsdb_update_monitor_t *mon, + struct schema_IPv4_Neighbors *old_rec, + struct schema_IPv4_Neighbors *v4_neigh) +{ + if (mon->mon_type == OVSDB_UPDATE_NEW) + { + neigh_table_add_v4_entry(v4_neigh); + return; + } + + if (mon->mon_type == OVSDB_UPDATE_DEL) + { + neigh_table_delete_v4_entry(v4_neigh); + return; + } + + if (mon->mon_type == OVSDB_UPDATE_MODIFY) + { + neigh_table_update_v4_entry(old_rec, v4_neigh); + return; + } +} + /** * @brief add or update a IPv4_Neighbor cache entry * @@ -607,10 +852,12 @@ void neigh_src_init(void) { OVSDB_TABLE_INIT_NO_KEY(DHCP_leased_IP); + OVSDB_TABLE_INIT_NO_KEY(IPv4_Neighbors); OVSDB_TABLE_INIT_NO_KEY(IPv6_Neighbors); OVSDB_TABLE_INIT_NO_KEY(Wifi_Inet_State); OVSDB_TABLE_MONITOR(DHCP_leased_IP, false); + OVSDB_TABLE_MONITOR(IPv4_Neighbors, false); OVSDB_TABLE_MONITOR(IPv6_Neighbors, false); OVSDB_TABLE_MONITOR(Wifi_Inet_State, false); } diff --git a/src/lib/neigh_table/src/neigh_table.c b/src/lib/neigh_table/src/neigh_table.c index abfdf9f6..bc87759c 100644 --- a/src/lib/neigh_table/src/neigh_table.c +++ b/src/lib/neigh_table/src/neigh_table.c @@ -460,6 +460,10 @@ neigh_table_add_to_cache(struct neighbour_entry *to_add) { LOGD("%s: entry already exists", __func__); print_neigh_entry(entry); + + /* Refresh timestamp */ + entry->cache_valid_ts = to_add->cache_valid_ts; + return NULL; } @@ -482,6 +486,8 @@ neigh_table_add_to_cache(struct neighbour_entry *to_add) memcpy(entry->mac, to_add->mac, sizeof(os_macaddr_t)); entry->source = to_add->source; entry->ifindex = to_add->ifindex; + entry->cache_valid_ts = to_add->cache_valid_ts; + neigh_table_set_entry(entry); LOGT("%s: adding to cache: ", __func__); print_neigh_entry(entry); @@ -714,6 +720,53 @@ bool neigh_table_lookup(struct sockaddr_storage *ip_in, os_macaddr_t *mac_out) } +/** + * @brief remove old cache entres added by fsm + * + * @param ttl the cache entry time to live + */ +void neigh_table_ttl_cleanup(int64_t ttl, uint32_t source_mask) +{ + struct neigh_table_mgr *mgr = neigh_table_get_mgr(); + struct neighbour_entry *remove_node; + struct neighbour_entry *entry_node; + ds_tree_t *tree; + time_t now; + + if (!mgr->initialized) return; + + now = time(NULL); + tree = &mgr->neigh_table; + entry_node = ds_tree_head(tree); + while (entry_node != NULL) + { + /* We are only interested in the fsm added entries */ + if (!(entry_node->source & source_mask)) + { + entry_node = ds_tree_next(tree, entry_node); + continue; + } + + if ((now - entry_node->cache_valid_ts) < ttl) + { + entry_node = ds_tree_next(tree, entry_node); + continue; + } + + remove_node = entry_node; + + if (mgr->update_ovsdb_tables) + { + mgr->update_ovsdb_tables(remove_node, true); + } + + entry_node = ds_tree_next(tree, entry_node); + ds_tree_remove(tree, remove_node); + free_neigh_entry(remove_node); + } +} + + void print_neigh_entry(struct neighbour_entry *entry) { char ipstr[INET6_ADDRSTRLEN] = { 0 }; diff --git a/src/lib/neigh_table/ut/neigh_table/test_neigh_table.c b/src/lib/neigh_table/ut/neigh_table/test_neigh_table.c index 33737744..7642d234 100644 --- a/src/lib/neigh_table/ut/neigh_table/test_neigh_table.c +++ b/src/lib/neigh_table/ut/neigh_table/test_neigh_table.c @@ -77,6 +77,7 @@ struct test_mgr struct test_timers system; struct test_timers neigh_add; struct test_timers dhcp_timers; + struct test_timers ipv4_neighbors_timers; struct test_timers ipv6_neighbors_timers; struct test_timers intf_timers; int ut_ifindex; @@ -739,7 +740,7 @@ void test_lookup_neigh_entry_not_in_cache(void) /* Validate mac content */ cmp = memcmp(&mac_out, entry1->mac, sizeof(os_macaddr_t)); - TEST_ASSERT_TRUE(cmp != 0) + TEST_ASSERT_TRUE(cmp != 0); /* v6 tests */ // fill sockaddr @@ -754,7 +755,7 @@ void test_lookup_neigh_entry_not_in_cache(void) /* Validate mac content */ cmp = memcmp(&mac_out, entry3->mac, sizeof(os_macaddr_t)); - TEST_ASSERT_TRUE(cmp != 0) + TEST_ASSERT_TRUE(cmp != 0); LOGI("\n******************** %s: completed ****************", __func__); } @@ -1174,6 +1175,255 @@ void setup_lookup_dhcp_entry_in_ovsdb(void) } +void add_ipv4_neigh_entry_into_ovsdb_cb(EV_P_ ev_timer *w, int revents) +{ + struct neigh_table_mgr *mgr = neigh_table_get_mgr(); + char ipstr[INET_ADDRSTRLEN] = { 0 }; + struct neighbour_entry *entry; + char cmd[256]; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr->update_ovsdb_tables = update_ip_in_ovsdb_table; + + /* Add entry in ovsdb */ + entry = entry1; + neigh_table_set_entry(entry); + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, entry->ip_tbl, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh i IPv4_Neighbors address:=%s hwaddr:=" PRI_os_macaddr_t + " if_name:=%s", + ipstr, FMT_os_macaddr_pt(entry->mac), g_dummy_intf); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + g_test_mgr.expected_v4_source = OVSDB_ARP; + g_test_mgr.expected = true; + LOGI("\n***** %s: done\n", __func__); +} + +void delete_ipv4_neigh_entry_into_ovsdb_cb(EV_P_ ev_timer *w, int revents) +{ + struct neigh_table_mgr *mgr = neigh_table_get_mgr(); + char ipstr[INET_ADDRSTRLEN] = { 0 }; + struct neighbour_entry *entry; + char cmd[256]; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr->update_ovsdb_tables = update_ip_in_ovsdb_table; + + /* Add entry in ovsdb */ + entry = entry1; + neigh_table_set_entry(entry); + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, entry->ip_tbl, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh d IPv4_Neighbors -w address==%s", ipstr); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + g_test_mgr.expected = false; + LOGI("\n***** %s: done\n", __func__); +} + +void lookup_ipv4_neigh_in_cache_cb(EV_P_ ev_timer *w, int revents) +{ + uint32_t v4udstip = htonl(0x04030201); + struct sockaddr_storage key; + os_macaddr_t mac_out; + bool rc_lookup; + int cmp; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + // fill sockaddr + memset(&key, 0, sizeof(struct sockaddr_storage)); + util_populate_sockaddr(AF_INET, &v4udstip, &key); + /* Lookup the neighbour entry */ + rc_lookup = neigh_table_lookup(&key, &mac_out); + /* Validate lookup to the neighbour entry */ + TEST_ASSERT_TRUE(rc_lookup == g_test_mgr.expected); + + if (g_test_mgr.expected) + { + struct neighbour_entry *lookup; + struct neighbour_entry entry; + + /* Validate mac content */ + cmp = memcmp(&mac_out, entry1->mac, sizeof(os_macaddr_t)); + TEST_ASSERT_EQUAL_INT(cmp, 0); + + /* Retrieve cached entry to validate its source */ + memset(&entry, 0, sizeof(entry)); + entry.ipaddr = &key; + entry.mac = &mac_out; + entry.ifname = NULL; + entry.source = g_test_mgr.expected_v4_source; + neigh_table_set_entry(&entry); + lookup = neigh_table_cache_lookup(&entry); + TEST_ASSERT_NOT_NULL(lookup); + } + LOGI("\n***** %s: done\n", __func__); +} + +void update_ipv4_neigh_into_ovsdb_cb(EV_P_ ev_timer *w, int revents) +{ + os_macaddr_t mac = { { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66} }; + struct neigh_table_mgr *mgr = neigh_table_get_mgr(); + uint32_t v4udstip = htonl(0x04030210); + char ipstr[INET_ADDRSTRLEN] = { 0 }; + struct neighbour_entry *entry; + char cmd[256]; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr->update_ovsdb_tables = update_ip_in_ovsdb_table; + + /* Add entry1 in ovsdb */ + entry = entry1; + neigh_table_set_entry(entry); + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, entry->ip_tbl, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh i IPv4_Neighbors address:=%s hwaddr:=" PRI_os_macaddr_t + " if_name:=%s source:=UT", + ipstr, FMT_os_macaddr_pt(entry->mac), g_dummy_intf); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + /* Add entry2 in ovsdb */ + entry = entry2; + neigh_table_set_entry(entry); + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, entry->ip_tbl, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh i IPv4_Neighbors address:=%s hwaddr:=" PRI_os_macaddr_t + " if_name:=%s source:=UT", + ipstr, FMT_os_macaddr_pt(entry->mac), g_dummy_intf); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + /* Update entry1 mac address */ + entry = entry1; + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, entry->ip_tbl, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh u IPv4_Neighbors -w address==%s hwaddr:=" PRI_os_macaddr_t, + ipstr, FMT_os_macaddr_t(mac)); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + /* Update entry2 ip address */ + entry = entry2; + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, &v4udstip, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh u IPv4_Neighbors -w hwaddr==" PRI_os_macaddr_t + " address:=%s", + FMT_os_macaddr_pt(entry->mac), ipstr); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + g_test_mgr.expected_v4_source = OVSDB_ARP; + LOGI("\n***** %s: done\n", __func__); +} + +void lookup_ipv4_update_in_cache_cb(EV_P_ ev_timer *w, int revents) +{ + uint32_t v4udstip = htonl(0x04030210); + char ipstr[INET_ADDRSTRLEN] = { 0 }; + struct neighbour_entry *entry; + char cmd[256]; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + + /* Delete entry1 mac address */ + entry = entry1; + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, entry->ip_tbl, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh d IPv4_Neighbors -w address==%s", ipstr); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + /* Delete entry2 ip address */ + entry = entry2; + memset(cmd, 0, sizeof(cmd)); + inet_ntop(entry->af_family, &v4udstip, ipstr, sizeof(ipstr)); + snprintf(cmd, sizeof(cmd), + "ovsh d IPv4_Neighbors -w hwaddr==" PRI_os_macaddr_t, + FMT_os_macaddr_pt(entry->mac)); + LOGI("%s: cmd: %s", __func__, cmd); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + LOGI("\n***** %s: done\n", __func__); +} + +void setup_lookup_ipv4_neigh_entry_in_ovsdb(void) +{ + struct test_timers *t; + struct ev_loop *loop; + + if (!g_test_mgr.has_ovsdb) + { + LOGI("%s: ovsdb support, bypassing test", __func__); + return; + } + + t = &g_test_mgr.ipv4_neighbors_timers; + loop = g_test_mgr.loop; + + /* Arm the addition execution timer */ + ev_timer_init(&t->timeout_watcher_add, add_ipv4_neigh_entry_into_ovsdb_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_add.data = NULL; + + /* Arm the cache lookup execution timer validating the cache addition */ + ev_timer_init(&t->timeout_watcher_add_cache, lookup_ipv4_neigh_in_cache_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_add_cache.data = NULL; + + /* Arm the deletion execution timer */ + ev_timer_init(&t->timeout_watcher_delete, delete_ipv4_neigh_entry_into_ovsdb_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_delete.data = NULL; + + /* Arm the cache lookup execution timer validating the cache deletion */ + ev_timer_init(&t->timeout_watcher_delete_cache, lookup_ipv4_neigh_in_cache_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_delete_cache.data = NULL; + + /* Arm the update execution timer */ + ev_timer_init(&t->timeout_watcher_update, + update_ipv4_neigh_into_ovsdb_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_update.data = NULL; + + /* Arm the cache lookup execution timer validating the cache update */ + ev_timer_init(&t->timeout_watcher_update_cache, + lookup_ipv4_update_in_cache_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_update_cache.data = NULL; + + t->timeout_watcher_delete_cache.data = NULL; + ev_timer_start(loop, &t->timeout_watcher_add); + ev_timer_start(loop, &t->timeout_watcher_add_cache); + ev_timer_start(loop, &t->timeout_watcher_delete); + ev_timer_start(loop, &t->timeout_watcher_delete_cache); + ev_timer_start(loop, &t->timeout_watcher_update); + ev_timer_start(loop, &t->timeout_watcher_update_cache); +} + + void add_ipv6_neigh_entry_into_ovsdb_cb(EV_P_ ev_timer *w, int revents) { struct neigh_table_mgr *mgr = neigh_table_get_mgr(); @@ -1582,6 +1832,7 @@ void test_events(void) setup_lookup_neigh_entry_in_kernel(); setup_lookup_neigh_entry_in_ovsdb(); setup_lookup_dhcp_entry_in_ovsdb(); + setup_lookup_ipv4_neigh_entry_in_ovsdb(); setup_lookup_ipv6_neigh_entry_in_ovsdb(); setup_intf_events_test(); diff --git a/src/lib/network_metadata/inc/network_metadata_report.h b/src/lib/network_metadata/inc/network_metadata_report.h index d34a55f6..a66a4c10 100644 --- a/src/lib/network_metadata/inc/network_metadata_report.h +++ b/src/lib/network_metadata/inc/network_metadata_report.h @@ -120,6 +120,7 @@ struct net_md_aggregator bool (*collect_filter)(struct net_md_aggregator *, struct net_md_flow_key *); bool (*send_report)(struct net_md_aggregator *, char *); bool (*neigh_lookup)(struct sockaddr_storage *, os_macaddr_t *); + bool (*process)(struct net_md_stats_accumulator *); }; @@ -223,4 +224,41 @@ bool net_md_send_report(struct net_md_aggregator *aggr, char *mqtt_topic); */ size_t net_md_get_total_flows(struct net_md_aggregator *aggr); +/** + * @brief logs the content of an accumulator + * + * @param acc the accumulator to log + */ +void +net_md_log_acc(struct net_md_stats_accumulator *acc); + +/** + * @brief logs the content of an aggregator + * + * Walks the aggregator and logs its accumulators + * @param aggr the accumulator to log + */ +void +net_md_log_aggr(struct net_md_aggregator *aggr); + +/** + * @brief process an accumulator + * + * Process an accumulator + * @param aggr the accumulator to process + * @param acc the accumulator to process + */ +void +net_md_process_acc(struct net_md_aggregator *aggr, + struct net_md_stats_accumulator *acc); + +/** + * @brief logs the content of an accumulator + * + * Walks an aggregator and processes its accumulators + * @param acc the accumulator to process + */ +void +net_md_process_aggr(struct net_md_aggregator *aggr); + #endif /* NETWORK_METADATA_REPORT_H_INCLUDED */ diff --git a/src/lib/network_metadata/src/network_metadata_utils.c b/src/lib/network_metadata/src/network_metadata_utils.c index b134bee7..c86c7b13 100644 --- a/src/lib/network_metadata/src/network_metadata_utils.c +++ b/src/lib/network_metadata/src/network_metadata_utils.c @@ -1758,3 +1758,239 @@ net_md_update_aggr(struct net_md_aggregator *aggr, struct packed_buffer *pb) return; } + + +/** + * @brief logs the content of an accumulator + * + * @param acc the accumulator to log + */ +void +net_md_log_acc(struct net_md_stats_accumulator *acc) +{ + char src_ip[INET6_ADDRSTRLEN] = {0}; + char dst_ip[INET6_ADDRSTRLEN] = {0}; + struct net_md_flow_key *key; + struct flow_tags *ftag; + os_macaddr_t null_mac; + struct flow_key *fkey; + os_macaddr_t *smac; + os_macaddr_t *dmac; + size_t i, j; + int af; + + if (!LOG_SEVERITY_ENABLED(LOG_SEVERITY_DEBUG)) return; + + if (acc->key == NULL) return; + if (acc->fkey == NULL) return; + + fkey = acc->fkey; + key = acc->key; + + memset(&null_mac, 0, sizeof(null_mac)); + + if (key->ip_version == 4 || key->ip_version == 6) + { + af = key->ip_version == 4 ? AF_INET : AF_INET6; + inet_ntop(af, key->src_ip, src_ip, INET6_ADDRSTRLEN); + inet_ntop(af, key->dst_ip, dst_ip, INET6_ADDRSTRLEN); + } + + smac = (key->smac != NULL ? key->smac : &null_mac); + dmac = (key->dmac != NULL ? key->dmac : &null_mac); + + LOGD("%s: Printing key => net_md_flow_key :: fkey => flow_key", + __func__); + LOGD("------------"); + LOGD(" smac:" PRI_os_macaddr_lower_t \ + " dmac:" PRI_os_macaddr_lower_t \ + " vlanid: %d" \ + " ethertype: %d" \ + " ip_version: %d" \ + " src_ip: %s" \ + " dst_ip: %s" \ + " ipprotocol: %d" \ + " sport: %d" \ + " dport: %d", + FMT_os_macaddr_pt(smac), + FMT_os_macaddr_pt(dmac), + key->vlan_id, + key->ethertype, + key->ip_version, + src_ip, + dst_ip, + key->ipprotocol, + ntohs(key->sport), + ntohs(key->dport)); + if (key->fstart) LOGD(" Flow Starts"); + if (key->fend) LOGD(" Flow Ends"); + LOGD("------------"); + + LOGD(" smac: %s" \ + " dmac: %s" \ + " vlanid: %d" \ + " ethertype: %d" \ + " ip_version: %d"\ + " src_ip: %s" \ + " dst_ip: %s" \ + " protocol: %d" \ + " sport: %d" \ + " dport: %d", + fkey->smac, + fkey->dmac, + fkey->vlan_id, + fkey->ethertype, + fkey->ip_version, + fkey->src_ip ? fkey->src_ip : "None", + fkey->dst_ip ? fkey->dst_ip : "None", + fkey->protocol, + fkey->sport, + fkey->dport); + LOGD(" Flow State:"); + LOGD(" First observed : %s", ctime(&fkey->state.first_obs)); + LOGD(" Last observed : %s", ctime(&fkey->state.last_obs)); + if (fkey->state.fstart) LOGD(" Flow Starts"); + if (fkey->state.fend) LOGD(" Flow Ends"); + for (i = 0; i < fkey->num_tags; i++) + { + ftag = fkey->tags[i]; + LOGD(" vendor: %s" \ + " app_name: %s", + ftag->vendor, + ftag->app_name); + for (j = 0; j < ftag->nelems; j++) + { + LOGD(" tag[%zu]: %s", + j, ftag->tags[j]); + } + } + LOGD("%s: ------------", __func__); + LOGD("%s: counter packets_count = %" PRIu64 ", bytes_count = %" PRIu64, + __func__, + acc->counters.packets_count, + acc->counters.bytes_count); +} + + +/** + * @brief log the content of accumulators in the given tree + * + * @param aggr the aggregator containing the accumulators + * @tree the tree of accumulators + */ +void +net_md_log_accs(struct net_md_aggregator *aggr, + ds_tree_t *tree) +{ + struct net_md_flow *flow; + + flow = ds_tree_head(tree); + while (flow != NULL) + { + struct net_md_stats_accumulator *acc; + struct net_md_flow *next; + + acc = flow->tuple_stats; + net_md_log_acc(acc); + next = ds_tree_next(tree, flow); + flow = next; + } +} + + +void +net_md_log_eth_acc(struct net_md_aggregator *aggr, + struct net_md_eth_pair *eth_pair) +{ + struct net_md_stats_accumulator *eth_acc; + ds_tree_t *tree; + + eth_acc = eth_pair->mac_stats; + net_md_log_acc(eth_acc); + tree = ð_pair->ethertype_flows; + net_md_log_accs(aggr, tree); +} + + +/** + * @brief logs the content of an aggregator + * + * Walks the aggregator and logs its accumulators + * @param aggr the accumulator to log + */ +void net_md_log_aggr(struct net_md_aggregator *aggr) +{ + struct net_md_eth_pair *eth_pair; + + eth_pair = ds_tree_head(&aggr->eth_pairs); + while (eth_pair != NULL) + { + net_md_log_eth_acc(aggr, eth_pair); + net_md_log_accs(aggr, ð_pair->five_tuple_flows); + eth_pair = ds_tree_next(&aggr->eth_pairs, eth_pair); + } + + net_md_log_accs(aggr, &aggr->five_tuple_flows); +} + +/** + * @brief log the content of accumulators in the given tree + * + * @param aggr the aggregator containing the accumulators + * @tree the tree of accumulators + */ +void +net_md_process_accs(struct net_md_aggregator *aggr, + ds_tree_t *tree) +{ + struct net_md_flow *flow; + + flow = ds_tree_head(tree); + while (flow != NULL) + { + struct net_md_stats_accumulator *acc; + struct net_md_flow *next; + + acc = flow->tuple_stats; + aggr->process(acc); + next = ds_tree_next(tree, flow); + flow = next; + } +} + +void +net_md_process_eth_acc(struct net_md_aggregator *aggr, + struct net_md_eth_pair *eth_pair) +{ + struct net_md_stats_accumulator *eth_acc; + ds_tree_t *tree; + + eth_acc = eth_pair->mac_stats; + aggr->process(eth_acc); + tree = ð_pair->ethertype_flows; + net_md_process_accs(aggr, tree); +} + + +/** + * @brief process an accumulator + * + * Process an accumulator + * @param acc the accumulator to process + */ +void net_md_process_aggr(struct net_md_aggregator *aggr) +{ + struct net_md_eth_pair *eth_pair; + + if (aggr->process == NULL) return; + + eth_pair = ds_tree_head(&aggr->eth_pairs); + while (eth_pair != NULL) + { + net_md_process_eth_acc(aggr, eth_pair); + net_md_process_accs(aggr, ð_pair->five_tuple_flows); + eth_pair = ds_tree_next(&aggr->eth_pairs, eth_pair); + } + + net_md_process_accs(aggr, &aggr->five_tuple_flows); +} diff --git a/src/lib/network_metadata/ut/test_network_metadata_report.c b/src/lib/network_metadata/ut/test_network_metadata_report.c index 632d216f..78eaed71 100644 --- a/src/lib/network_metadata/ut/test_network_metadata_report.c +++ b/src/lib/network_metadata/ut/test_network_metadata_report.c @@ -1391,7 +1391,7 @@ test_flow_tags_one_key(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("Plume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("Plume App"); TEST_ASSERT_NOT_NULL(tag->app_name); @@ -1945,7 +1945,7 @@ test_vendor_data_serialize_deserialize(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("Plume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("Plume App"); TEST_ASSERT_NOT_NULL(tag->app_name); @@ -2048,7 +2048,7 @@ test_update_flow_tags(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("Plume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("Plume App"); TEST_ASSERT_NOT_NULL(tag->app_name); @@ -2120,7 +2120,7 @@ test_update_flow_tags(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("NotPlume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("NotPlume App"); TEST_ASSERT_NOT_NULL(tag->app_name); @@ -2336,7 +2336,7 @@ test_update_vendor_data(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("Plume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("Plume App"); TEST_ASSERT_NOT_NULL(tag->app_name); @@ -2468,7 +2468,7 @@ test_update_filter_flow_tags(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("Plume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("Plume App"); TEST_ASSERT_NOT_NULL(tag->app_name); @@ -2540,7 +2540,7 @@ test_update_filter_flow_tags(void) TEST_ASSERT_NOT_NULL(tag); tag->vendor = strdup("NotPlume"); - TEST_ASSERT_NOT_NULL(tag->vendor) + TEST_ASSERT_NOT_NULL(tag->vendor); tag->app_name = strdup("NotPlume App"); TEST_ASSERT_NOT_NULL(tag->app_name); diff --git a/src/lib/objmfs/inc/objmfs.h b/src/lib/objmfs/inc/objmfs.h new file mode 100644 index 00000000..a7849b7e --- /dev/null +++ b/src/lib/objmfs/inc/objmfs.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OBJMFS_H_INCLUDED +#define OBJMFS_H_INCLUDED + +#include + +bool objmfs_install(char *path, char *name, char *version); +bool objmfs_remove(char *name, char *version); +bool objmfs_path(char *buf, size_t buffsz, char *name, char *version); + +#endif /* OBJMFS_H_INCLUDED */ diff --git a/src/lib/objmfs/kconfig/Kconfig b/src/lib/objmfs/kconfig/Kconfig new file mode 100644 index 00000000..48d8d805 --- /dev/null +++ b/src/lib/objmfs/kconfig/Kconfig @@ -0,0 +1,21 @@ +if OSP_OBJM_OBJMFS + +menuconfig OBJMFS_ENABLED + bool "OBJMFS Backend" + default n + help + OBJMFS is short for Object management file system and is a library + that implements object management on read-write filesystem + + comment "OBJMFS Options" + depends on OBJMFS_ENABLED + + config OBJMFS_DIR + depends on OBJMFS_ENABLED + string "Folder location" + default "$(INSTALL_PREFIX)/storage" + help + Folder location where installed objects are stored. Objects are + stored in sub-folders as / + +endif diff --git a/src/lib/objmfs/src/objmfs.c b/src/lib/objmfs/src/objmfs.c new file mode 100644 index 00000000..6f15e728 --- /dev/null +++ b/src/lib/objmfs/src/objmfs.c @@ -0,0 +1,196 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include + +#include "const.h" +#include "schema.h" +#include "log.h" +#include "os.h" + +#define FIELD_ARRAY_LEN(TYPE,FIELD) ARRAY_LEN(((TYPE*)0)->FIELD) +#define CMD_LEN 1024 + +/****************************************************************************** + * Support functions + *****************************************************************************/ + +// Remove folder +static bool objmfs_rmdir(char *path) +{ + char cmd[CMD_LEN]; + if (strcmp(path, "/") == 0){ + LOG(ERR, "objmfs: removing / is not allowed: '%s'", path); + return false; + } + sprintf(cmd, "rm -fr %s", path); + LOG(TRACE, "objmfs: rmdir: %s", cmd); + if (cmd_log(cmd)) + { + return false; + } + return true; +} + +// Create folder and subfolders +static bool objmfs_mkdir(char *path) +{ + char cmd[CMD_LEN]; + sprintf(cmd, "mkdir -p %s", path); + LOG(TRACE, "objmfs: mkdir: %s", cmd); + if (cmd_log(cmd)) + { + return false; + } + return true; +} + +/****************************************************************************** + * Public API + *****************************************************************************/ + +bool objmfs_install(char *path, char *name, char *version) +{ + FILE *fd; + char cmd[CMD_LEN]; + char folder_path[PATH_MAX]; + char version_path[PATH_MAX]; + char *line = NULL; + + char object_name[FIELD_ARRAY_LEN(struct schema_Object_Store_Config, name)]; + char object_version[FIELD_ARRAY_LEN(struct schema_Object_Store_Config, version)]; + size_t len = 0; + ssize_t read; + bool ret; + + ret = true; + LOG(DEBUG, "objmfs: (%s): Installing: %s:%s:%s", __func__, name, version, path); + + objmfs_mkdir(CONFIG_OBJMFS_DIR); + sprintf(folder_path, "%s/%s", CONFIG_OBJMFS_DIR, name); + objmfs_mkdir(folder_path); + sprintf(folder_path, "%s/%s/%s", CONFIG_OBJMFS_DIR, name, version); + objmfs_mkdir(folder_path); + + sprintf(version_path, "%s/version", folder_path); + + objmfs_mkdir(folder_path); + + // Validate md5 of downloaded data + // Note: currently only tar.gz is supported, .deb package would require additional handling + sprintf(cmd, "gzip -t %s", path); + if (cmd_log(cmd)) + { + LOG(ERR, "objmfs: Integrity check of package failed: %s", cmd); + ret = false; + goto cleanup; + } + + // Extract tarball (or deb package) + sprintf(cmd, "tar -xzf %s -C %s", path, folder_path); + LOG(TRACE, "objmfs: Extract base tarball command: %s", cmd); + if (cmd_log(cmd)) + { + LOG(ERR, "objmfs: Extraction of package failed: %s", cmd); + ret = false; + goto cleanup; + } + + // Read name & version file and compare with data from ovsdb + fd = fopen(version_path, "r"); + while ((read = getline(&line, &len, fd)) != -1) + { + if (strstr(line, "name") != NULL) + { + sscanf(line, "name:%s", object_name); + } + if (strstr(line, "version") != NULL) + { + sscanf(line, "version:%s", object_version); + } + } + fclose(fd); + + // Validate metadata of object (name, version) + if (strcmp(object_name, name) != 0) + { + LOG(ERR, "objmfs: name mismatch; ovsdb name: '%s'; package_name: '%s'", name, object_name); + ret = false; + goto cleanup; + } + + if (strcmp(object_version, version) != 0) + { + LOG(ERR, "objmfs: version mismatch; ovsdb version: '%s'; package version: '%s'", version, object_version); + ret = false; + goto cleanup; + } + + // Extract data directly to storage + sprintf(cmd, "tar -xzf %s/data.tar.gz -C %s", folder_path, folder_path); + LOG(TRACE, "objmfs: Extract data command: %s", cmd); + if (cmd_log(cmd)) + { + LOG(ERR, "objmfs: Extraction of data failed: %s", cmd); + ret = false; + goto cleanup; + } + +cleanup: + sprintf(folder_path, "%s/data.tar.gz", folder_path); + objmfs_rmdir(folder_path); + objmfs_rmdir(path); //clean downloaded tarball + + return ret; +} + +bool objmfs_remove(char *name, char *version) +{ + char buf[PATH_MAX]; + LOG(DEBUG, "objmfs: Removing %s version %s from objmfs", name, version); + sprintf(buf, "%s/%s/%s", CONFIG_OBJMFS_DIR, name, version); + objmfs_rmdir(buf); + return true; +} + +bool objmfs_path(char *buf, size_t buffsz, char *name, char *version) +{ + int rc; + snprintf(buf, buffsz, "%s/%s/%s", CONFIG_OBJMFS_DIR, name, version); + + rc = access(buf, F_OK); + if (rc) + { + LOG(ERR, "objmfs: Object does not exist: %s %s: %s", name, version, strerror(errno)); + buf[0] = '\0'; + return false; + } + + return true; +} diff --git a/src/lib/objmfs/unit.mk b/src/lib/objmfs/unit.mk new file mode 100644 index 00000000..b7204cf7 --- /dev/null +++ b/src/lib/objmfs/unit.mk @@ -0,0 +1,42 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################## +# +# Object management file system backend -- library implementation +# +############################################################################## + +UNIT_NAME := objmfs + +# Template type: +UNIT_TYPE := LIB + +UNIT_CFLAGS += -I$(UNIT_PATH)/inc +UNIT_EXPORT_CFLAGS := -I$(UNIT_PATH)/inc + +UNIT_SRC += src/objmfs.c + +UNIT_DEPS_CFLAGS += src/lib/log +UNIT_DEPS_CFLAGS += src/lib/osp diff --git a/src/lib/oms/inc/object_manager.pb-c.h b/src/lib/oms/inc/object_manager.pb-c.h new file mode 100644 index 00000000..d2599c4e --- /dev/null +++ b/src/lib/oms/inc/object_manager.pb-c.h @@ -0,0 +1,172 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: object_manager.proto */ + +#ifndef PROTOBUF_C_object_5fmanager_2eproto__INCLUDED +#define PROTOBUF_C_object_5fmanager_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1000000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1003001 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct _ObjectManager__Status__ObservationPoint ObjectManager__Status__ObservationPoint; +typedef struct _ObjectManager__Status__ObjectStatus ObjectManager__Status__ObjectStatus; +typedef struct _ObjectManager__Status__ObjectStatusReport ObjectManager__Status__ObjectStatusReport; + + +/* --- enums --- */ + + +/* --- messages --- */ + +struct _ObjectManager__Status__ObservationPoint +{ + ProtobufCMessage base; + char *nodeid; + char *locationid; +}; +#define OBJECT_MANAGER__STATUS__OBSERVATION_POINT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&object_manager__status__observation_point__descriptor) \ + , NULL, NULL } + + +struct _ObjectManager__Status__ObjectStatus +{ + ProtobufCMessage base; + char *objectname; + char *version; + char *status; +}; +#define OBJECT_MANAGER__STATUS__OBJECT_STATUS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&object_manager__status__object_status__descriptor) \ + , NULL, NULL, NULL } + + +struct _ObjectManager__Status__ObjectStatusReport +{ + ProtobufCMessage base; + protobuf_c_boolean has_reportedat; + uint64_t reportedat; + ObjectManager__Status__ObservationPoint *observationpoint; + size_t n_objectstatus; + ObjectManager__Status__ObjectStatus **objectstatus; +}; +#define OBJECT_MANAGER__STATUS__OBJECT_STATUS_REPORT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&object_manager__status__object_status_report__descriptor) \ + , 0, 0, NULL, 0,NULL } + + +/* ObjectManager__Status__ObservationPoint methods */ +void object_manager__status__observation_point__init + (ObjectManager__Status__ObservationPoint *message); +size_t object_manager__status__observation_point__get_packed_size + (const ObjectManager__Status__ObservationPoint *message); +size_t object_manager__status__observation_point__pack + (const ObjectManager__Status__ObservationPoint *message, + uint8_t *out); +size_t object_manager__status__observation_point__pack_to_buffer + (const ObjectManager__Status__ObservationPoint *message, + ProtobufCBuffer *buffer); +ObjectManager__Status__ObservationPoint * + object_manager__status__observation_point__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void object_manager__status__observation_point__free_unpacked + (ObjectManager__Status__ObservationPoint *message, + ProtobufCAllocator *allocator); +/* ObjectManager__Status__ObjectStatus methods */ +void object_manager__status__object_status__init + (ObjectManager__Status__ObjectStatus *message); +size_t object_manager__status__object_status__get_packed_size + (const ObjectManager__Status__ObjectStatus *message); +size_t object_manager__status__object_status__pack + (const ObjectManager__Status__ObjectStatus *message, + uint8_t *out); +size_t object_manager__status__object_status__pack_to_buffer + (const ObjectManager__Status__ObjectStatus *message, + ProtobufCBuffer *buffer); +ObjectManager__Status__ObjectStatus * + object_manager__status__object_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void object_manager__status__object_status__free_unpacked + (ObjectManager__Status__ObjectStatus *message, + ProtobufCAllocator *allocator); +/* ObjectManager__Status__ObjectStatusReport methods */ +void object_manager__status__object_status_report__init + (ObjectManager__Status__ObjectStatusReport *message); +size_t object_manager__status__object_status_report__get_packed_size + (const ObjectManager__Status__ObjectStatusReport *message); +size_t object_manager__status__object_status_report__pack + (const ObjectManager__Status__ObjectStatusReport *message, + uint8_t *out); +size_t object_manager__status__object_status_report__pack_to_buffer + (const ObjectManager__Status__ObjectStatusReport *message, + ProtobufCBuffer *buffer); +ObjectManager__Status__ObjectStatusReport * + object_manager__status__object_status_report__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void object_manager__status__object_status_report__free_unpacked + (ObjectManager__Status__ObjectStatusReport *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*ObjectManager__Status__ObservationPoint_Closure) + (const ObjectManager__Status__ObservationPoint *message, + void *closure_data); +typedef void (*ObjectManager__Status__ObjectStatus_Closure) + (const ObjectManager__Status__ObjectStatus *message, + void *closure_data); +typedef void (*ObjectManager__Status__ObjectStatusReport_Closure) + (const ObjectManager__Status__ObjectStatusReport *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor object_manager__status__observation_point__descriptor; +extern const ProtobufCMessageDescriptor object_manager__status__object_status__descriptor; +extern const ProtobufCMessageDescriptor object_manager__status__object_status_report__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_object_5fmanager_2eproto__INCLUDED */ diff --git a/src/lib/oms/inc/oms.h b/src/lib/oms/inc/oms.h new file mode 100644 index 00000000..be0d8143 --- /dev/null +++ b/src/lib/oms/inc/oms.h @@ -0,0 +1,207 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OMS_H_INCLUDED +#define OMS_H_INCLUDED + +#include +#include + +#include "ds_tree.h" +#include "schema.h" + + +/** + * @brief config entry + * + * The config entry is used by the store manager to notify the recipient manager + * of an an object to load. + */ +struct oms_config_entry +{ + char *object; /* Object name */ + char *version; /* Version */ + ds_tree_t *other_config; /* Placeholder */ + ds_tree_node_t node; +}; + + +struct oms_state_entry +{ + char *object; /* Object name */ + char *version; /* Version */ + char *state; /* Mandatory state */ + bool fw_integrated; /* FW integrated indicator */ + char *prev_state; /* Previous state */ + ds_tree_t *other_state; /* placeholder */ + ds_tree_node_t node; +}; + + +typedef bool (*accept_id)(const char *); +typedef void (*ovsdb_config_cb)(struct oms_config_entry *, int); +typedef void (*ovsdb_state_cb)(struct oms_state_entry *, int); +typedef bool (*oms_report_status_cb)(struct oms_state_entry *); +typedef int (*oms_cmp_cb)(char *, char *, char *); + + +/** + * oms global context + */ +struct oms_mgr +{ + ds_tree_t config; /* DS tree of configs */ + ds_tree_t state; /* DS tree of states */ + ds_tree_t *mqtt_headers; /* DS tree of mqtt info */ + char *location_id; /* platfrom's location id */ + char *node_id; /* platform's node id */ + size_t num_states; /* Number of status nodes in the DS tree */ + size_t num_reports; /* Number of status node to report */ + accept_id accept_id; /* Filter object id */ + ovsdb_config_cb config_cb; /* osdb config event callback */ + ovsdb_state_cb state_cb; /* osdb state event callback */ + oms_report_status_cb report_cb; /* status report filter */ + bool initialized; /* Initialization completion flag */ +}; + + +/** + * oms initialization paramaters container + */ +struct oms_ovsdb_set +{ + bool monitor_config; /* Request to monitor oms config table */ + bool monitor_state; /* Request to monitor oms state table */ + bool monitor_awlan; /* Request to monitor AWLAN_Node table */ + accept_id accept_id; /* Filter object */ + ovsdb_config_cb config_cb; /* ovsdb config event callback */ + ovsdb_state_cb state_cb; /* ovsdb state event callback */ + oms_report_status_cb report_cb; /* status report filter */ +}; + +void +oms_init_manager(void); + +struct oms_mgr * +oms_get_mgr(void); + +void +oms_ovsdb_init(struct oms_ovsdb_set *oms_set); + + +/** + * @brief delete an oms config entry + * + * @param entry the config entry to delete + */ +void +oms_free_config_entry(struct oms_config_entry *entry); + + +/** + * @brief free all stored config entries + */ +void +oms_delete_config_entries(void); + +/** + * @param process an ovsdb add config event + * + * @param config the ovsdb entry to process + * Allocates resources for the entry and stores it. + */ +void +oms_ovsdb_add_config_entry(struct schema_OMS_Config *config); + +/** + * @param process an ovsdb delete config event + * + * @param config the ovsdb entry to process + * Frees resources for the entry and deletes it. + */ +void +oms_ovsdb_del_config_entry(struct schema_OMS_Config *config); + +/** + * @brief add a config entry in the ovsdb object config table + * + * @param entry the entry to add + */ +int +oms_add_config_entry(struct oms_config_entry *entry); + +/** + * @brief delete a config entry in the ovsdb object config table + * + * @param entry the entry to delete + */ +int +oms_delete_config_entry(struct oms_config_entry *entry); + +/** + * @brief delete an oms state entry + * + * @param entry the state entry to delete + */ +void +oms_free_state_entry(struct oms_state_entry *entry); + +/** + * @brief free all stored config entries + */ +void +oms_delete_state_entries(void); + +/** + * @brief process an ovsdb add state event + * + * @param state the ovsdb entry to process + * Allocates resources for the entry and stores it. + */ +void +oms_ovsdb_add_state_entry(struct schema_Object_Store_State *state); + +/** + * @brief add a state entry in the ovsdb object state table + * + * @param entry the entry to add + */ +int +oms_add_state_entry(struct oms_state_entry *entry); + +/** + * @brief add a state entry in the ovsdb object state table + * + * @param entry the entry to add + */ +int +oms_delete_state_entry(struct oms_state_entry *entry); + + +struct oms_config_entry * +oms_get_highest_version(char *object, char *version_cap, oms_cmp_cb cmp_cb); + +#endif /* OMS_H_INCLUDED */ diff --git a/src/lib/oms/inc/oms_report.h b/src/lib/oms/inc/oms_report.h new file mode 100644 index 00000000..cd29307a --- /dev/null +++ b/src/lib/oms/inc/oms_report.h @@ -0,0 +1,71 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OMS_REPORT_H_INCLUDED +#define OMS_REPORT_H_INCLUDED + +/** + * @brief Container of protobuf serialization output + * + * Contains the information related to a serialized protobuf + */ +struct packed_buffer +{ + size_t len; /*buf) + * and the container (pb). + * + * @param pb a pointer to a serialized data container + * @return none + */ +void +oms_report_free_packed_buffer(struct packed_buffer *pb); + +/** + * @brief Generates a flow report serialized protobuf + * + * Uses the information pointed by the report parameter to generate + * a serialized flow report buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see oms_report_free_packed_buffer() for this purpose. + * + * @param node info used to fill up the protobuf. + * @return a pointer to the serialized data. + */ +struct packed_buffer * +oms_report_serialize_report(void); + + +bool oms_report_send_report(char *mqtt_topic); + +#endif /* OMS_REPORT_H_INCLUDED */ diff --git a/src/lib/oms/src/object_manager.pb-c.c b/src/lib/oms/src/object_manager.pb-c.c new file mode 100644 index 00000000..a0be014e --- /dev/null +++ b/src/lib/oms/src/object_manager.pb-c.c @@ -0,0 +1,349 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: object_manager.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "object_manager.pb-c.h" +void object_manager__status__observation_point__init + (ObjectManager__Status__ObservationPoint *message) +{ + static const ObjectManager__Status__ObservationPoint init_value = OBJECT_MANAGER__STATUS__OBSERVATION_POINT__INIT; + *message = init_value; +} +size_t object_manager__status__observation_point__get_packed_size + (const ObjectManager__Status__ObservationPoint *message) +{ + assert(message->base.descriptor == &object_manager__status__observation_point__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t object_manager__status__observation_point__pack + (const ObjectManager__Status__ObservationPoint *message, + uint8_t *out) +{ + assert(message->base.descriptor == &object_manager__status__observation_point__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t object_manager__status__observation_point__pack_to_buffer + (const ObjectManager__Status__ObservationPoint *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &object_manager__status__observation_point__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +ObjectManager__Status__ObservationPoint * + object_manager__status__observation_point__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (ObjectManager__Status__ObservationPoint *) + protobuf_c_message_unpack (&object_manager__status__observation_point__descriptor, + allocator, len, data); +} +void object_manager__status__observation_point__free_unpacked + (ObjectManager__Status__ObservationPoint *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &object_manager__status__observation_point__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void object_manager__status__object_status__init + (ObjectManager__Status__ObjectStatus *message) +{ + static const ObjectManager__Status__ObjectStatus init_value = OBJECT_MANAGER__STATUS__OBJECT_STATUS__INIT; + *message = init_value; +} +size_t object_manager__status__object_status__get_packed_size + (const ObjectManager__Status__ObjectStatus *message) +{ + assert(message->base.descriptor == &object_manager__status__object_status__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t object_manager__status__object_status__pack + (const ObjectManager__Status__ObjectStatus *message, + uint8_t *out) +{ + assert(message->base.descriptor == &object_manager__status__object_status__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t object_manager__status__object_status__pack_to_buffer + (const ObjectManager__Status__ObjectStatus *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &object_manager__status__object_status__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +ObjectManager__Status__ObjectStatus * + object_manager__status__object_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (ObjectManager__Status__ObjectStatus *) + protobuf_c_message_unpack (&object_manager__status__object_status__descriptor, + allocator, len, data); +} +void object_manager__status__object_status__free_unpacked + (ObjectManager__Status__ObjectStatus *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &object_manager__status__object_status__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void object_manager__status__object_status_report__init + (ObjectManager__Status__ObjectStatusReport *message) +{ + static const ObjectManager__Status__ObjectStatusReport init_value = OBJECT_MANAGER__STATUS__OBJECT_STATUS_REPORT__INIT; + *message = init_value; +} +size_t object_manager__status__object_status_report__get_packed_size + (const ObjectManager__Status__ObjectStatusReport *message) +{ + assert(message->base.descriptor == &object_manager__status__object_status_report__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t object_manager__status__object_status_report__pack + (const ObjectManager__Status__ObjectStatusReport *message, + uint8_t *out) +{ + assert(message->base.descriptor == &object_manager__status__object_status_report__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t object_manager__status__object_status_report__pack_to_buffer + (const ObjectManager__Status__ObjectStatusReport *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &object_manager__status__object_status_report__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +ObjectManager__Status__ObjectStatusReport * + object_manager__status__object_status_report__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (ObjectManager__Status__ObjectStatusReport *) + protobuf_c_message_unpack (&object_manager__status__object_status_report__descriptor, + allocator, len, data); +} +void object_manager__status__object_status_report__free_unpacked + (ObjectManager__Status__ObjectStatusReport *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &object_manager__status__object_status_report__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor object_manager__status__observation_point__field_descriptors[2] = +{ + { + "nodeId", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(ObjectManager__Status__ObservationPoint, nodeid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "locationId", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(ObjectManager__Status__ObservationPoint, locationid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned object_manager__status__observation_point__field_indices_by_name[] = { + 1, /* field[1] = locationId */ + 0, /* field[0] = nodeId */ +}; +static const ProtobufCIntRange object_manager__status__observation_point__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor object_manager__status__observation_point__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "objectManager.status.ObservationPoint", + "ObservationPoint", + "ObjectManager__Status__ObservationPoint", + "objectManager.status", + sizeof(ObjectManager__Status__ObservationPoint), + 2, + object_manager__status__observation_point__field_descriptors, + object_manager__status__observation_point__field_indices_by_name, + 1, object_manager__status__observation_point__number_ranges, + (ProtobufCMessageInit) object_manager__status__observation_point__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor object_manager__status__object_status__field_descriptors[3] = +{ + { + "objectName", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(ObjectManager__Status__ObjectStatus, objectname), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "version", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(ObjectManager__Status__ObjectStatus, version), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "status", + 3, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(ObjectManager__Status__ObjectStatus, status), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned object_manager__status__object_status__field_indices_by_name[] = { + 0, /* field[0] = objectName */ + 2, /* field[2] = status */ + 1, /* field[1] = version */ +}; +static const ProtobufCIntRange object_manager__status__object_status__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor object_manager__status__object_status__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "objectManager.status.ObjectStatus", + "ObjectStatus", + "ObjectManager__Status__ObjectStatus", + "objectManager.status", + sizeof(ObjectManager__Status__ObjectStatus), + 3, + object_manager__status__object_status__field_descriptors, + object_manager__status__object_status__field_indices_by_name, + 1, object_manager__status__object_status__number_ranges, + (ProtobufCMessageInit) object_manager__status__object_status__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor object_manager__status__object_status_report__field_descriptors[3] = +{ + { + "reportedAt", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(ObjectManager__Status__ObjectStatusReport, has_reportedat), + offsetof(ObjectManager__Status__ObjectStatusReport, reportedat), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "observationPoint", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(ObjectManager__Status__ObjectStatusReport, observationpoint), + &object_manager__status__observation_point__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "objectStatus", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(ObjectManager__Status__ObjectStatusReport, n_objectstatus), + offsetof(ObjectManager__Status__ObjectStatusReport, objectstatus), + &object_manager__status__object_status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned object_manager__status__object_status_report__field_indices_by_name[] = { + 2, /* field[2] = objectStatus */ + 1, /* field[1] = observationPoint */ + 0, /* field[0] = reportedAt */ +}; +static const ProtobufCIntRange object_manager__status__object_status_report__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor object_manager__status__object_status_report__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "objectManager.status.ObjectStatusReport", + "ObjectStatusReport", + "ObjectManager__Status__ObjectStatusReport", + "objectManager.status", + sizeof(ObjectManager__Status__ObjectStatusReport), + 3, + object_manager__status__object_status_report__field_descriptors, + object_manager__status__object_status_report__field_indices_by_name, + 1, object_manager__status__object_status_report__number_ranges, + (ProtobufCMessageInit) object_manager__status__object_status_report__init, + NULL,NULL,NULL /* reserved[123] */ +}; diff --git a/src/lib/oms/src/oms.c b/src/lib/oms/src/oms.c new file mode 100644 index 00000000..91a43763 --- /dev/null +++ b/src/lib/oms/src/oms.c @@ -0,0 +1,260 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "oms.h" +#include "ovsdb_utils.h" +#include "log.h" + +static struct oms_mgr mgr = +{ + .initialized = false, +}; + + +struct oms_mgr * +oms_get_mgr(void) +{ + return &mgr; +} + + +/** + * @brief compare 2 config entries + * + * A config entry is uniquely identified by its object id and version + */ +static int +oms_config_cmp(void *a, void *b) +{ + struct oms_config_entry *id_a; + struct oms_config_entry *id_b; + int ret; + + id_a = (struct oms_config_entry *)a; + id_b = (struct oms_config_entry *)b; + + /* First compare object id */ + ret = strcmp(id_a->object, id_b->object); + if (ret != 0) return ret; + + /* Then compare versions */ + return strcmp(id_a->version, id_b->version); +} + + +/** + * @brief compare 2 state entries + * + * A state entry is uniquely identified by its object id and version + */ +static int +oms_state_cmp(void *a, void *b) +{ + struct oms_state_entry *id_a; + struct oms_state_entry *id_b; + int ret; + + id_a = (struct oms_state_entry *)a; + id_b = (struct oms_state_entry *)b; + + ret = strcmp(id_a->object, id_b->object); + if (ret != 0) return ret; + + /* Then compare versions */ + return strcmp(id_a->version, id_b->version); +} + + +/** + * @brief delete an oms config entry + * + * @param entry the config entry to delete + */ +void +oms_free_config_entry(struct oms_config_entry *entry) +{ + if (entry == NULL) return; + + free(entry->object); + free(entry->version); + free_str_tree(entry->other_config); + free(entry); +} + + +/** + * @brief free all stored config entries + */ +void +oms_delete_config_entries(void) +{ + struct oms_config_entry *remove; + struct oms_config_entry *entry; + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + tree = &mgr->config; + + entry = ds_tree_head(tree); + while (entry != NULL) + { + remove = entry; + entry = ds_tree_next(tree, entry); + ds_tree_remove(tree, remove); + oms_free_config_entry(remove); + } +} + + +/** + * @brief delete an oms state entry + * + * @param entry the state entry to delete + */ +void +oms_free_state_entry(struct oms_state_entry *entry) +{ + if (entry == NULL) return; + + free(entry->object); + free(entry->version); + free(entry->state); + free(entry->prev_state); + free_str_tree(entry->other_state); + free(entry); +} + +/** + * @brief free all stored config entries + */ +void +oms_delete_state_entries(void) +{ + struct oms_state_entry *remove; + struct oms_state_entry *entry; + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + tree = &mgr->state; + + entry = ds_tree_head(tree); + while (entry != NULL) + { + remove = entry; + entry = ds_tree_next(tree, entry); + ds_tree_remove(tree, remove); + oms_free_state_entry(remove); + } + mgr->num_states = 0; +} + + +/** + * @brief return the highest version of an object + * + * @param object the object name + * @param version_cap the version cap, excluded + * @return the object with the highest version + * + * If @param version_cap is provided, the return shall be lesser than it or NULL + * The caller is responsible for freeing the returned object + */ +struct oms_config_entry * +oms_get_highest_version(char *object, char *version_cap, oms_cmp_cb cmp_cb) +{ + struct oms_config_entry *latest; + struct oms_config_entry *entry; + struct oms_mgr *mgr; + ds_tree_t *tree; + int cmp; + + if (object == NULL) return NULL; + if (cmp_cb == NULL) return NULL; + + mgr = oms_get_mgr(); + tree = &mgr->config; + entry = ds_tree_head(tree); + latest = NULL; + + while (entry != NULL) + { + /* Ignore object mismatch */ + cmp = strcmp(object, entry->object); + if (cmp != 0) + { + entry = ds_tree_next(tree, entry); + continue; + } + + /* Ignore version greater or equal the max version if provided */ + if (version_cap != NULL) + { + cmp = cmp_cb(object, entry->version, version_cap); + if (cmp >= 0) + { + entry = ds_tree_next(tree, entry); + continue; + } + } + + if (latest == NULL) + { + latest = entry; + entry = ds_tree_next(tree, entry); + continue; + } + + cmp = cmp_cb(object, entry->version, latest->version); + if (cmp > 0) latest = entry; + entry = ds_tree_next(tree, entry); + } + + return latest; +} + + +void +oms_init_manager(void) +{ + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + + /* Initialize configs container */ + tree = &mgr->config; + ds_tree_init(tree, oms_config_cmp, struct oms_config_entry, node); + + /* Initialize state container */ + tree = &mgr->state; + ds_tree_init(tree, oms_state_cmp, struct oms_state_entry, node); + + mgr->initialized = true; +} diff --git a/src/lib/oms/src/oms_ovsdb.c b/src/lib/oms/src/oms_ovsdb.c new file mode 100644 index 00000000..12ba479d --- /dev/null +++ b/src/lib/oms/src/oms_ovsdb.c @@ -0,0 +1,723 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "ds_tree.h" +#include "oms.h" +#include "os.h" +#include "ovsdb.h" +#include "ovsdb_update.h" +#include "ovsdb_sync.h" +#include "ovsdb_table.h" +#include "ovsdb_utils.h" +#include "schema.h" +#include "log.h" +#include "util.h" + +static ovsdb_table_t table_OMS_Config; +static ovsdb_table_t table_Object_Store_State; +static ovsdb_table_t table_AWLAN_Node; + +/** + * @brief add a config entry in the ovsdb object config table + * + * @param entry the entry to add + */ +int +oms_add_config_entry(struct oms_config_entry *entry) +{ + struct schema_OMS_Config config; + const char *key; + json_t *where; + json_t *cond; + bool rc; + int ret; + + if (entry == NULL) return -1; + if (entry->object == NULL) return -1; + if (entry->version == NULL) return -1; + + /* Select ovsdb target based on the object id and version */ + where = json_array(); + cond = ovsdb_tran_cond_single("object_name", OFUNC_EQ, entry->object); + json_array_append_new(where, cond); + cond = ovsdb_tran_cond_single("version", OFUNC_EQ, entry->version); + json_array_append_new(where, cond); + + MEMZERO(config); + + /* Object name */ + key = entry->object; + if (key != NULL) SCHEMA_SET_STR(config.object_name, key); + + /* Version */ + key = entry->version; + if (key != NULL) SCHEMA_SET_STR(config.version, key); + + /* other_config, to be processed */ + + rc = ovsdb_table_upsert_where(&table_OMS_Config, where, &config, false); + json_decref(where); + + ret = rc ? 0 : -1; + + return ret; +} + + +/** + * @brief delete a config entry from the ovsdb object config table + * + * @param entry the entry to delete + */ +int +oms_delete_config_entry(struct oms_config_entry *entry) +{ + json_t *where; + json_t *cond; + bool rc; + int ret; + + if (entry == NULL) return -1; + if (entry->object == NULL) return -1; + if (entry->version == NULL) return -1; + + /* Select ovsdb target based on the object id and version */ + where = json_array(); + cond = ovsdb_tran_cond_single("object_name", OFUNC_EQ, entry->object); + json_array_append_new(where, cond); + cond = ovsdb_tran_cond_single("version", OFUNC_EQ, entry->version); + json_array_append_new(where, cond); + + rc = ovsdb_table_delete_where(&table_OMS_Config, where); + json_decref(where); + + ret = rc ? 0 : -1; + + return ret; +} + + +/** + * @brief add a state entry in the ovsdb object state table + * + * @param entry the entry to add + */ +int +oms_add_state_entry(struct oms_state_entry *entry) +{ + struct schema_Object_Store_State state; + const char *key; + json_t *where; + json_t *cond; + bool rc; + int ret; + + if (entry == NULL) return -1; + if (entry->object == NULL) return -1; + if (entry->version == NULL) return -1; + + /* Select ovsdb target based on the object id and version */ + where = json_array(); + cond = ovsdb_tran_cond_single("name", OFUNC_EQ, entry->object); + json_array_append_new(where, cond); + cond = ovsdb_tran_cond_single("version", OFUNC_EQ, entry->version); + json_array_append_new(where, cond); + + MEMZERO(state); + + /* Object name */ + key = entry->object; + if (key != NULL) SCHEMA_SET_STR(state.name, key); + + /* Version */ + key = entry->version; + if (key != NULL) SCHEMA_SET_STR(state.version, key); + + /* State */ + key = entry->state; + if (key != NULL) SCHEMA_SET_STR(state.status, key); + + /* Fw integrated */ + SCHEMA_SET_INT(state.fw_integrated, entry->fw_integrated); + + /* other_config, to be processed */ + + rc = ovsdb_table_upsert_where(&table_Object_Store_State, where, &state, false); + json_decref(where); + + ret = rc ? 0 : -1; + + return ret; +} + + +/** + * @brief delete a state entry from the ovsdb object state table + * + * @param entry the entry to delete + */ +int +oms_delete_state_entry(struct oms_state_entry *entry) +{ + json_t *where; + json_t *cond; + bool rc; + int ret; + + if (entry == NULL) return -1; + if (entry->object == NULL) return -1; + if (entry->version == NULL) return -1; + + /* Select ovsdb target based on the object id and version */ + where = json_array(); + cond = ovsdb_tran_cond_single("name", OFUNC_EQ, entry->object); + json_array_append_new(where, cond); + cond = ovsdb_tran_cond_single("version", OFUNC_EQ, entry->version); + json_array_append_new(where, cond); + + rc = ovsdb_table_delete_where(&table_Object_Store_State, where); + json_decref(where); + + ret = rc ? 0 : -1; + + return ret; +} + + +/** + * @brief process an ovsdb add config event + * + * @param config the ovsdb entry to process + * Allocates resources for the entry and stores it. + */ +void +oms_ovsdb_add_config_entry(struct schema_OMS_Config *config) +{ + struct oms_config_entry *entry; + struct oms_config_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *object; + bool rc; + + mgr = oms_get_mgr(); + rc = true; + tree = &mgr->config; + + if (!config->object_name_present) return; + if (!config->version_present) return; + + /* Get the object identifier */ + object = config->object_name; + + /* Check if we are interested in this object id */ + if (mgr->accept_id) rc = mgr->accept_id(object); + if (!rc) return; + + /* Look up the entry. If found, bail */ + lookup.object = object; + lookup.version = config->version; + entry = ds_tree_find(tree, &lookup); + if (entry != NULL) return; + + /* Allocate and initialize the entry */ + entry = calloc(1, sizeof(*entry)); + if (entry == NULL) return; + + entry->object = strdup(config->object_name); + if (entry->object == NULL) goto err_free_entry; + + entry->version = strdup(config->version); + if (entry->version == NULL) goto err_free_object; + + + if (config->other_config_present && config->other_config_len) + { + entry->other_config = schema2tree(sizeof(config->other_config_keys[0]), + sizeof(config->other_config[0]), + config->other_config_len, + config->other_config_keys, + config->other_config); + if (entry->other_config == NULL) goto err_free_version; + } + + /* Store the entry */ + ds_tree_insert(tree, entry, entry); + + /* Notify the manager */ + if (mgr->config_cb) (mgr->config_cb(entry, OVSDB_UPDATE_NEW)); + + return; + +err_free_version: + free(entry->version); + +err_free_object: + free(entry->object); + +err_free_entry: + free(entry); + + LOGE("%s: entry creation failed", __func__); + return; +} + + +/** + * @brief process an ovsdb delete config event + * + * @param config the ovsdb entry to process + * Frees resources for the entry and deletes it. + */ +void +oms_ovsdb_del_config_entry(struct schema_OMS_Config *config) +{ + struct oms_config_entry *entry; + struct oms_config_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *object; + bool rc; + + mgr = oms_get_mgr(); + rc = true; + tree = &mgr->config; + + /* Get the object identifier */ + object = config->object_name; + + /* Check if we are interested in this object id */ + if (mgr->accept_id) rc = mgr->accept_id(object); + if (!rc) return; + + /* Look up the entry. If not found, bail */ + lookup.object = object; + lookup.version = config->version; + entry = ds_tree_find(tree, &lookup); + if (entry == NULL) return; + + /* Notify the manager */ + if (mgr->config_cb) (mgr->config_cb(entry, OVSDB_UPDATE_DEL)); + + /* remove and free the entry */ + ds_tree_remove(tree, entry); + oms_free_config_entry(entry); + +} + + +/** + * @brief add or update an oms config entry + * + * @param old_rec the previous ovsdb oms config info about the entry + * to add/update + * @param config the ovsdb oms config info about the entry to add/update + * + * If the entry's object_id or version is flagged as changed, + * remove the old entry and add a new one. + * Else update the entry. + */ +void +oms_ovsdb_update_config_entry(struct schema_OMS_Config *old_rec, + struct schema_OMS_Config *config) +{ + if (config->object_name_changed || config->version_changed) + { + /* Remove the old record */ + oms_ovsdb_del_config_entry(old_rec); + } + + /* Add/update the new record */ + oms_ovsdb_add_config_entry(config); + + return; +} + + +/** + * @brief OMS_Config events callback + */ +static void +callback_OMS_Config(ovsdb_update_monitor_t *mon, + struct schema_OMS_Config *old_rec, + struct schema_OMS_Config *oms_config) +{ + if (mon->mon_type == OVSDB_UPDATE_NEW) + { + oms_ovsdb_add_config_entry(oms_config); + return; + } + + if (mon->mon_type == OVSDB_UPDATE_DEL) + { + oms_ovsdb_del_config_entry(oms_config); + return; + } + + if (mon->mon_type == OVSDB_UPDATE_MODIFY) + { + oms_ovsdb_update_config_entry(old_rec, oms_config); + return; + } +} + + +/** + * @brief process an ovsdb add state event + * + * @param state the ovsdb entry to process + * Allocates resources for the entry and stores it. + */ +void +oms_ovsdb_add_state_entry(struct schema_Object_Store_State *state) +{ + struct oms_config_entry lookup; + struct oms_state_entry *entry; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *object; + + mgr = oms_get_mgr(); + tree = &mgr->state; + + if (!state->name_present) return; + if (!state->version_present) return; + if (!state->status_present) return; + + /* Get the object identifier */ + object = state->name; + + /* Look up the entry. If found, bail */ + lookup.object = object; + lookup.version = state->version; + entry = ds_tree_find(tree, &lookup); + if (entry != NULL) return; + + /* Allocate and initialize the entry */ + entry = calloc(1, sizeof(*entry)); + if (entry == NULL) return; + + entry->object = strdup(state->name); + if (entry->object == NULL) goto err_free_entry; + + entry->version = strdup(state->version); + if (entry->version == NULL) goto err_free_object; + + entry->state = strdup(state->status); + if (entry->state == NULL) goto err_free_version; + + /* Store the entry */ + ds_tree_insert(tree, entry, entry); + + /* Notify the manager */ + if (mgr->state_cb) (mgr->state_cb(entry, OVSDB_UPDATE_NEW)); + + mgr->num_states++; + + return; + +err_free_version: + free(entry->version); + +err_free_object: + free(entry->object); + +err_free_entry: + free(entry); + + LOGE("%s: entry creation failed", __func__); + return; +} + + +/** + * @brief process an ovsdb delete state event + * + * @param state the ovsdb entry to process + * Frees resources for the entry and deletes it. + */ +void +oms_ovsdb_del_state_entry(struct schema_Object_Store_State *state) +{ + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + tree = &mgr->state; + + /* Get the object identifier */ + if (!state->name_present) return; + if (!state->version_present) return; + + lookup.object = state->name; + lookup.version = state->version; + + /* Look up the entry based on its object id. If not found, bail */ + entry = ds_tree_find(tree, &lookup); + if (entry == NULL) return; + + /* Notify the manager */ + if (mgr->state_cb) (mgr->state_cb(entry, OVSDB_UPDATE_DEL)); + + /* remove and free the entry */ + ds_tree_remove(tree, entry); + oms_free_state_entry(entry); + mgr->num_states--; +} + + +void +oms_ovsdb_update_state(struct schema_Object_Store_State *old_rec, + struct schema_Object_Store_State *oms_state) +{ + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + tree = &mgr->state; + + /* Get the object identifier */ + if (!oms_state->name_present) return; + if (!oms_state->version_present) return; + + lookup.object = oms_state->name; + lookup.version = oms_state->version; + + /* Look up the entry based on its object id. If not found, bail */ + entry = ds_tree_find(tree, &lookup); + if (entry == NULL) return; + + if (oms_state->status_changed) + { + char *previous_state; + char *new_state; + + /* Get the previous state */ + previous_state = strdup(entry->state); + if (previous_state == NULL) return; + + /* Get the new state */ + new_state = strdup(oms_state->status); + if (new_state == NULL) return; + + free(entry->prev_state); + entry->prev_state = previous_state; + + free(entry->state); + entry->state = new_state; + } + + if (mgr->state_cb) (mgr->state_cb(entry, OVSDB_UPDATE_MODIFY)); +} + + +/** + * @brief add or update an oms state entry + * + * @param old_rec the previous ovsdb oms state info about the entry + * to add/update + * @param oms_state the ovsdb oms state info about the entry to add/update + * + * If the entry's object_id or version is flagged as changed, + * remove the old entry and add a new one. + * Else update the entry. + */ +void +oms_ovsdb_update_state_entry(struct schema_Object_Store_State *old_rec, + struct schema_Object_Store_State *oms_state) +{ + if (oms_state->name_changed || oms_state->version_changed) + { + /* Remove the old record */ + oms_ovsdb_del_state_entry(old_rec); + + /* Add/update the new record */ + oms_ovsdb_add_state_entry(oms_state); + } + + oms_ovsdb_update_state(old_rec, oms_state); +} + + +/** + * @brief Object_Store_State events callback + */ +static void +callback_Object_Store_State(ovsdb_update_monitor_t *mon, + struct schema_Object_Store_State *old_rec, + struct schema_Object_Store_State *oms_state) +{ + if (mon->mon_type == OVSDB_UPDATE_NEW) + { + oms_ovsdb_add_state_entry(oms_state); + return; + } + + if (mon->mon_type == OVSDB_UPDATE_DEL) + { + oms_ovsdb_del_state_entry(oms_state); + return; + } + + if (mon->mon_type == OVSDB_UPDATE_MODIFY) + { + oms_ovsdb_update_state_entry(old_rec, oms_state); + return; + } +} + +/** + * @brief gather mqtt records from AWLAN_Node's mqtt headers table + * + * Records the mqtt_headers (locationId, nodeId) + * @param awlan AWLAN_Node record + */ +void +oms_get_awlan_headers(struct schema_AWLAN_Node *awlan) +{ + char *location = "locationId"; + struct str_pair *pair; + char *node = "nodeId"; + struct oms_mgr *mgr; + size_t key_size; + size_t val_size; + size_t nelems; + + /* Get the manager */ + mgr = oms_get_mgr(); + + /* Free previous headers if any */ + free_str_tree(mgr->mqtt_headers); + + /* Get AWLAN_Node's mqtt_headers element size */ + key_size = sizeof(awlan->mqtt_headers_keys[0]); + val_size = sizeof(awlan->mqtt_headers[0]); + + /* Get AWLAN_Node's number of elements */ + nelems = awlan->mqtt_headers_len; + + mgr->mqtt_headers = schema2tree(key_size, val_size, nelems, + awlan->mqtt_headers_keys, + awlan->mqtt_headers); + if (mgr->mqtt_headers == NULL) goto err; + + /* Check the presence of locationId in the mqtt headers */ + pair = ds_tree_find(mgr->mqtt_headers, location); + if (pair == NULL) goto err; + mgr->location_id = pair->value; + + /* Check the presence of nodeId in the mqtt headers */ + pair = ds_tree_find(mgr->mqtt_headers, node); + if (pair == NULL) goto err; + + mgr->node_id = pair->value; + + return; + +err: + free_str_tree(mgr->mqtt_headers); + mgr->mqtt_headers = NULL; + mgr->location_id = NULL; + mgr->node_id = NULL; + + return; +} + + +/** + * @brief delete recorded mqtt headers + */ +void +oms_rm_awlan_headers(void) +{ + struct oms_mgr *mgr; + + /* Get the manager */ + mgr = oms_get_mgr(); + + /* Free previous headers if any */ + free_str_tree(mgr->mqtt_headers); + mgr->mqtt_headers = NULL; + mgr->location_id = NULL; + mgr->node_id = NULL; +} + + +/** + * @brief registered callback for AWLAN_Node events + */ +static void +callback_AWLAN_Node(ovsdb_update_monitor_t *mon, + struct schema_AWLAN_Node *old_rec, + struct schema_AWLAN_Node *awlan) +{ + if (mon->mon_type == OVSDB_UPDATE_NEW) oms_get_awlan_headers(awlan); + if (mon->mon_type == OVSDB_UPDATE_DEL) oms_rm_awlan_headers(); + if (mon->mon_type == OVSDB_UPDATE_MODIFY) oms_get_awlan_headers(awlan); +} + + +/** + * @brief Initialize ovsdb tables + * + * @param oms_set the set of configuration parameters + */ +void +oms_ovsdb_init(struct oms_ovsdb_set *oms_set) +{ + struct oms_mgr *mgr; + + OVSDB_TABLE_INIT_NO_KEY(OMS_Config); + OVSDB_TABLE_INIT_NO_KEY(Object_Store_State); + + if (oms_set->monitor_config) + { + OVSDB_TABLE_MONITOR(OMS_Config, false); + } + + if (oms_set->monitor_state) + { + OVSDB_TABLE_MONITOR(Object_Store_State, false); + } + + if (oms_set->monitor_awlan) + { + OVSDB_TABLE_INIT_NO_KEY(AWLAN_Node); + OVSDB_TABLE_MONITOR(AWLAN_Node, false); + } + + mgr = oms_get_mgr(); + mgr->accept_id = oms_set->accept_id; + mgr->config_cb = oms_set->config_cb; + mgr->state_cb = oms_set->state_cb; + mgr->report_cb = oms_set->report_cb; +} diff --git a/src/lib/oms/src/oms_report.c b/src/lib/oms/src/oms_report.c new file mode 100644 index 00000000..1990d20d --- /dev/null +++ b/src/lib/oms/src/oms_report.c @@ -0,0 +1,606 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "log.h" +#include "qm_conn.h" +#include "oms.h" +#include "oms_report.h" +#include "object_manager.pb-c.h" + +#define MAX_STRLEN 256 + +/** + * @brief Duplicates a string and returns true if successful + * + * wrapper around string duplication when the source string might be + * a null pointer. + * + * @param src source string to duplicate. Might be NULL. + * @param dst destination string pointer + * @return true if duplicated, false otherwise + */ +static bool +oms_report_str_duplicate(char *src, char **dst) +{ + if (src == NULL) + { + *dst = NULL; + return true; + } + + *dst = strndup(src, MAX_STRLEN); + if (*dst == NULL) + { + LOGE("%s: could not duplicate %s", __func__, src); + return false; + } + + return true; +} + + +/** + * @brief Allocates and sets an observation point protobuf. + * + * Uses the node info to fill a dynamically allocated + * observation point protobuf. + * The caller is responsible for freeing the returned pointer, + * @see oms_free_pb_op() for this purpose. + * + * @param node info used to fill up the protobuf. + * @return a pointer to a observation point protobuf structure + */ +static ObjectManager__Status__ObservationPoint * +oms_report_set_node_info(void) +{ + ObjectManager__Status__ObservationPoint *pb; + struct oms_mgr *mgr; + bool ret; + + mgr = oms_get_mgr(); + + /* Allocate the protobuf structure */ + pb = calloc(1, sizeof(*pb)); + if (pb == NULL) + { + LOGE("%s: ObservationPoint protobuf struct allocation" + " failed", __func__); + return NULL; + } + + /* Initialize the protobuf structure */ + object_manager__status__observation_point__init(pb); + + /* Set the protobuf fields */ + ret = oms_report_str_duplicate(mgr->node_id, &pb->nodeid); + LOGI("%s: nodeid set to %s", __func__, pb->nodeid); + if (!ret) goto err_free_pb; + + ret = oms_report_str_duplicate(mgr->location_id, &pb->locationid); + if (!ret) goto err_free_node_id; + + return pb; + +err_free_node_id: + free(pb->nodeid); + +err_free_pb: + free(pb); + + return NULL; +} + + +/** + * @brief Frees an observation point protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb observation point structure to free + * @return none + */ +static void +oms_report_free_pb_op(ObjectManager__Status__ObservationPoint *pb) +{ + if (pb == NULL) return; + + free(pb->nodeid); + free(pb->locationid); + + free(pb); + + return; +} + + +/** + * @brief Generates an observation point serialized protobuf + * + * Uses the information pointed by the info parameter to generate + * a serialized obervation point buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see free_packed_buffer() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to the serialized data. + */ +struct packed_buffer * +oms_report_serialize_node_info(void) +{ + ObjectManager__Status__ObservationPoint *pb; + struct packed_buffer *serialized; + size_t len; + void *buf; + + /* Allocate serialization output container */ + serialized = calloc(1, sizeof(*serialized)); + if (!serialized) return NULL; + + /* Allocate and set observation point protobuf */ + pb = oms_report_set_node_info(); + if (pb == NULL) goto err_free_serialized; + + /* Get serialization length */ + len = object_manager__status__observation_point__get_packed_size(pb); + if (len == 0) goto err_free_pb; + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + if (buf == NULL) goto err_free_pb; + + /* Serialize protobuf */ + serialized->len = object_manager__status__observation_point__pack(pb, buf); + serialized->buf = buf; + + /* Free the protobuf structure */ + oms_report_free_pb_op(pb); + + return serialized; + +err_free_pb: + oms_report_free_pb_op(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + + +/** + * @brief Allocates and sets an object status report protobuf. + * + * Uses the state info to fill a dynamically allocated protobuf. + * The caller is responsible for freeing the returned pointer, + * @see oms_report_free_pb_report_status() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to a object status protobuf structure + */ +static ObjectManager__Status__ObjectStatus * +oms_report_set_report_status(struct oms_state_entry *state) +{ + ObjectManager__Status__ObjectStatus *pb; + struct oms_mgr *mgr; + bool report; + bool ret; + + mgr = oms_get_mgr(); + + /* Check if this entry is to be reported */ + report = true; + if (mgr->report_cb) report = mgr->report_cb(state); + if (!report) return NULL; + + /* Allocate the protobuf structure */ + pb = calloc(1, sizeof(*pb)); + if (pb == NULL) + { + LOGE("%s: memory allocation failure", __func__); + return NULL; + } + + /* Initialize the protobuf structure */ + object_manager__status__object_status__init(pb); + + ret = oms_report_str_duplicate(state->object, &pb->objectname); + if (!ret) goto err_free_pb; + + ret = oms_report_str_duplicate(state->state, &pb->status); + if (!ret) goto err_free_object; + + ret = oms_report_str_duplicate(state->version, &pb->version); + if (!ret) goto err_free_state; + return pb; + +err_free_state: + free(pb->status); + +err_free_object: + free(pb->objectname); + +err_free_pb: + free(pb); + + return NULL; +} + + +/** + * @brief Free a object status protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb flow stats structure to free + * @return none + */ +void +oms_report_free_pb_report_status(ObjectManager__Status__ObjectStatus *pb) +{ + if (pb == NULL) return; + + free(pb->objectname); + free(pb->status); + free(pb->version); + + free(pb); +} + + +/** + * @brief Generate an object status serialized protobuf. + * + * Uses the information pointed by the state parameter to generate + * a serialized object status report buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see oms_report_free_packed_buffer() for this purpose. + * + * @param state info used to fill up the protobuf. + * @return a pointer to the serialized data. + */ +struct packed_buffer * +oms_report_serialize_status(struct oms_state_entry *state) +{ + ObjectManager__Status__ObjectStatus *pb; + struct packed_buffer *serialized; + size_t len; + void *buf; + + if (state == NULL) return NULL; + + /* Allocate serialization output container */ + serialized = calloc(1, sizeof(*serialized)); + if (!serialized) return NULL; + + /* Allocate and set the i container */ + pb = oms_report_set_report_status(state); + if (pb == NULL) goto err_free_serialized; + + /* get serialization length */ + len = object_manager__status__object_status__get_packed_size(pb); + if (len == 0) goto err_free_pb; + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + if (!buf) goto err_free_pb; + + /* Serialize protobuf */ + serialized->len = object_manager__status__object_status__pack(pb, buf); + serialized->buf = buf; + + /* Free the protobuf structure */ + oms_report_free_pb_report_status(pb); + + /* Return the serialized content */ + return serialized; + +err_free_pb: + oms_report_free_pb_report_status(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + + +/** + * @brief Allocates and sets table of object status protobufs + * + * Uses the window info to fill a dynamically allocated + * table of object status protobufs. + * The caller is responsible for freeing the returned pointer + * + * @return a flow stats protobuf pointers table + */ +ObjectManager__Status__ObjectStatus ** +oms_report_set_object_status(void) +{ + ObjectManager__Status__ObjectStatus **status_pb_tbl; + ObjectManager__Status__ObjectStatus **status_pb; + struct oms_state_entry *state; + struct oms_mgr *mgr; + size_t allocated; + ds_tree_t *tree; + size_t n_nodes; + size_t i; + + mgr = oms_get_mgr(); + n_nodes = mgr->num_states; + if (n_nodes == 0) return NULL; + tree = &mgr->state; + + /* Allocate the array of interfaces */ + status_pb_tbl = calloc(mgr->num_states, sizeof(*status_pb_tbl)); + if (status_pb_tbl == NULL) + { + LOGE("%s: allocation failure", __func__); + return NULL; + } + + allocated = 0; + state = ds_tree_head(tree); + status_pb = status_pb_tbl; + while (state && allocated < n_nodes) + { + *status_pb = oms_report_set_report_status(state); + if (*status_pb != NULL) + { + status_pb++; + allocated++; + } + state = ds_tree_next(tree, state); + } + + if (allocated != 0) + { + mgr->num_reports = allocated; + return status_pb_tbl; + } + +err_free_pb_status_tbl: + status_pb = status_pb_tbl; + for (i = 0; i < allocated; i++) + { + oms_report_free_pb_report_status(*status_pb); + status_pb++; + } + + free(status_pb_tbl); + + return NULL; +} + + +/** + * @brief Allocates and sets a object manager status report protobuf. + * + * The caller is responsible for freeing the returned pointer, + * @see oms_report_free_pb_report() for this purpose. + * + * @param node info used to fill up the protobuf + * @return a pointer to a observation point protobuf structure + */ +static ObjectManager__Status__ObjectStatusReport * +oms_report_set_pb_report(void) +{ + ObjectManager__Status__ObjectStatusReport *pb; + struct oms_mgr *mgr; + + mgr = oms_get_mgr(); + + pb = calloc(1, sizeof(*pb)); + if (pb == NULL) + { + LOGE("%s: allocation failure", __func__); + return NULL; + } + + /* Initialize protobuf */ + object_manager__status__object_status_report__init(pb); + + /* Set protobuf fields */ + pb->reportedat = time(NULL); + pb->has_reportedat = true; + + pb->observationpoint = oms_report_set_node_info(); + if (!pb->observationpoint) goto err_free_pb_report; + + pb->objectstatus = oms_report_set_object_status(); + if (!pb->objectstatus) goto err_free_pb_os; + pb->n_objectstatus = mgr->num_reports; + + return pb; + +err_free_pb_os: + oms_report_free_pb_op(pb->observationpoint); + +err_free_pb_report: + free(pb); + + return NULL; +} + + +/** + * @brief Free an object status report protobuf structure. + * + * Free dynamically allocated fields and the protobuf structure. + * + * @param pb flow report structure to free + * @return none + */ +static void +oms_report_free_pb_report(ObjectManager__Status__ObjectStatusReport *pb) +{ + size_t i; + + if (pb == NULL) return; + + oms_report_free_pb_op(pb->observationpoint); + + for (i = 0; i < pb->n_objectstatus; i++) + { + oms_report_free_pb_report_status(pb->objectstatus[i]); + } + + free(pb->objectstatus); + free(pb); + + return; +} + + +/** + * @brief Generates a flow report serialized protobuf + * + * Uses the information pointed by the report parameter to generate + * a serialized flow report buffer. + * The caller is responsible for freeing to the returned serialized data, + * @see oms_report_free_packed_buffer() for this purpose. + * + * @param node info used to fill up the protobuf. + * @return a pointer to the serialized data. + */ +struct packed_buffer * +oms_report_serialize_report(void) +{ + ObjectManager__Status__ObjectStatusReport *pb; + struct packed_buffer *serialized; + struct oms_mgr *mgr; + size_t len; + void *buf; + + mgr = oms_get_mgr(); + mgr->num_reports = 0; + + /* Allocate serialization output structure */ + serialized = calloc(1,sizeof(*serialized)); + if (serialized == NULL) + { + LOGE("%s: packed_buffer memory allocation failed", __func__); + return NULL; + } + + /* Allocate and set the object status report protobuf */ + pb = oms_report_set_pb_report(); + if (pb == NULL) goto err_free_serialized; + + /* Get serialized length */ + len = object_manager__status__object_status_report__get_packed_size(pb); + if (len == 0) + { + LOGE("%s: Failed to get serialized report len", __func__); + goto err_free_pb; + } + + /* Allocate space for the serialized buffer */ + buf = malloc(len); + if (buf == NULL) + { + LOGE("%s: failed to allocate serialized buf", __func__); + goto err_free_pb; + } + + len = object_manager__status__object_status_report__pack(pb, buf); + serialized->len = len; + serialized->buf = buf; + + /* Free the protobuf structure */ + oms_report_free_pb_report(pb); + + return serialized; + +err_free_pb: + free(pb); + +err_free_serialized: + free(serialized); + + return NULL; +} + + +/** + * @brief Frees the pointer to serialized data and container + * + * Frees the dynamically allocated pointer to serialized data (pb->buf) + * and the container (pb). + * + * @param pb a pointer to a serialized data container + * @return none + */ +void +oms_report_free_packed_buffer(struct packed_buffer *pb) +{ + if (pb == NULL) return; + + free(pb->buf); + free(pb); +} + + +/** + * @brief Prepares the serialized object status report and sends it over mqtt + * + * Converts the object status report information into serialized content, and + * sends it over MQTT. + * + * @param mqtt_topic a pointer to the mqtt topic + * @return result of mqtt send + */ +bool +oms_report_send_report(char *mqtt_topic) +{ + struct packed_buffer *pb; + qm_response_t res; + bool ret; + + if (mqtt_topic == NULL) + { + LOGE("%s: MQTT topic is NULL", __func__); + return false; + } + + pb = oms_report_serialize_report(); + if (pb == NULL) + { + LOGE("%s: report serialization failed", __func__); + return false; + } + + ret = qm_conn_send_direct(QM_REQ_COMPRESS_IF_CFG, mqtt_topic, + pb->buf, pb->len, &res); + + /* Free the serialized container */ + oms_report_free_packed_buffer(pb); + + return ret; +} diff --git a/src/lib/oms/unit.mk b/src/lib/oms/unit.mk new file mode 100644 index 00000000..bcf7e4eb --- /dev/null +++ b/src/lib/oms/unit.mk @@ -0,0 +1,50 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################### +# +# Object management state library +# +############################################################################### +UNIT_NAME := oms +UNIT_DISABLE := n + +UNIT_TYPE := LIB +UNIT_DIR := lib + +UNIT_SRC := src/oms.c +UNIT_SRC += src/oms_ovsdb.c +UNIT_SRC += src/oms_report.c +UNIT_SRC += src/object_manager.pb-c.c + +UNIT_CFLAGS := -I$(UNIT_PATH)/inc +UNIT_LDFLAGS := -lprotobuf-c + +UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS) +UNIT_EXPORT_LDFLAGS := $(UNIT_LDFLAGS) + +UNIT_DEPS += src/lib/log +UNIT_DEPS += src/lib/ds +UNIT_DEPS += src/lib/ovsdb +UNIT_DEPS += src/lib/common diff --git a/src/lib/oms/update_proto.sh b/src/lib/oms/update_proto.sh new file mode 100755 index 00000000..4eef597b --- /dev/null +++ b/src/lib/oms/update_proto.sh @@ -0,0 +1,49 @@ + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################### +# update protobuf c files based on object manager protobuf description +############################################################################### + +RELDIR=$(basename $(dirname $PWD))/$(basename $PWD) +PROTOCC=`which protoc-c` + +if [ $RELDIR != "lib/oms" ] +then + echo "Please cd to src/lib/oms folder" + exit 1 +fi + +FNAME=object_manager +$PROTOCC --c_out=. --proto_path=../../../interfaces ../../../interfaces/${FNAME}.proto +mv "${FNAME}.pb-c.c" src/ +mv "${FNAME}.pb-c.h" inc/ + +if [ $? -ne 0 ] +then + echo "Error generating protobuf c files" +else + echo "protobuf update successfully completed" +fi diff --git a/src/lib/oms/ut/test_oms.c b/src/lib/oms/ut/test_oms.c new file mode 100644 index 00000000..03bc702d --- /dev/null +++ b/src/lib/oms/ut/test_oms.c @@ -0,0 +1,844 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "ds_tree.h" +#include "log.h" +#include "oms.h" +#include "oms_report.h" +#include "ovsdb.h" +#include "os.h" +#include "os_types.h" +#include "qm_conn.h" +#include "schema.h" +#include "target.h" +#include "unity.h" + + + +const char *test_name = "oms_tests"; + +/** + * @brief a set of config entries as would be delivered through ovsdb + */ +static struct +schema_OMS_Config g_confs[] = +{ + { + .object_name = "test_object_1", + .object_name_present = true, + .version = "9999.8888", + .version_present = true, + .other_config_present = false, + }, +}; + + +/** + * @brief a set of state entries as would be delivered through ovsdb + */ +static struct +schema_Object_Store_State g_states[] = +{ + { + .name = "test_object_1", + .name_present = true, + .version = "9999.8888", + .version_present = true, + .status = "active", + .status_present = true, + }, + { + .name = "test_object_2", + .name_present = true, + .version = "9999.8888.7", + .version_present = true, + .status = "error", + .status_present = true, + }, + { + .name = "test_object_3", + .name_present = true, + .version = "9999.8888.7777", + .version_present = true, + .status = "active", + .status_present = true, + } +}; + + +struct test_timers +{ + ev_timer timeout_watcher_add; /* Add entries */ + ev_timer timeout_watcher_validate_add; /* Validate added entries */ + ev_timer timeout_watcher_delete; /* Delete entries */ + ev_timer timeout_watcher_validate_delete; /* Validate added entries */ + ev_timer timeout_watcher_update; /* Update entries */ + ev_timer timeout_watcher_validate_update; /* Validate updated entries */ +}; + + +struct test_mgr +{ + struct ev_loop *loop; + ev_timer timeout_watcher; + bool has_ovsdb; + bool has_qm; + bool expected; + struct test_timers oms_config_test; + struct test_timers oms_state_test; + double g_timeout; + char *mqtt_topic; +} g_test_mgr; + + +/** + * @brief breaks the ev loop to terminate a test + */ +static void +timeout_cb(EV_P_ ev_timer *w, int revents) +{ + ev_break(EV_A_ EVBREAK_ONE); +} + + +#if !defined(__x86_64__) +/** + * @brief called by the unity framework at the start of each test + */ +int +oms_ovsdb_test_setup(void) +{ + int rc; + + /* Connect to ovsdb */ + rc = ovsdb_init_loop(g_test_mgr.loop, test_name); + if (!rc) + { + LOGE("%s: Failed to initialize OVSDB", __func__); + return -1; + } + + g_test_mgr.has_ovsdb = true; + return 0; +} + +#else +int oms_ovsdb_test_setup(void) +{ + g_test_mgr.has_ovsdb = false; + return 0; +} +#endif + + +int +oms_ev_test_setup(double timeout) +{ + ev_timer *p_timeout_watcher; + + /* Set up the timer killing the ev loop, indicating the end of the test */ + p_timeout_watcher = &g_test_mgr.timeout_watcher; + + ev_timer_init(p_timeout_watcher, timeout_cb, timeout, 0.); + ev_timer_start(g_test_mgr.loop, p_timeout_watcher); + + return 0; +} + + +bool +accept_id_test(const char *object) +{ + return true; +} + + +void +config_cb_test(struct oms_config_entry *entry, int event) +{ + LOGI("%s: object: %s, event: %d", __func__, + entry->object, event); +} + + +void +state_cb_test(struct oms_state_entry *entry, int event) +{ + LOGI("%s: object: %s, event: %d", __func__, + entry->object, event); +} + + +bool +report_cb_test(struct oms_state_entry *entry) +{ + bool ret; + int rc; + + rc = strcmp("error", entry->state); + ret = (rc != 0); + LOGI("%s: object: %s, state: %s, reporting: %s", __func__, + entry->object, entry->state, ret ? "true" : "false"); + + return ret; +} + + +void +oms_global_test_setup(void) +{ + struct oms_ovsdb_set oms_set; + struct oms_mgr *mgr; + int rc; + + g_test_mgr.has_ovsdb = false; + g_test_mgr.loop = EV_DEFAULT; + g_test_mgr.g_timeout = 1.0; + rc = oms_ovsdb_test_setup(); + TEST_ASSERT_EQUAL_INT(0, rc); + +#if !defined(ARCH_X86) + g_test_mgr.has_qm = true; +#else + g_test_mgr.has_qm = false; +#endif + + g_test_mgr.mqtt_topic = strdup("dev-ut/object_status_report"); + TEST_ASSERT_NOT_NULL(g_test_mgr.mqtt_topic); + + oms_init_manager(); + memset(&oms_set, 0, sizeof(oms_set)); + oms_set.monitor_config = g_test_mgr.has_ovsdb; + oms_set.monitor_state = g_test_mgr.has_ovsdb; + oms_set.monitor_awlan = g_test_mgr.has_ovsdb; + oms_set.accept_id = accept_id_test; + oms_set.config_cb = config_cb_test; + oms_set.state_cb = state_cb_test; + oms_set.report_cb = report_cb_test; + oms_ovsdb_init(&oms_set); + + mgr = oms_get_mgr(); + mgr->node_id = "4C718002B3"; + mgr->location_id = "59f39f5acbb22513f0ae5e17"; +} + + +/** + * @brief sends a serialized buffer over MQTT + * + * @param pb serialized buffer + */ +static void +oms_test_emit_report(struct packed_buffer *pb) +{ + qm_response_t res; + bool ret; + + if (!g_test_mgr.has_qm) return; + + ret = qm_conn_send_direct(QM_REQ_COMPRESS_IF_CFG, + g_test_mgr.mqtt_topic, + pb->buf, pb->len, &res); + TEST_ASSERT_TRUE(ret); +} + +void +oms_global_test_teardown(void) +{ + g_test_mgr.has_ovsdb = false; +} + + +void +setUp(void) +{} + + +void +tearDown(void) +{} + + +void +test_ovsdb_add_config(void) +{ + struct schema_OMS_Config *config; + struct oms_config_entry *entry; + struct oms_config_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + tree = &mgr->config; + + config = &g_confs[0]; + oms_ovsdb_add_config_entry(config); + + lookup.object = config->object_name; + lookup.version = config->version; + + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NOT_NULL(entry); + + /* Clean up */ + oms_delete_config_entries(); +} + + +void +test_ovsdb_add_state(void) +{ + struct schema_Object_Store_State *state; + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + + mgr = oms_get_mgr(); + tree = &mgr->state; + + state = &g_states[0]; + oms_ovsdb_add_state_entry(state); + + /* Validate the number of states */ + TEST_ASSERT_EQUAL_UINT(1, mgr->num_states); + + lookup.object = state->name; + lookup.version = state->version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NOT_NULL(entry); + + /* Clean up */ + oms_delete_state_entries(); + + /* Validate the number of states */ + TEST_ASSERT_EQUAL_UINT(0, mgr->num_states); +} + + +void +test_add_and_delete_config_entry(void) +{ + struct oms_config_entry entry; + + if (!g_test_mgr.has_ovsdb) return; + + memset(&entry, 0, sizeof(entry)); + + entry.object = "dpi signatures"; + entry.version = "1.0.1"; + + oms_add_config_entry(&entry); + + oms_delete_config_entry(&entry); +} + + +void +test_add_and_delete_state_entry(void) +{ + struct oms_state_entry entry; + + if (!g_test_mgr.has_ovsdb) return; + + memset(&entry, 0, sizeof(entry)); + + entry.object = "dpi signatures"; + entry.version = "1.0.1"; + entry.state = "active"; + + oms_add_state_entry(&entry); + + oms_delete_state_entry(&entry); +} + + +void +add_config_cb(EV_P_ ev_timer *w, int revents) +{ + char *version; + char cmd[256]; + char *object; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + + object = "ut"; + version = "1.99.0"; + + memset(cmd, 0 , sizeof(cmd)); + snprintf(cmd, sizeof(cmd), + "ovsh i OMS_Config " + "object_name:=%s " + "version:=%s", + object, version); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +lookup_added_config_cb(EV_P_ ev_timer *w, int revents) +{ + struct oms_config_entry *entry; + struct oms_config_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *version; + char *object; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr = oms_get_mgr(); + tree = &mgr->config; + + object = "ut"; + version = "1.99.0"; + + lookup.object = object; + lookup.version = version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NOT_NULL(entry); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +delete_config_cb(EV_P_ ev_timer *w, int revents) +{ + char *version; + char cmd[256]; + char *object; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + + object = "ut"; + version = "1.99.0"; + + memset(cmd, 0 , sizeof(cmd)); + snprintf(cmd, sizeof(cmd), + "ovsh d OMS_Config " + "-w object_name==%s " + "-w version==%s", + object, version); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +lookup_deleted_config_cb(EV_P_ ev_timer *w, int revents) +{ + struct oms_config_entry *entry; + struct oms_config_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *version; + char *object; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr = oms_get_mgr(); + tree = &mgr->config; + object = "ut"; + version = "1.99.0"; + + lookup.object = object; + lookup.version = version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NULL(entry); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +setup_config_event_tests(void) +{ + struct test_timers *t; + struct ev_loop *loop; + + if (!g_test_mgr.has_ovsdb) + { + LOGI("%s: ovsdb support, bypassing test", __func__); + return; + } + + t = &g_test_mgr.oms_config_test; + loop = g_test_mgr.loop; + + /* Arm the addition execution timer */ + ev_timer_init(&t->timeout_watcher_add, + add_config_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_add.data = NULL; + + /* Arm the cache lookup execution timer validating the cache addition */ + ev_timer_init(&t->timeout_watcher_validate_add, + lookup_added_config_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_validate_add.data = NULL; + + /* Arm the deletion execution timer */ + ev_timer_init(&t->timeout_watcher_delete, + delete_config_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_delete.data = NULL; + + /* Arm the cache lookup execution timer validating the cache deletion */ + ev_timer_init(&t->timeout_watcher_validate_delete, + lookup_deleted_config_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_validate_delete.data = NULL; + + ev_timer_start(loop, &t->timeout_watcher_add); + ev_timer_start(loop, &t->timeout_watcher_validate_add); + ev_timer_start(loop, &t->timeout_watcher_delete); + ev_timer_start(loop, &t->timeout_watcher_validate_delete); +} + + +void +add_state_cb(EV_P_ ev_timer *w, int revents) +{ + char *version; + char cmd[256]; + char *object; + char *state; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + + object = "ut"; + version = "1.100.0"; + state = "install-done"; + + memset(cmd, 0 , sizeof(cmd)); + snprintf(cmd, sizeof(cmd), + "ovsh i Object_Store_State " + "name:=%s " + "version:=%s " + "status:=%s", + object, version, state); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +lookup_added_state_cb(EV_P_ ev_timer *w, int revents) +{ + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *version; + char *object; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr = oms_get_mgr(); + tree = &mgr->state; + + object = "ut"; + version = "1.100.0"; + + lookup.object = object; + lookup.version = version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NOT_NULL(entry); + TEST_ASSERT_EQUAL_STRING("install-done", entry->state); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +update_state_cb(EV_P_ ev_timer *w, int revents) +{ + char *version; + char cmd[256]; + char *object; + char *state; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + + object = "ut"; + version = "1.100.0"; + state = "active"; + + memset(cmd, 0 , sizeof(cmd)); + snprintf(cmd, sizeof(cmd), + "ovsh u Object_Store_State " + "-w name==%s " + "-w version==%s " + "status:=%s", + object, version, state); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +lookup_updated_state_cb(EV_P_ ev_timer *w, int revents) +{ + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *version; + char *object; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr = oms_get_mgr(); + tree = &mgr->state; + + object = "ut"; + version = "1.100.0"; + + lookup.object = object; + lookup.version = version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NOT_NULL(entry); + TEST_ASSERT_EQUAL_STRING("install-done", entry->prev_state); + TEST_ASSERT_EQUAL_STRING("active", entry->state); + LOGI("\n***** %s: done\n", __func__); +} + + +void +delete_state_cb(EV_P_ ev_timer *w, int revents) +{ + char *version; + char cmd[256]; + char *object; + int rc; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + + object = "ut"; + version = "1.100.0"; + + memset(cmd, 0 , sizeof(cmd)); + snprintf(cmd, sizeof(cmd), + "ovsh d Object_Store_State " + "-w name==%s " + "-w version==%s", + object, version); + rc = cmd_log(cmd); + TEST_ASSERT_EQUAL_INT(0, rc); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +lookup_deleted_state_cb(EV_P_ ev_timer *w, int revents) +{ + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct oms_mgr *mgr; + ds_tree_t *tree; + char *version; + char *object; + + LOGI("\n\n\n\n ***** %s: entering\n", __func__); + mgr = oms_get_mgr(); + tree = &mgr->state; + object = "ut"; + version = "1.100.0"; + + lookup.object = object; + lookup.version = version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NULL(entry); + + LOGI("\n***** %s: done\n", __func__); +} + + +void +setup_state_event_tests(void) +{ + struct test_timers *t; + struct ev_loop *loop; + + if (!g_test_mgr.has_ovsdb) + { + LOGI("%s: ovsdb support, bypassing test", __func__); + return; + } + + t = &g_test_mgr.oms_state_test; + loop = g_test_mgr.loop; + + /* Arm the addition execution timer */ + ev_timer_init(&t->timeout_watcher_add, + add_state_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_add.data = NULL; + + /* Arm the cache lookup execution timer validating the cache addition */ + ev_timer_init(&t->timeout_watcher_validate_add, + lookup_added_state_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_validate_add.data = NULL; + + /* Arm the update execution timer */ + ev_timer_init(&t->timeout_watcher_update, + update_state_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_update.data = NULL; + + /* Arm the cache lookup execution timer validating the cache addition */ + ev_timer_init(&t->timeout_watcher_validate_update, + lookup_updated_state_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_validate_update.data = NULL; + + /* Arm the deletion execution timer */ + ev_timer_init(&t->timeout_watcher_delete, + delete_state_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_delete.data = NULL; + + /* Arm the cache lookup execution timer validating the cache deletion */ + ev_timer_init(&t->timeout_watcher_validate_delete, + lookup_deleted_state_cb, + g_test_mgr.g_timeout++, 0); + t->timeout_watcher_validate_delete.data = NULL; + + ev_timer_start(loop, &t->timeout_watcher_add); + ev_timer_start(loop, &t->timeout_watcher_validate_add); + ev_timer_start(loop, &t->timeout_watcher_update); + ev_timer_start(loop, &t->timeout_watcher_validate_update); + ev_timer_start(loop, &t->timeout_watcher_delete); + ev_timer_start(loop, &t->timeout_watcher_validate_delete); +} + + +void +test_events(void) +{ + if (!g_test_mgr.has_ovsdb) return; + + setup_config_event_tests(); + setup_state_event_tests(); + + /* Test overall test duration */ + oms_ev_test_setup(++g_test_mgr.g_timeout); + + /* Start the main loop */ + ev_run(g_test_mgr.loop, 0); +} + + +void +test_serialize_report(void) +{ + struct schema_Object_Store_State *state; + struct oms_state_entry *entry; + struct oms_state_entry lookup; + struct packed_buffer *pb; + struct oms_mgr *mgr; + ds_tree_t *tree; + size_t nelems; + size_t i; + + mgr = oms_get_mgr(); + tree = &mgr->state; + + /* Populate the states */ + nelems = sizeof(g_states) / sizeof(g_states[0]); + for (i = 0; i < nelems; i++) + { + state = &g_states[i]; + oms_ovsdb_add_state_entry(state); + + lookup.object = state->name; + lookup.version = state->version; + entry = ds_tree_find(tree, &lookup); + TEST_ASSERT_NOT_NULL(entry); + } + + /* Validate the number of states */ + TEST_ASSERT_EQUAL_UINT(nelems, mgr->num_states); + + pb = oms_report_serialize_report(); + TEST_ASSERT_NOT_NULL(pb); + TEST_ASSERT_NOT_NULL(pb->buf); + + /* Validate the number of states to report (state == 3 filtered out) */ + TEST_ASSERT_EQUAL_UINT(nelems - 1, mgr->num_reports); + + oms_test_emit_report(pb); + + /* Clean up */ + oms_report_free_packed_buffer(pb); + oms_delete_state_entries(); +} + + +int +main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + target_log_open("TEST", LOG_OPEN_STDOUT); + log_severity_set(LOG_SEVERITY_TRACE); + + UnityBegin(test_name); + + oms_global_test_setup(); + + RUN_TEST(test_ovsdb_add_config); + RUN_TEST(test_ovsdb_add_state); + RUN_TEST(test_add_and_delete_config_entry); + RUN_TEST(test_add_and_delete_state_entry); + RUN_TEST(test_serialize_report); + RUN_TEST(test_events); + + oms_global_test_teardown(); + + return UNITY_END(); +} diff --git a/src/lib/oms/ut/unit.mk b/src/lib/oms/ut/unit.mk new file mode 100644 index 00000000..e680943e --- /dev/null +++ b/src/lib/oms/ut/unit.mk @@ -0,0 +1,47 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_DISABLE := n + +UNIT_NAME := test_oms + +UNIT_TYPE := TEST_BIN + +UNIT_SRC := test_oms.c + +UNIT_CFLAGS := -I$(UNIT_PATH)/../inc +UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS) + +UNIT_LDFLAGS := -lev -ljansson +UNIT_EXPORT_LDFLAGS := $(UNIT_LDFLAGS) + + +UNIT_DEPS := src/lib/log +UNIT_DEPS += src/lib/osa +UNIT_DEPS += src/lib/const +UNIT_DEPS += src/lib/common +UNIT_DEPS += src/lib/ovsdb +UNIT_DEPS += src/lib/unity +UNIT_DEPS += src/lib/oms + diff --git a/src/lib/osa/inc/os_backtrace.h b/src/lib/osa/inc/os_backtrace.h index ca6351d3..69adef39 100644 --- a/src/lib/osa/inc/os_backtrace.h +++ b/src/lib/osa/inc/os_backtrace.h @@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /** - * Executables that want to take advantage of backtracing should be compiled with -fasnychronous-unwind-tables + * Executables that want to take advantage of backtracing should be compiled with -fasynchronous-unwind-tables * and linked with -rdynamic to get the best results. * * Executables with debug symbols can be used post-mortem to get more accurate information about the stack trace; diff --git a/src/lib/osa/src/os_nif_linux.c b/src/lib/osa/src/os_nif_linux.c index 30db5c8b..4e8adb27 100644 --- a/src/lib/osa/src/os_nif_linux.c +++ b/src/lib/osa/src/os_nif_linux.c @@ -48,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "os_util.h" #include "os_regex.h" #include "target.h" +#include "osp_unit.h" #include "build_version.h" #define MODULE_ID LOG_MODULE_ID_OSA @@ -782,10 +783,10 @@ bool os_nif_dhcpc_start(char* ifname, bool apply, int dhcp_time) } /* read SERIAL number & SKU, inputs for options 12 & 0xe */ - target_serial_get(serial_num, sizeof(serial_num)); + osp_unit_serial_get(serial_num, sizeof(serial_num)); /* read SKU number, if empty, reset buffer */ - if (false == target_sku_get(sku_num, sizeof(sku_num))) + if (false == osp_unit_sku_get(sku_num, sizeof(sku_num))) { snprintf(hostname, sizeof(hostname), "hostname:%s_Pod", serial_num); } @@ -832,7 +833,7 @@ bool os_nif_dhcpc_start(char* ifname, bool apply, int dhcp_time) snprintf(serial_opt + len, sizeof(serial_opt) - len, "%02X", serial_num[i]); } - if (false == target_model_get(dhcp_vendor_class, sizeof(dhcp_vendor_class))) + if (false == osp_unit_model_get(dhcp_vendor_class, sizeof(dhcp_vendor_class))) { STRSCPY(dhcp_vendor_class, TARGET_NAME); } diff --git a/src/lib/osn/inc/osn_dhcp.h b/src/lib/osn/inc/osn_dhcp.h index 02e812ff..6aea8d30 100644 --- a/src/lib/osn/inc/osn_dhcp.h +++ b/src/lib/osn/inc/osn_dhcp.h @@ -24,8 +24,6 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - */ #ifndef OSN_DHCP_H_INCLUDED #define OSN_DHCP_H_INCLUDED diff --git a/src/lib/osn/inc/osn_dhcpv6.h b/src/lib/osn/inc/osn_dhcpv6.h index d3df00f0..a919c942 100644 --- a/src/lib/osn/inc/osn_dhcpv6.h +++ b/src/lib/osn/inc/osn_dhcpv6.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSN_DHCPV6_H_INCLUDED) +#ifndef OSN_DHCPV6_H_INCLUDED #define OSN_DHCPV6_H_INCLUDED #include "osn_inet6.h" diff --git a/src/lib/osn/inc/osn_fw.h b/src/lib/osn/inc/osn_fw.h index d81ccd7a..9e58f434 100644 --- a/src/lib/osn/inc/osn_fw.h +++ b/src/lib/osn/inc/osn_fw.h @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSN_FW_H_INCLUDED) +#ifndef OSN_FW_H_INCLUDED #define OSN_FW_H_INCLUDED #include @@ -126,4 +126,3 @@ bool osfw_rule_del(int family, enum osfw_table table, const char *chain, bool osfw_apply(void); #endif /* OSN_FW_H_INCLUDED */ - diff --git a/src/lib/osn/inc/osn_inet.h b/src/lib/osn/inc/osn_inet.h index e3a8d070..69369b9c 100644 --- a/src/lib/osn/inc/osn_inet.h +++ b/src/lib/osn/inc/osn_inet.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSN_INET_H_INCLUDED) +#ifndef OSN_INET_H_INCLUDED #define OSN_INET_H_INCLUDED #include diff --git a/src/lib/osn/inc/osn_inet6.h b/src/lib/osn/inc/osn_inet6.h index 2e9cbfd8..a2b9faa0 100644 --- a/src/lib/osn/inc/osn_inet6.h +++ b/src/lib/osn/inc/osn_inet6.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSN_INET6_H_INCLUDED) +#ifndef OSN_INET6_H_INCLUDED #define OSN_INET6_H_INCLUDED #include diff --git a/src/lib/osn/inc/osn_netif.h b/src/lib/osn/inc/osn_netif.h index c94128ca..0b6bfe8e 100644 --- a/src/lib/osn/inc/osn_netif.h +++ b/src/lib/osn/inc/osn_netif.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSN_NETIF_H_INCLUDED) +#ifndef OSN_NETIF_H_INCLUDED #define OSN_NETIF_H_INCLUDED #include @@ -250,4 +250,4 @@ bool osn_netif_hwaddr_set(osn_netif_t *self, osn_mac_addr_t hwaddr); /** @} OSN_L2 */ /** @} OSN */ -#endif /* OSN_NETIF_H_INCLUDED) */ +#endif /* OSN_NETIF_H_INCLUDED */ diff --git a/src/lib/osn/inc/osn_pppoe.h b/src/lib/osn/inc/osn_pppoe.h new file mode 100644 index 00000000..5081e93d --- /dev/null +++ b/src/lib/osn/inc/osn_pppoe.h @@ -0,0 +1,211 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSN_PPPOE_H_INCLUDED +#define OSN_PPPOE_H_INCLUDED + +#include + +#include "osn_types.h" + +/** + * @file osn_pppoe.h + * + * @brief OpenSync PPPoE Interface Abstraction + * + * @addtogroup OSN + * @{ + * + * @defgroup OSN_PPPOE PPPoE + * + * OpenSync API for managing PPPoE links + * + * @{ + */ + +/* + * =========================================================================== + * PPPoE interface configuration + * =========================================================================== + */ + +/** + * OSN PPPoE object type + * + * This is an opaque type. The actual structure implementation is hidden and is + * platform dependent. A new instance of the object can be obtained by calling + * @ref osn_pppoe_new() and must be destroyed using @ref osn_pppoe_del(). + */ +typedef struct osn_pppoe osn_pppoe_t; + +/** + * Create a new instance of a PPPoE interface object. + * + * @param[in] ifname Interface name of the PPPoE link + * + * @return + * This function returns NULL if an error occurs, otherwise a valid @ref + * osn_netif_t object is returned. + * + * @note + * The PPPoE interface may be created after osn_pppoe_apply() is called. + */ + +osn_pppoe_t *osn_pppoe_new(const char *ifname); + +/** + * Destroy a valid osn_pppoe_t object. + * + * @param[in] self A valid pointer to an osn_pppoe_t object + * + * @return + * This function returns true on success. On error, false is returned. + * The input parameter should be considered invalid after this function + * returns, regardless of the error code. + * + * @note + * All resources that were allocated during the lifetime of the object are + * freed. + */ +bool osn_pppoe_del(osn_pppoe_t *self); + +/** + * Set the parent interface; this interface will be used to create the PPPoE + * interface + * + * @param[in] self A valid pointer to an osn_pppoe_t object + * @param[in] parent_ifname The parent interface name + * + * This function must be called before osn_pppoe_apply(), otherwise the + * PPPoE interface creation will fail. + * + * If this function is called multiple times, previous values are overwritten. + * + * @return + * This function returns true on success. On error, false is returned. + */ +bool osn_pppoe_parent_set( + osn_pppoe_t *self, + const char *parent_ifname); + +/** + * Set credentials for this PPPoE connection. + * + * @param[in] self A valid pointer to an osn_pppoe_t object + * @param[in] username Username to be used during PAP/CHAP authentication + * @param[in] password Password to be used during PAP/CHAP authentication + * + * If this function is called multiple times, previous credentials are + * overwritten. + * + * @return + * This function returns true on success. On error, false is returned. + */ +bool osn_pppoe_secret_set( + osn_pppoe_t *self, + const char *username, + const char *password); + +/** + * Apply configuration to the system. + * + * This function applies the PPPoE data to the running system and creates the + * PPPoE interface. + * + * @note + * When this function returns, the running system may be still in an incomplete + * configuration state -- this function just ensures that the configuration + * process has started. + */ +bool osn_pppoe_apply(osn_pppoe_t *self); + +/* + * =========================================================================== + * Utility functions + * =========================================================================== + */ + +/** + * Set the object @p self user data. + * + * @param[in] self A valid pointer to an osn_pppoe_t object + * @param[in] data Pointer to user data + */ +void osn_pppoe_data_set(osn_pppoe_t *self, void *data); + +/** + * Get the object @p self user data. If no user data was set, NULL will + * be returned. + * + * @param[in] self A valid pointer to an osn_pppoe_t object + * + * @return + * Returns a pointer to user data previously set using @ref + * osn_pppoe_data_set(). + */ +void *osn_pppoe_data_get(osn_pppoe_t *self); + +/* + * =========================================================================== + * PPPoE status reporting + * =========================================================================== + */ + +/** + * PPPoE link status reporting structure. This structure is used as a parameter + * to a @ref osn_pppoe_status_fn_t type function. A status callback is typically + * registered with the osn_pppoe_status_notify() function. + */ +struct osn_pppoe_status +{ + const char *ps_ifname; /**< Interface name */ + bool ps_exists; /**< The PPPoE interface was created */ + bool ps_carrier; /**< The PPPoE interface is ready to send/receive packets */ + osn_ip_addr_t ps_local_ip; /**< Local IP address */ + osn_ip_addr_t ps_remote_ip; /**< Remote IP address */ + int ps_mtu; /**< MTU of the interface */ +}; + +/** + * Function callback type used for PPPoE status reporting. See + * @ref osn_pppoe_status_notify for more details. + */ +typedef void osn_pppoe_status_fn_t( + osn_pppoe_t *self, + struct osn_pppoe_status *status); + +/** + * Register a function callback that will be used for asynchronous PPPoE link + * status reporting. Depending on the implementation, the callback may be + * invoked before osn_pppoe_apply() is called (before the configuration is + * applied to the system). + */ +void osn_pppoe_status_notify(osn_pppoe_t *self, osn_pppoe_status_fn_t *fn); + +/** @} OSN_PPPOE */ +/** @} OSN */ + +#endif /* OSN_PPPOE_H_INCLUDED */ diff --git a/src/lib/osn/inc/osn_types.h b/src/lib/osn/inc/osn_types.h index e9b742fd..b0f7914b 100644 --- a/src/lib/osn/inc/osn_types.h +++ b/src/lib/osn/inc/osn_types.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSN_TYPES_H_INCLUDED) +#ifndef OSN_TYPES_H_INCLUDED #define OSN_TYPES_H_INCLUDED #include @@ -147,6 +147,17 @@ char* __FMT_osn_ip_addr(char *buf, size_t sz, const osn_ip_addr_t *addr); */ bool osn_ip_addr_from_str(osn_ip_addr_t *out, const char *str); +/** + * Initialize a osn_ip_addr_t structure from a in_addr structure. in_addr is + * commonly used hidden inside struct sockaddr + */ +bool osn_ip_addr_from_in_addr(osn_ip_addr_t *out, const struct in_addr *in); + +/** + * Initialize a son_ip_addr_t structure from a sockaddr structure. + */ +bool osn_ip_addr_from_sockaddr(osn_ip_addr_t *out, const struct sockaddr *in); + /** * Comparator for @ref osn_ip_addr_t structures. * diff --git a/src/lib/osn/inc/osn_upnp.h b/src/lib/osn/inc/osn_upnp.h index ebec22ba..b70c071b 100644 --- a/src/lib/osn/inc/osn_upnp.h +++ b/src/lib/osn/inc/osn_upnp.h @@ -39,7 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @defgroup OSN_UPNP UPnP * - * UPnP API definitions + * OpenSync UPnP API * * @{ */ diff --git a/src/lib/osn/inc/osn_vlan.h b/src/lib/osn/inc/osn_vlan.h new file mode 100644 index 00000000..c1c74daa --- /dev/null +++ b/src/lib/osn/inc/osn_vlan.h @@ -0,0 +1,144 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSN_VLAN_H_INCLUDED +#define OSN_VLAN_H_INCLUDED + +#include + +#include "osn_types.h" + +/** + * @file osn_vlan.h + * + * @brief OpenSync VLAN Interface Abstraction + * + * @addtogroup OSN + * @{ + * + * @defgroup OSN_VLAN VLAN + * + * OpenSync API for managing VLAN interfaces + * + * @{ + */ + +/* + * =========================================================================== + * VLAN interface configuration + * =========================================================================== + */ + +/** + * OSN VLAN object type + * + * This is an opaque type. The actual structure implementation is hidden and is + * platform dependent. A new instance of the object can be obtained by calling + * @ref osn_vlan_new() and must be destroyed using @ref osn_vlan_del(). + */ +typedef struct osn_vlan osn_vlan_t; + +/** + * Create a new instance of a VLAN interface object. + * + * @param[in] ifname VLAN interface name + * + * @return + * This function returns NULL if an error occurs, otherwise a valid @ref + * osn_vlan_t object is returned. + * + * @note + * The VLAN interface may be created after osn_vlan_apply() is called. + */ + +osn_vlan_t *osn_vlan_new(const char *ifname); + +/** + * Destroy a valid osn_vlan_t object. + * + * @param[in] self A valid pointer to an osn_vlan_t object + * + * @return + * This function returns true on success. On error, false is returned. + * The input parameter should be considered invalid after this function + * returns, regardless of the error code. + * + * @note + * All resources that were allocated during the lifetime of the object are + * freed. + */ +bool osn_vlan_del(osn_vlan_t *self); + +/** + * Apply the interface VLAN configuration to the system. If not already created, + * this function will create the VLAN interface. + * + * @note + * When this function returns, the running system may be still in an incomplete + * configuration state -- this function just ensures that the configuration + * process has started. + */ +bool osn_vlan_apply(osn_vlan_t *self); + +/** + * Set the parent interface; this interface will be used to create the VLAN + * interface + * + * @param[in] self A valid pointer to an osn_vlan_t object + * @param[in] parent_ifname The parent interface name + * + * This function must be called to set the parent interface name before + * osn_vlan_apply(), otherwise the VLAN interface creation will fail. + * + * If this function is called multiple times, previous values are overwritten. + * + * @return + * This function returns true on success. On error, false is returned. + */ +bool osn_vlan_parent_set( + osn_vlan_t *self, + const char *parent_ifname); + +/** + * Set the VLAN ID of the interface. + * + * @param[in] self A valid pointer to an osn_vlan_t object + * @param[in] vlanid The VLAN ID of the interface + * + * A valid VLAN ID must be set before osn_vlan_apply() can succeed. + * + * @return + * This function return true on success or false otherwise. On error, the + * previous value of the VLAN ID will be preserved. + */ +bool osn_vlan_vid_set( + osn_vlan_t *self, + int vlanid); + +/** @} OSN_VLAN */ +/** @} OSN */ + +#endif /* OSN_VLAN_H_INCLUDED */ diff --git a/src/lib/osn/kconfig/Kconfig.osn b/src/lib/osn/kconfig/Kconfig.osn index 7739b758..46976a8a 100644 --- a/src/lib/osn/kconfig/Kconfig.osn +++ b/src/lib/osn/kconfig/Kconfig.osn @@ -12,6 +12,8 @@ menuconfig OSN_LINUX_ENABLED - DHCPv6 client support (via odhcp6c) - Router Advertisement support (via dnsmasq) - UPnP support (via miniupnpd) + - PPPoE support (via pppd) + - VLAN support (via iproute2) if OSN_LINUX_ENABLED config OSN_LINUX_NETIF @@ -203,6 +205,19 @@ if OSN_LINUX_ENABLED files will be created. endif + config OSN_LINUX_PPPOE + bool "Linux pppd PPPoE support" + default y + help + PPPoE support using the pppd daemon and the rp-pppoe plug-in. + pppd version that supports the "ifname" config option is required. + + config OSN_LINUX_VLAN + bool "Linux VLAN interface support" + default y + help + VLAN support uses the iproute2 package to create VLAN interfaces + config OSN_LINUX_ROUTE bool "Linux routing table" default y diff --git a/src/lib/osn/kconfig/Kconfig.osn.pppoe_backend b/src/lib/osn/kconfig/Kconfig.osn.pppoe_backend new file mode 100644 index 00000000..0b24a5e7 --- /dev/null +++ b/src/lib/osn/kconfig/Kconfig.osn.pppoe_backend @@ -0,0 +1,13 @@ +config OSN_BACKEND_PPPOE_NULL + bool "Null" + help + Use dummy PPPoE implementation for platforms that do not support it. + +config OSN_BACKEND_PPPOE_LINUX + bool "Linux" + select OSN_LINUX_ENABLED + select OSN_LINUX_PPPOE + help + Use the Linux PPPoE implementation that uses the pppd daemon and the + rp-pppoe plug-in. + diff --git a/src/lib/osn/kconfig/Kconfig.osn.vlan_backend b/src/lib/osn/kconfig/Kconfig.osn.vlan_backend new file mode 100644 index 00000000..3cbd9cbd --- /dev/null +++ b/src/lib/osn/kconfig/Kconfig.osn.vlan_backend @@ -0,0 +1,14 @@ +config OSN_BACKEND_VLAN_NULL + bool "Null" + help + Use dummy VLAN implementation for platforms where VLAN functionality is + not desired or not supported. + +config OSN_BACKEND_VLAN_LINUX + bool "Linux" + select OSN_LINUX_ENABLED + select OSN_LINUX_VLAN + help + Use the Linux VLAN implementation that uses the iproute2 tool to create + VLAN interfaces. + diff --git a/src/lib/osn/src/linux/lnx_ip.c b/src/lib/osn/src/linux/lnx_ip.c index 44cee602..8d27e2e8 100644 --- a/src/lib/osn/src/linux/lnx_ip.c +++ b/src/lib/osn/src/linux/lnx_ip.c @@ -52,6 +52,7 @@ struct lnx_ip_route_gw_node static bool lnx_ip_addr_flush(lnx_ip_t *self); static bool lnx_ip_route_flush(lnx_ip_t *self); +static void lnx_ip_status_poll(lnx_ip_t *self); /* execsh commands */ static char lnx_ip_addr_add_cmd[] = _S(ip address add "$2/$3" broadcast "+" dev "$1"); @@ -102,12 +103,6 @@ bool lnx_ip_init(lnx_ip_t *self, const char *ifname) lnx_netlink_set_events(&self->ip_nl, LNX_NETLINK_IP4ADDR); lnx_netlink_set_ifname(&self->ip_nl, self->ip_ifname); - if (!lnx_netlink_start(&self->ip_nl)) - { - LOG(ERR, "ip: %s: Unable to start netlink object.", self->ip_ifname); - return false; - } - return true; } @@ -375,6 +370,21 @@ bool lnx_ip_dns_del(lnx_ip_t *ip, const osn_ip_addr_t *addr) void lnx_ip_status_notify(lnx_ip_t *self, lnx_ip_status_fn_t *fn) { self->ip_status_fn = fn; + + if (fn != NULL) + { + if (!lnx_netlink_start(&self->ip_nl)) + { + LOG(WARN, "ip: %s: Unable to start netlink object.", self->ip_ifname); + } + } + else + { + if (!lnx_netlink_stop(&self->ip_nl)) + { + LOG(WARN, "ip: %s: Unable to stop netlink object.", self->ip_ifname); + } + } } /* diff --git a/src/lib/osn/src/linux/lnx_ip.h b/src/lib/osn/src/linux/lnx_ip.h index 91b6132b..91933966 100644 --- a/src/lib/osn/src/linux/lnx_ip.h +++ b/src/lib/osn/src/linux/lnx_ip.h @@ -24,12 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * =========================================================================== - * Linux backend for the OSN IP API - * =========================================================================== - */ -#if !defined(LNX_IP_H_INCLUDED) +#ifndef LNX_IP_H_INCLUDED #define LNX_IP_H_INCLUDED #include @@ -40,6 +35,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "const.h" #include "lnx_netlink.h" +/* + * =========================================================================== + * Linux backend for the OSN IP API + * =========================================================================== + */ + typedef struct lnx_ip lnx_ip_t; typedef void lnx_ip_status_fn_t(lnx_ip_t *ip, struct osn_ip_status *status); diff --git a/src/lib/osn/src/linux/lnx_netif.c b/src/lib/osn/src/linux/lnx_netif.c index 51bd3353..28b146aa 100644 --- a/src/lib/osn/src/linux/lnx_netif.c +++ b/src/lib/osn/src/linux/lnx_netif.c @@ -79,13 +79,6 @@ bool lnx_netif_init(lnx_netif_t *self, const char *ifname) lnx_netlink_set_ifname(&self->ni_netlink, self->ni_ifname); lnx_netlink_set_events(&self->ni_netlink, LNX_NETLINK_LINK); - /* Start polling the interface status immediately */ - if (!lnx_netlink_start(&self->ni_netlink)) - { - LOG(ERR, "netif: %s: Error starting netlink object.", ifname); - return false; - } - return true; } @@ -212,11 +205,22 @@ void lnx_netif_status_notify(lnx_netif_t *self, lnx_netif_status_fn_t *fn) { self->ni_status_fn = fn; - /* - * Polling the interface right will cause the callback to be called before - * osn_netif_status_notify() actually returns - */ - lnx_netif_status_poll(self); + if (fn != NULL) + { + /* Start polling the interface status immediately */ + if (!lnx_netlink_start(&self->ni_netlink)) + { + LOG(WARN, "netif: %s: Error stopping netlink object.", self->ni_ifname); + } + } + else + { + /* Start polling the interface status immediately */ + if (!lnx_netlink_stop(&self->ni_netlink)) + { + LOG(WARN, "netif: %s: Error starting netlink object.", self->ni_ifname); + } + } } diff --git a/src/lib/osn/src/linux/lnx_netlink.c b/src/lib/osn/src/linux/lnx_netlink.c index f7a7b255..b092ea33 100644 --- a/src/lib/osn/src/linux/lnx_netlink.c +++ b/src/lib/osn/src/linux/lnx_netlink.c @@ -101,6 +101,12 @@ bool lnx_netlink_start(lnx_netlink_t *self) self->nl_active = true; ds_dlist_insert_tail(&lnx_netlink_list, self); + /* + * Immediately dispatch an event -- this ensures that at least 1 event is + * received by the listener and that it is received sooner rather than later + */ + lnx_netlink_dispatch(self->nl_events, self->nl_ifname); + exit: return self->nl_active; } diff --git a/src/lib/osn/src/linux/lnx_pppoe.c b/src/lib/osn/src/linux/lnx_pppoe.c new file mode 100644 index 00000000..013cb389 --- /dev/null +++ b/src/lib/osn/src/linux/lnx_pppoe.c @@ -0,0 +1,481 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include +#include +#include +#include + +#include "const.h" +#include "ds_tree.h" +#include "log.h" +#include "osa_assert.h" +#include "osn_types.h" +#include "util.h" + +#include "lnx_pppoe.h" +#include "lnx_netlink.h" + +#define LNX_PPPOE_PPP_DIR "/tmp/ppp" +#define LNX_PPPOE_PEERS_DIR "/tmp/ppp/peers" +#define LNX_PPPOE_PAP_SECRETS "/tmp/ppp/pap-secrets" +#define LNX_PPPOE_CHAP_SECRETS "/tmp/ppp/chap-secrets" + +/* Template for the "peers" (config) file */ +const char lnx_pppoe_peers_template[] = + "#\n" + "# Autogenerated, do not edit.\n" + "#\n" + "# Persist at acquiring the connection\n" + "persist\n" + "# Acquire IP from peer\n" + "noipdefault\n" + "# Add default route to peer when link is up\n" + "defaultroute\n" + "# Hide passwords when logging\n" + "hide-password\n" + "# Enable the PPPoE plug-in\n" + "plugin rp-pppoe.so %s\n" + "# Peer is not required to authenticate (we're the client, not the server)\n" + "noauth\n" + "# Interface name\n" + "ifname %s\n" + "# Remote name\n" + "remotename %s\n" + "# Get DNS settings from the peer\n" + "usepeerdns\n" + "# Disable VJ TCP/IP header compression\n" + "novj\n" + "# Disable BSD compression\n" + "nobsdcomp\n" + "# Do not fork into background\n" + "nodetach\n" + "# Log to file descriptor 2 (stderr)\n" + "logfd 2\n" + "# IPv6 support\n" + "+ipv6\n" + "ipv6cp-use-persistent\n" + "# Enable debug logging\n" + "debug\n"; + +const char lnx_pppoe_peers_template_username[] = + "# Username to use\n" + "user \"%s\"\n"; +/* + * A structure representing a single PPP "secret". A secret is a + * username/password pair. Secrets must be written to a global file, which is + * shared by all pppd instances. There's no option to have a per pppd instance + * file and this is also the reason we must cache this in memory. + * + * TODO: Verify username/password maximum length. + */ +struct lnx_pppoe_secret +{ + char *ps_remote; /**< Remote specifier */ + char ps_username[128]; /**< PPP username */ + char ps_password[128]; /**< PPP password */ + ds_tree_node_t ps_tnode; /**< Tree node structure */ +}; + +static ds_tree_t lnx_pppoe_secrets = DS_TREE_INIT(ds_str_cmp, struct lnx_pppoe_secret, ps_tnode); + +static void lnx_pppoe_secret_del(lnx_pppoe_t *self); +static void lnx_pppoe_secret_update(void); +static bool lnx_pppoe_secret_write(const char *secret_file); +static bool lnx_pppoe_peers_write(lnx_pppoe_t *self); + +static void lnx_pppoe_status_poll(lnx_pppoe_t *self); +static lnx_netlink_fn_t lnx_pppoe_netlink_fn; +static bool lnx_pppoe_ifreq(const char *ifname, int cmd, struct ifreq *req); + +bool lnx_pppoe_init(lnx_pppoe_t *self, const char *ifname) +{ + memset(self, 0, sizeof(*self)); + + if (mkdir(LNX_PPPOE_PPP_DIR, 0700) != 0 && errno != EEXIST) + { + LOG(WARN, "pppoe: %s: Error creating folder: %s", ifname, LNX_PPPOE_PPP_DIR); + } + + if (mkdir(LNX_PPPOE_PEERS_DIR, 0700) != 0 && errno != EEXIST) + { + LOG(WARN, "pppoe: %s: Error creating folder: %s", ifname, LNX_PPPOE_PEERS_DIR); + } + + STRSCPY_WARN(self->lp_ifname, ifname); + + if (!daemon_init(&self->lp_pppd, "/usr/sbin/pppd", DAEMON_LOG_ALL)) + { + LOG(ERR, "pppoe: %s: Unable to initialize pppd daemon object.", ifname); + return false; + } + + daemon_arg_add(&self->lp_pppd, "call", (char *)ifname); + + /* Register to netlink update events */ + if (!lnx_netlink_init(&self->lp_nl, lnx_pppoe_netlink_fn)) + { + LOG(ERR, "pppoe: %s: Error initializing netlink socket.", ifname); + daemon_fini(&self->lp_pppd); + return false; + } + + lnx_netlink_set_ifname(&self->lp_nl, ifname); + lnx_netlink_set_events(&self->lp_nl, LNX_NETLINK_LINK | LNX_NETLINK_IP4ADDR | LNX_NETLINK_IP6ADDR); + + return true; +} + +bool lnx_pppoe_fini(lnx_pppoe_t *self) +{ + char fpath[C_MAXPATH_LEN]; + size_t rc; + + lnx_netlink_fini(&self->lp_nl); + daemon_fini(&self->lp_pppd); + lnx_pppoe_secret_del(self); + + /* + * Delete the peers (configuration) file for this interface + */ + rc = snprintf(fpath, sizeof(fpath), "%s/%s", LNX_PPPOE_PEERS_DIR, self->lp_ifname); + if (rc < sizeof(fpath)) + { + unlink(fpath); + } + + return true; +} + +bool lnx_pppoe_apply(lnx_pppoe_t *self) +{ + bool started; + + if (!daemon_is_started(&self->lp_pppd, &started) || started) + { + daemon_stop(&self->lp_pppd); + } + + /* Update the peers file -- aka config file */ + if (!lnx_pppoe_peers_write(self)) + { + LOG(ERR, "pppoe: %s: Error writing configuration file.", self->lp_ifname); + return false; + } + + /* Update secret files */ + lnx_pppoe_secret_update(); + + return daemon_start(&self->lp_pppd); +} + +void lnx_pppoe_status_notify(lnx_pppoe_t *self, lnx_pppoe_status_fn_t *fn) +{ + self->lp_status_fn = fn; + + if (fn != NULL) + { + if (!lnx_netlink_start(&self->lp_nl)) + { + LOG(WARN, "pppoe: %s: Error starting netlink socket.", self->lp_ifname); + } + } + else + { + if (!lnx_netlink_stop(&self->lp_nl)) + { + LOG(WARN, "pppoe: %s: Error stopping netlink socket.", self->lp_ifname); + } + } +} + +bool lnx_pppoe_parent_set(lnx_pppoe_t *self, const char *parent_ifname) +{ + if (strscpy(self->lp_pifname, parent_ifname, sizeof(self->lp_pifname)) < 0) + { + LOG(WARN, "pppoe: %s: Parent interface name %s is too long.", + self->lp_ifname, parent_ifname); + + self->lp_pifname[0] = '\0'; + return false; + } + + return true; +} + +/* + * Set the secret for this PPPoE link. Calling this function multiple times will + * overwrite previous secrets. + */ +bool lnx_pppoe_secret_set(lnx_pppoe_t *self, const char *username, const char *password) +{ + struct lnx_pppoe_secret *ps; + + ps = ds_tree_find(&lnx_pppoe_secrets, self->lp_ifname); + if (ps == NULL) + { + ps = calloc(1, sizeof(struct lnx_pppoe_secret)); + ASSERT(ps != NULL, "pppoe: Error allocating PPPoE secret.") + ps->ps_remote = self->lp_ifname; + ds_tree_insert(&lnx_pppoe_secrets, ps, ps->ps_remote); + } + + if (username == NULL) + { + lnx_pppoe_secret_del(self); + return true; + } + + /* + * Use the interface name as the remote name since it will be used as + * 'remotename' in the pppd configuration file + */ + if (strlen(username) >= sizeof(ps->ps_username)) + { + LOG(ERR, "pppoe: %s: Error setting secret: username too long.", self->lp_ifname); + lnx_pppoe_secret_del(self); + return false; + } + + if (strlen(password) >= sizeof(ps->ps_password)) + { + LOG(ERR, "pppoe: %s: Error setting secret: password too long.", self->lp_ifname); + lnx_pppoe_secret_del(self); + return false; + } + + STRSCPY(ps->ps_username, username); + STRSCPY(ps->ps_password, password); + + return true; +} + +void lnx_pppoe_secret_del(lnx_pppoe_t *self) +{ + struct lnx_pppoe_secret *ps; + + ps = ds_tree_find(&lnx_pppoe_secrets, self->lp_ifname); + if (ps == NULL) return; + + ds_tree_remove(&lnx_pppoe_secrets, ps); + memset(ps, 0x0, sizeof(*ps)); + free(ps); + lnx_pppoe_secret_update(); +} + + +/* + * Update PPP "secret" files. + * + * It is impossible to know in advance which authentication scheme will be used + * so this function updates both pap-secrets and chap-secrets files. + */ +static void lnx_pppoe_secret_update(void) +{ + (void)lnx_pppoe_secret_write(LNX_PPPOE_PAP_SECRETS); + (void)lnx_pppoe_secret_write(LNX_PPPOE_CHAP_SECRETS); +} + +bool lnx_pppoe_secret_write(const char *secret_file) +{ + struct lnx_pppoe_secret *ps; + int fd; + FILE *f; + + fd = open(secret_file, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (fd < 0) + { + LOG(ERR, "pppoe: Error opening secret file %s for writing: %s", + secret_file, strerror(errno)); + return false; + } + + f = fdopen(fd, "w"); + if (f == NULL) + { + LOG(ERR, "pppoe: Error opening secret file %s, fdopen() failed.", + secret_file); + close(fd); + return false; + } + + ds_tree_foreach(&lnx_pppoe_secrets, ps) + { + fprintf(f, "\"%s\"\t\"%s\"\t\"%s\"\t*\n", + ps->ps_username, ps->ps_remote, ps->ps_password); + } + + fclose(f); + + return true; +} + +/* + * Write out the "peers" (aka configuration) file for this pppd instance + */ +bool lnx_pppoe_peers_write(lnx_pppoe_t *self) +{ + struct lnx_pppoe_secret *ps; + char fpath[C_MAXPATH_LEN]; + size_t rc; + FILE *f; + int fd; + + if (self->lp_pifname[0] == '\0') + { + LOG(ERR, "pppoe: %s: Parent interface not set.", self->lp_ifname); + return false; + } + + ps = ds_tree_find(&lnx_pppoe_secrets, self->lp_ifname); + + rc = snprintf(fpath, sizeof(fpath), "%s/%s", LNX_PPPOE_PEERS_DIR, self->lp_ifname); + if (rc >= sizeof(fpath)) + { + LOG(ERR, "pppoe: %s: Peers configuration file name is too long.", self->lp_ifname); + return false; + } + + LOG(DEBUG, "pppoe: %s: Writing configuration to: %s", self->lp_ifname, fpath); + + fd = open(fpath, O_TRUNC | O_CREAT | O_WRONLY, 0600); + if (fd < 0) + { + LOG(ERR, "pppoe: %s: Error creating configuration file %s: %s", + self->lp_ifname, fpath, strerror(errno)); + return false; + } + + f = fdopen(fd, "w"); + if (f == NULL) + { + LOG(ERR, "pppoe: %s: fdopen() failed when writing configuration.", self->lp_ifname); + close(fd); + return false; + } + + fprintf(f, lnx_pppoe_peers_template, + self->lp_pifname, + self->lp_ifname, + self->lp_ifname); + + if (ps != NULL) + { + fprintf(f, lnx_pppoe_peers_template_username, ps->ps_username); + } + + fclose(f); + + return true; +} + +/* + * Poll the current interface status and call the status callback + */ +void lnx_pppoe_status_poll(lnx_pppoe_t *self) +{ + struct ifreq ifr; + + memset(&self->lp_status, 0, sizeof(self->lp_status)); + self->lp_status.ps_local_ip = OSN_IP_ADDR_INIT; + self->lp_status.ps_remote_ip = OSN_IP_ADDR_INIT; + + self->lp_status.ps_ifname = self->lp_ifname; + + if (lnx_pppoe_ifreq(self->lp_ifname, SIOCGIFFLAGS, &ifr)) + { + self->lp_status.ps_exists = true; + self->lp_status.ps_carrier = ifr.ifr_flags & IFF_RUNNING; + } + + if (lnx_pppoe_ifreq(self->lp_ifname, SIOCGIFMTU, &ifr)) + { + self->lp_status.ps_mtu = ifr.ifr_mtu; + } + + if (lnx_pppoe_ifreq(self->lp_ifname, SIOCGIFADDR, &ifr) && + !osn_ip_addr_from_sockaddr(&self->lp_status.ps_local_ip, &ifr.ifr_addr)) + { + LOG(WARN, "pppoe: %s: Unable to parse local IP.", self->lp_ifname); + } + + if (lnx_pppoe_ifreq(self->lp_ifname, SIOCGIFDSTADDR, &ifr) && + !osn_ip_addr_from_sockaddr(&self->lp_status.ps_remote_ip, &ifr.ifr_addr)) + { + LOG(WARN, "pppoe: %s: Unable to parse local IP.", self->lp_ifname); + } + + if (self->lp_status_fn != NULL) + { + self->lp_status_fn(self, &self->lp_status); + } +} + +void lnx_pppoe_netlink_fn(lnx_netlink_t *nl, uint64_t event, const char *ifname) +{ + (void)event; + (void)ifname; + + lnx_pppoe_t *self = CONTAINER_OF(nl, lnx_pppoe_t, lp_nl); + + lnx_pppoe_status_poll(self); +} + +/* + * Issue an ioctl() on the specified interface + */ +bool lnx_pppoe_ifreq(const char *ifname, int cmd, struct ifreq *req) +{ + static int ifreq_socket = -1; + + if (ifreq_socket < 0) + { + ifreq_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (ifreq_socket < 0) + { + LOG(ERR, "pppoe: Unable to open ifreq socket."); + return false; + } + } + + if (STRSCPY(req->ifr_name, ifname) < 0) + { + LOG(ERR, "pppoe: %s: ioctl() failed, interface name too long.", ifname); + return false; + } + + /* Issue ioctl() */ + if (ioctl(ifreq_socket, cmd, (void *)req) < 0) + { + LOG(DEBUG, "pppoe: %s: ioctl() failed.", ifname); + return false; + } + + return true; +} diff --git a/src/lib/osn/src/linux/lnx_pppoe.h b/src/lib/osn/src/linux/lnx_pppoe.h new file mode 100644 index 00000000..da32b086 --- /dev/null +++ b/src/lib/osn/src/linux/lnx_pppoe.h @@ -0,0 +1,62 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef LNX_PPPOE_H_INCLUDED +#define LNX_PPPOE_H_INCLUDED + +#include +#include + +#include "const.h" +#include "daemon.h" +#include "osn_pppoe.h" + +#include "lnx_netlink.h" + +typedef struct lnx_pppoe lnx_pppoe_t; +typedef void lnx_pppoe_status_fn_t( + lnx_pppoe_t *self, + struct osn_pppoe_status *status); + +struct lnx_pppoe +{ + char lp_ifname[C_IFNAME_LEN]; /* PPPoE interface name */ + char lp_pifname[C_IFNAME_LEN]; /* Parent interface */ + daemon_t lp_pppd; /* pppd process structure ?*/ + lnx_netlink_t lp_nl; /* Netlink socket */ + ev_async lp_async; /* Async event feeder */ + struct osn_pppoe_status lp_status; /* Cached status structure */ + lnx_pppoe_status_fn_t *lp_status_fn; /* Status callback */ +}; + +bool lnx_pppoe_init(lnx_pppoe_t *self, const char *ifname); +bool lnx_pppoe_fini(lnx_pppoe_t *self); +bool lnx_pppoe_apply(lnx_pppoe_t *self); +void lnx_pppoe_status_notify(lnx_pppoe_t *self, lnx_pppoe_status_fn_t *fn); +bool lnx_pppoe_parent_set(lnx_pppoe_t *self, const char *pifname); +bool lnx_pppoe_secret_set(lnx_pppoe_t *self, const char *username, const char *password); + +#endif /* LNX_PPPOE_H_INCLUDED */ diff --git a/src/lib/osn/src/linux/lnx_vlan.c b/src/lib/osn/src/linux/lnx_vlan.c new file mode 100644 index 00000000..0291cd14 --- /dev/null +++ b/src/lib/osn/src/linux/lnx_vlan.c @@ -0,0 +1,155 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ds.h" +#include "execsh.h" +#include "log.h" +#include "util.h" + +#include "lnx_vlan.h" + +/* + * Script for creating a VLAN interface. + * + * Input parameters: + * + * $1 - Interface name + * $2 - Parent interface name + * $3 - VLANID + */ +const char lnx_vlan_create[] = _S( + ip link add link "$2" name "$1" type vlan id "$3"); + +/* + * Script for deleting a VLAN interface + * + * Input parameters: + * + * $1 - Interface name + */ +const char lnx_vlan_delete[] = _S( + if [ -e "/sys/class/net/$1" ]; + then + ip link del "$1"; + fi;); + +bool lnx_vlan_init(lnx_vlan_t *self, const char *ifname) +{ + memset(self, 0, sizeof(*self)); + + if (strscpy(self->lv_ifname, ifname, sizeof(self->lv_ifname)) < 0) + { + LOG(ERR, "vlan: %s: Interface name too long.", ifname); + return false; + } + + return true; +} + +bool lnx_vlan_fini(lnx_vlan_t *self) +{ + int rc; + + if (!self->lv_applied) return true; + + /* Silently delete old interfaces, if there are any */ + rc = execsh_log(LOG_SEVERITY_DEBUG, lnx_vlan_delete, self->lv_ifname); + if (rc != 0) + { + LOG(WARN, "vlan: %s: Error deleting interface.", self->lv_ifname); + } + + return true; +} + +bool lnx_vlan_apply(lnx_vlan_t *self) +{ + char svlanid[C_INT32_LEN]; + int rc; + + if (self->lv_vlanid < 1 || self->lv_vlanid > 4095) + { + LOG(ERR, "vlan: %s: Unable to apply configuration, VLAN ID is not set.", + self->lv_ifname); + return false; + } + + if (self->lv_pifname[0] == '\0') + { + LOG(ERR, "vlan: %s: Unable to apply configuration, parent interface is not set.", + self->lv_ifname); + return false; + } + + self->lv_applied = true; + + snprintf(svlanid, sizeof(svlanid), "%d", self->lv_vlanid); + + /* Silently delete old interfaces, if there are any */ + execsh_log(LOG_SEVERITY_DEBUG, lnx_vlan_delete, self->lv_ifname); + + rc = execsh_log( + LOG_SEVERITY_DEBUG, + lnx_vlan_create, + self->lv_ifname, + self->lv_pifname, + svlanid); + if (rc != 0) + { + LOG(ERR, "vlan: %s: Error creating VLAN interface (parent %s, vlanid %d).", + self->lv_ifname, self->lv_pifname, self->lv_vlanid); + return false; + } + + return true; +} + +bool lnx_vlan_parent_ifname_set(lnx_vlan_t *self, const char *parent_ifname) +{ + if (strlen(parent_ifname) >= sizeof(self->lv_pifname)) + { + LOG(ERR, "vlan: %s: Parent interface name too long.", parent_ifname); + return false; + } + + STRSCPY(self->lv_pifname, parent_ifname); + + return true; +} + +bool lnx_vlan_vid_set(lnx_vlan_t *self, int vid) +{ + if (vid <= 1 || vid >= 4096) + { + LOG(ERR, "vlan: %s: Invalid VID: %d", + self->lv_ifname, vid); + return false; + } + + self->lv_vlanid = vid; + + return true; +} diff --git a/src/lib/osn/src/linux/lnx_vlan.h b/src/lib/osn/src/linux/lnx_vlan.h new file mode 100644 index 00000000..1d64a117 --- /dev/null +++ b/src/lib/osn/src/linux/lnx_vlan.h @@ -0,0 +1,51 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef LNX_VLAN_H_INCLUDED +#define LNX_VLAN_H_INCLUDED + +#include + +#include "const.h" + +typedef struct lnx_vlan lnx_vlan_t; + +struct lnx_vlan +{ + char lv_ifname[C_IFNAME_LEN]; /* Interface name */ + char lv_pifname[C_IFNAME_LEN]; /* Parent interface name */ + bool lv_applied; /* True if configuration was applied */ + int lv_vlanid; /* VLAN ID */ + ev_async lv_async; /* Async watcher */ +}; + +bool lnx_vlan_init(lnx_vlan_t *self, const char *ifname); +bool lnx_vlan_fini(lnx_vlan_t *self); +bool lnx_vlan_apply(lnx_vlan_t *self); +bool lnx_vlan_parent_ifname_set(lnx_vlan_t *self, const char *parent_ifname); +bool lnx_vlan_vid_set(lnx_vlan_t *self, int vid); + +#endif /* LNX_VLAN_H_INCLUDED */ diff --git a/src/lib/osn/src/osn_pppoe_linux.c b/src/lib/osn/src/osn_pppoe_linux.c new file mode 100644 index 00000000..c30b5fae --- /dev/null +++ b/src/lib/osn/src/osn_pppoe_linux.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "daemon.h" +#include "log.h" + +#include "osn_pppoe.h" +#include "lnx_pppoe.h" + +struct osn_pppoe +{ + lnx_pppoe_t op_pppoe; + void *op_data; + osn_pppoe_status_fn_t *op_status_fn; +}; + +static lnx_pppoe_status_fn_t osn_pppoe_status_fn; + +osn_pppoe_t *osn_pppoe_new(const char *ifname) +{ + osn_pppoe_t *self; + + self = calloc(1, sizeof(osn_pppoe_t)); + if (self == NULL) + { + LOG(ERR, "osn_pppoe: %s: Error allocating PPPoE object.", ifname); + return NULL; + } + + if (!lnx_pppoe_init(&self->op_pppoe, ifname)) + { + LOG(ERR, "osn_pppoe: %s: Error initializing PPPoE object.", ifname); + free(self); + return NULL; + } + + return self; +} + +bool osn_pppoe_del(osn_pppoe_t *self) +{ + bool retval = true; + + if (!lnx_pppoe_fini(&self->op_pppoe)) + { + LOG(WARN, "osn_pppoe: %s: Error destroying PPPoE object.", self->op_pppoe.lp_ifname); + retval = false; + } + + free(self); + + return retval; +} + +bool osn_pppoe_apply(osn_pppoe_t *self) +{ + return lnx_pppoe_apply(&self->op_pppoe); +} + +void osn_pppoe_data_set(osn_pppoe_t *self, void *data) +{ + self->op_data = data; +} + +void *osn_pppoe_data_get(osn_pppoe_t *self) +{ + return self->op_data; +} + +bool osn_pppoe_parent_set(osn_pppoe_t *self, const char *parent_ifname) +{ + return lnx_pppoe_parent_set(&self->op_pppoe, parent_ifname); +} + + +bool osn_pppoe_secret_set(osn_pppoe_t *self, const char *username, const char *password) +{ + return lnx_pppoe_secret_set(&self->op_pppoe, username, password); +} + +void osn_pppoe_status_fn(lnx_pppoe_t *lnx, struct osn_pppoe_status *status) +{ + osn_pppoe_t *self = CONTAINER_OF(lnx, osn_pppoe_t, op_pppoe); + + if (self->op_status_fn != NULL) + { + self->op_status_fn(self, status); + } +} + +void osn_pppoe_status_notify(osn_pppoe_t *self, osn_pppoe_status_fn_t *fn) +{ + self->op_status_fn = fn; + + lnx_pppoe_status_notify(&self->op_pppoe, (fn == NULL) ? NULL : osn_pppoe_status_fn); +} + diff --git a/src/lib/osn/src/osn_pppoe_null.c b/src/lib/osn/src/osn_pppoe_null.c new file mode 100644 index 00000000..ddeef73e --- /dev/null +++ b/src/lib/osn/src/osn_pppoe_null.c @@ -0,0 +1,97 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "daemon.h" +#include "log.h" + +#include "osn_pppoe.h" +#include "lnx_pppoe.h" + +struct osn_pppoe +{ + void *data; +}; + +osn_pppoe_t *osn_pppoe_new(const char *ifname) +{ + osn_pppoe_t *self; + + self = malloc(sizeof(struct osn_pppoe)); + if (self == NULL) + { + LOG(ERR, "osn_pppoe: %s: Error allocating PPPoE object.", ifname); + return false; + } + + return self; +} + +bool osn_pppoe_del(osn_pppoe_t *self) +{ + free(self); + + return true; +} + +bool osn_pppoe_apply(osn_pppoe_t *self) +{ + (void)self; + return true; +} + +bool osn_pppoe_parent_set(osn_pppoe_t *self, const char *parent_ifname) +{ + (void)self; + (void)parent_ifname; + + return true; +} + +bool osn_pppoe_secret_set(osn_pppoe_t *self, const char *username, const char *password) +{ + (void)self; + (void)username; + (void)password; + + return true; +} + +void osn_pppoe_data_set(osn_pppoe_t *self, void *data) +{ + self->data = data; +} + +void *osn_pppoe_data_get(osn_pppoe_t *self) +{ + return self->data; +} + +void osn_pppoe_status_notify(osn_pppoe_t *self, osn_pppoe_status_fn_t *fn) +{ + (void)self; + (void)fn; +} + diff --git a/src/lib/osn/src/osn_types.c b/src/lib/osn/src/osn_types.c index 34edf77d..710167cf 100644 --- a/src/lib/osn/src/osn_types.c +++ b/src/lib/osn/src/osn_types.c @@ -92,6 +92,33 @@ bool osn_ip_addr_from_str(osn_ip_addr_t *out, const char *str) return true; } +/* + * Create a osn_ip_addr_t structure from a in_addr structure. in_addr is + * commonly used hidden inside sockaddr + */ +bool osn_ip_addr_from_in_addr(osn_ip_addr_t *out, const struct in_addr *in) +{ + *out = OSN_IP_ADDR_INIT; + memcpy(&out->ia_addr, in, sizeof(out->ia_addr)); + + return true; +} + +/* + * Create a osn_ip_addr_t structure from a sockaddr structure. + */ +bool osn_ip_addr_from_sockaddr(osn_ip_addr_t *out, const struct sockaddr *in) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)in; + + if (sin->sin_family != AF_INET) + { + return false; + } + + return osn_ip_addr_from_in_addr(out, &sin->sin_addr); +} + /* * Comparator function -- compare two osn_ip_addr_t and return negative, 0 or positive if * a is lower than, equal to or greater than b, respectively. diff --git a/src/lib/osn/src/osn_vlan_linux.c b/src/lib/osn/src/osn_vlan_linux.c new file mode 100644 index 00000000..12663535 --- /dev/null +++ b/src/lib/osn/src/osn_vlan_linux.c @@ -0,0 +1,86 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "log.h" + +#include "lnx_vlan.h" + +#include "osn_vlan.h" + +struct osn_vlan +{ + lnx_vlan_t ov_vlan; +}; + +osn_vlan_t *osn_vlan_new(const char *ifname) +{ + osn_vlan_t *self = calloc(1, sizeof(osn_vlan_t)); + + if (self == NULL) + { + LOG(ERR, "osn_vlan: %s: Error allocating the VLAN object.", ifname); + return NULL; + } + + if (!lnx_vlan_init(&self->ov_vlan, ifname)) + { + LOG(ERR, "osn_vlan: %s: Error initializing the VLAN object.", ifname); + free(self); + return NULL; + } + + return self; +} + +bool osn_vlan_del(osn_vlan_t *self) +{ + bool retval = true; + + if (!lnx_vlan_fini(&self->ov_vlan)) + { + LOG(WARN, "osn_pppoe: %s: Error destroying PPPoE object.", self->ov_vlan.lv_ifname); + retval = false; + } + + free(self); + + return retval; +} + +bool osn_vlan_parent_set(osn_vlan_t *self, const char *parent_ifname) +{ + return lnx_vlan_parent_ifname_set(&self->ov_vlan, parent_ifname); +} + +bool osn_vlan_vid_set(osn_vlan_t *self, int vlanid) +{ + return lnx_vlan_vid_set(&self->ov_vlan, vlanid); +} + +bool osn_vlan_apply(osn_vlan_t *self) +{ + return lnx_vlan_apply(&self->ov_vlan); +} diff --git a/src/lib/osn/src/osn_vlan_null.c b/src/lib/osn/src/osn_vlan_null.c new file mode 100644 index 00000000..11483d65 --- /dev/null +++ b/src/lib/osn/src/osn_vlan_null.c @@ -0,0 +1,77 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "log.h" + +#include "lnx_vlan.h" + +#include "osn_vlan.h" + +struct osn_vlan +{ + char data[1]; +}; + +osn_vlan_t *osn_vlan_new(const char *ifname) +{ + osn_vlan_t *self = calloc(1, sizeof(osn_vlan_t)); + if (self == NULL) + { + LOG(ERR, "osn_vlan: %s: Error allocating the VLAN object.", ifname); + return NULL; + } + + return self; +} + +bool osn_vlan_del(osn_vlan_t *self) +{ + free(self); + return false; +} + +bool osn_vlan_parent_set(osn_vlan_t *self, const char *parent_ifname) +{ + (void)self; + (void)parent_ifname; + + return true; +} + +bool osn_vlan_vid_set(osn_vlan_t *self, int vlanid) +{ + (void)self; + (void)vlanid; + + return true; +} + +bool osn_vlan_apply(osn_vlan_t *self) +{ + (void)self; + return true; +} + diff --git a/src/lib/osn/unit.mk b/src/lib/osn/unit.mk index 64a3d68a..aedbb988 100644 --- a/src/lib/osn/unit.mk +++ b/src/lib/osn/unit.mk @@ -69,6 +69,12 @@ UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_DHCPV6_SERVER_DNSMASQ6),src/osn_dhcpv6_ser UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_IPV6_RADV_NULL),src/osn_ip6_radv_null.c) UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_IPV6_RADV_DNSMASQ6),src/osn_ip6_radv_dnsmasq6.c) +UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_PPPOE_NULL),src/osn_pppoe_null.c) +UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_PPPOE_LINUX),src/osn_pppoe_linux.c) + +UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_VLAN_NULL),src/osn_vlan_null.c) +UNIT_SRC += $(if $(CONFIG_OSN_BACKEND_VLAN_LINUX),src/osn_vlan_linux.c) + ifdef CONFIG_OSN_LINUX_ENABLED UNIT_CFLAGS += -I$(UNIT_PATH)/src/linux @@ -82,6 +88,8 @@ UNIT_SRC += $(if $(CONFIG_OSN_LINUX_ROUTE),src/linux/lnx_route.c) UNIT_SRC += $(if $(CONFIG_OSN_MINIUPNPD),src/linux/mupnp_server.c) UNIT_SRC += $(if $(CONFIG_OSN_ODHCP6),src/linux/odhcp6_client.c) UNIT_SRC += $(if $(CONFIG_OSN_UDHCPC),src/linux/udhcp_client.c) +UNIT_SRC += $(if $(CONFIG_OSN_LINUX_PPPOE),src/linux/lnx_pppoe.c) +UNIT_SRC += $(if $(CONFIG_OSN_LINUX_VLAN),src/linux/lnx_vlan.c) UNIT_DEPS += src/lib/daemon UNIT_DEPS += src/lib/evx diff --git a/src/lib/osp/inc/osp.h b/src/lib/osp/inc/osp.h index 9dc22c12..e9aa5dbc 100644 --- a/src/lib/osp/inc/osp.h +++ b/src/lib/osp/inc/osp.h @@ -24,292 +24,37 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSP_H_INCLUDED) +#ifndef OSP_H_INCLUDED #define OSP_H_INCLUDED -#include -#include -#include - -#include "osp_tm.h" -#include "osp_led.h" - /// @file /// @brief Platform APIs /// +/////////////////////////////////////////////////////////////////////////////// +/// +/// @note The individual headers are included here for backward compatibility +/// and may be removed in the future. It is recommended to include just +/// the needed header(s) in source files. +/// +/////////////////////////////////////////////////////////////////////////////// +/// /// @defgroup OSP OpenSync Platform API /// OpenSync Platform API and types /// @{ -// =========================================================================== -// Button API -// =========================================================================== - -/// @defgroup OSP_BTN Button API -/// OpenSync Button API -/// @{ - -/** - * Enumeration of buttons supported by OpenSync - */ -enum osp_btn_name -{ - OSP_BTN_NAME_RESET = (1 << 0), /**< Factory reset button */ - OSP_BTN_NAME_WPS = (1 << 1), /**< WiFi WPS button */ - - /* More buttons can be added */ -}; - -/** - * Get the capabilities related to the buttons - * - * @param[out] caps Bitmask of buttons supported by the target - * You can test if a button is supported by testing the bitmask - * For example, to test if the reset button is supported by the - * target, you can test (caps & @ref OSP_BTN_NAME_RESET) - * - * @return true on success - */ -bool osp_btn_get_caps(uint32_t *caps); - -/** - * Definition of an event associated with a button - * - * Example 1: Button is pushed - * - pushed = true - * - duration = 0 - * - double_click = false - * - * Example 2: Button is double click - * - pushed = false - * - duration = 0 - * - double_click = true - * - * Example 3: Button is released after 1 second - * - pushed = false - * - duration = 1000 - * - double_click = false - * - * Example 4: Button is released after 5 seconds - * - pushed = false - * - duration = 5000 - * - double_click = false - */ -struct osp_btn_event -{ - /** - * True if the button is pushed, false if the button is released - */ - bool pushed; - - /** - * Duration in milliseconds of pressing the button - * - * Valid only when the button is released and it was not a double click. - */ - unsigned int duration; - - /** - * True if the button is pushed and released two times in less than - * 1000 milliseconds - * - * Valid only when the button is released. - */ - bool double_click; -}; - -/** - * Callback called by the target layer when an event is received on a button - * - * @param[in] obj Pointer to the object that was supplied when the callback - * was registered (@ref osp_btn_register call) - * @param[in] name Button associated with the event - * @param[in] event Details of the button event - */ -typedef void (*osp_btn_cb)(void *obj, enum osp_btn_name name, const struct osp_btn_event *event); - -/** - * Register the callback to receive button events - * - * @param[in] cb Callback called by the target layer when an event is received - * on a button. - * If callback is NULL, the target must unregister the previous - * one for this specific obj. - * @param[in] obj User pointer which will be given back when the callback will - * be called - * - * @return true on success - */ -bool osp_btn_register(osp_btn_cb cb, void *obj); - -/// @} OSP_BTN - - -// =========================================================================== -// Reboot API -// =========================================================================== - -/// @defgroup OSP_REBOOT Reboot API -/// OpenSync Reboot API -/// @{ - -/** - * Reboot type - */ -enum osp_reboot_type -{ - OSP_REBOOT_UNKNOWN, /**< Unknown reboot reason */ - OSP_REBOOT_COLD_BOOT, /**< Power-on / cold boot */ - OSP_REBOOT_POWER_CYCLE, /**< Power cycle or spontaneous reset */ - OSP_REBOOT_WATCHDOG, /**< Watchdog triggered reboot */ - OSP_REBOOT_CRASH, /**< Reboot due to kernel/system/driver crash */ - OSP_REBOOT_USER, /**< Human triggered reboot (via shell or otherwise) */ - OSP_REBOOT_DEVICE, /**< Device initiated reboot (upgrade, health check or otherwise) */ - OSP_REBOOT_HEALTH_CHECK, /**< Health check failed */ - OSP_REBOOT_UPGRADE, /**< Reboot due to an upgrade */ - OSP_REBOOT_THERMAL, /**< Reboot due to a thermal event */ - OSP_REBOOT_CLOUD, /**< Cloud initiated reboot */ - OSP_REBOOT_CANCEL /**< Cancel last reboot record */ -}; - -/** - * Unit reboot - * - * @param[in] type Reboot type (request source) - * @param[in] reason Reboot reason (description) - * @param[in] ms_delay Delay actual reboot in ms - * - * @return true on success - * - * @note - * If the reboot type is OSP_REBOOT_CANCEL, the last record reboot record is - * invalidated. - */ -bool osp_unit_reboot_ex(enum osp_reboot_type type, const char *reason, int ms_delay); - -/** osp_unit_reboot() is a simplified alias to osp_unit_reboot_ex() */ -static inline bool osp_unit_reboot(const char *reason, int ms_delay) -{ - return osp_unit_reboot_ex(OSP_REBOOT_DEVICE, reason, ms_delay); -} - -/** - * Unit reboot & factory reset - * - * @param[in] reason Reboot reason (description) - * @param[in] ms_delay Delay actual factory reboot in ms - * - * @return true on success - */ -bool osp_unit_factory_reboot(const char *reason, int ms_delay); - -/** - * This function returns the last reboot type and reason - * - * @param[out] type Returns an enum of type osp_reboot_type - * @param[out] reason Returns the reboot reason (as string) - * @param[out] reason_sz Maximum size of @p reason - * - * @return - * This function returns true if it was able to successfully detect - * the reboot type, or false in case of an error. - */ -bool osp_unit_reboot_get(enum osp_reboot_type *type, char *reason, ssize_t reason_sz); - -/// @} OSP_REBOOT - - -// =========================================================================== -// Upgrade API -// =========================================================================== - -/// @defgroup OSP_UPG Upgrade API -/// OpenSync Upgrade API -/// @{ - -/** - * Type of upgrade operations - */ -typedef enum -{ - OSP_UPG_DL, /**< Download of the upgrade file */ - OSP_UPG_UPG /**< Upgrade process */ -} osp_upg_op_t; - - -/** - * Upgrade operations status - */ -typedef enum -{ - OSP_UPG_OK = 0, /**< Success */ - OSP_UPG_ARGS = 1, /**< Wrong arguments (app error) */ - OSP_UPG_URL = 3, /**< Error setting url */ - OSP_UPG_DL_FW = 4, /**< DL of FW image failed */ - OSP_UPG_DL_MD5 = 5, /**< DL of *.md5 sum failed */ - OSP_UPG_MD5_FAIL = 6, /**< md5 CS failed or platform */ - OSP_UPG_IMG_FAIL = 7, /**< Image check failed */ - OSP_UPG_FL_ERASE = 8, /**< Flash erase failed */ - OSP_UPG_FL_WRITE = 9, /**< Flash write failed */ - OSP_UPG_FL_CHECK = 10, /**< Flash verification failed */ - OSP_UPG_BC_SET = 11, /**< New FW commit failed */ - OSP_UPG_APPLY = 12, /**< Applying new FW failed */ - OSP_UPG_BC_ERASE = 14, /**< Clean FW commit info failed */ - OSP_UPG_SU_RUN = 15, /**< Upgrade in progress running */ - OSP_UPG_DL_NOFREE = 16, /**< Not enough free space on unit */ - OSP_UPG_WRONG_PARAM = 17, /**< Wrong flashing parameters */ - OSP_UPG_INTERNAL = 18 /**< Internal error */ -} osp_upg_status_t; - - -/** - * Callback invoked by target layer during download & upgrade process - * - * @param[in] op - operation: download, download CS file or upgrade - * @param[in] status status - * @param[in] completed percentage of completed work 0 - 100% - */ -typedef void (*osp_upg_cb)(const osp_upg_op_t op, - const osp_upg_status_t status, - uint8_t completed); - - -/** - * Check system requirements for upgrade, like no upgrade in progress, - * available flash space etc. - */ -bool osp_upg_check_system(void); - -/** - * Download an image suitable for upgrade from @p uri and store it locally. - * Upon download and verification completion, invoke the @p dl_cb callback. - */ -bool osp_upg_dl(char *url, uint32_t timeout, osp_upg_cb dl_cb); - -/** - * Write the previously downloaded image to the system. If the image - * is encrypted, a password must be specified in @p password. - * - * After the image was successfully applied, the @p upg_cb callback is invoked. - */ -bool osp_upg_upgrade(char *password, osp_upg_cb upg_cb); - -/** - * On dual-boot system, flag the newly flashed image as the active one. - * This can be a no-op on single image systems. - */ -bool osp_upg_commit(void); - -/** - * Return a more detailed error code related to a failed osp_upg_*() function - * call. See osp_upg_status_t for a detailed list of error codes. - */ -int osp_upg_errno(void); +#include "osp_unit.h" +#include "osp_tm.h" +#include "osp_reboot.h" +#include "osp_led.h" +#include "osp_btn.h" +#include "osp_upg.h" +#include "osp_ps.h" +#include "osp_dl.h" +#include "osp_objm.h" -/// @} OSP_UPG /// @} OSP #endif /* OSP_H_INCLUDED */ diff --git a/src/lib/osp/inc/osp_btn.h b/src/lib/osp/inc/osp_btn.h new file mode 100644 index 00000000..04612add --- /dev/null +++ b/src/lib/osp/inc/osp_btn.h @@ -0,0 +1,146 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSP_BTN_H_INCLUDED +#define OSP_BTN_H_INCLUDED + +#include +#include + + +/// @file +/// @brief Button API +/// +/// @addtogroup OSP +/// @{ + + +// =========================================================================== +// Button API +// =========================================================================== + +/// @defgroup OSP_BTN Button API +/// OpenSync Button API +/// @{ + +/** + * Enumeration of buttons supported by OpenSync + */ +enum osp_btn_name +{ + OSP_BTN_NAME_RESET = (1 << 0), /**< Factory reset button */ + OSP_BTN_NAME_WPS = (1 << 1), /**< WiFi WPS button */ + + /* More buttons can be added */ +}; + +/** + * Get the capabilities related to the buttons + * + * @param[out] caps Bitmask of buttons supported by the target + * You can test if a button is supported by testing the bitmask + * For example, to test if the reset button is supported by the + * target, you can test (caps & @ref OSP_BTN_NAME_RESET) + * + * @return true on success + */ +bool osp_btn_get_caps(uint32_t *caps); + +/** + * Definition of an event associated with a button + * + * Example 1: Button is pushed + * - pushed = true + * - duration = 0 + * - double_click = false + * + * Example 2: Button is double click + * - pushed = false + * - duration = 0 + * - double_click = true + * + * Example 3: Button is released after 1 second + * - pushed = false + * - duration = 1000 + * - double_click = false + * + * Example 4: Button is released after 5 seconds + * - pushed = false + * - duration = 5000 + * - double_click = false + */ +struct osp_btn_event +{ + /** + * True if the button is pushed, false if the button is released + */ + bool pushed; + + /** + * Duration in milliseconds of pressing the button + * + * Valid only when the button is released and it was not a double click. + */ + unsigned int duration; + + /** + * True if the button is pushed and released two times in less than + * 1000 milliseconds + * + * Valid only when the button is released. + */ + bool double_click; +}; + +/** + * Callback called by the target layer when an event is received on a button + * + * @param[in] obj Pointer to the object that was supplied when the callback + * was registered (@ref osp_btn_register call) + * @param[in] name Button associated with the event + * @param[in] event Details of the button event + */ +typedef void (*osp_btn_cb)(void *obj, enum osp_btn_name name, const struct osp_btn_event *event); + +/** + * Register the callback to receive button events + * + * @param[in] cb Callback called by the target layer when an event is received + * on a button. + * If callback is NULL, the target must unregister the previous + * one for this specific obj. + * @param[in] obj User pointer which will be given back when the callback will + * be called + * + * @return true on success + */ +bool osp_btn_register(osp_btn_cb cb, void *obj); + + +/// @} OSP_BTN +/// @} OSP + +#endif /* OSP_BTN_H_INCLUDED */ diff --git a/src/lib/osp/inc/osp_dl.h b/src/lib/osp/inc/osp_dl.h new file mode 100644 index 00000000..fbc156ba --- /dev/null +++ b/src/lib/osp/inc/osp_dl.h @@ -0,0 +1,87 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSP_DL_H_INCLUDED +#define OSP_DL_H_INCLUDED + +#include + + +/// @file +/// @brief OSP Download API +/// +/// @addtogroup OSP +/// @{ + + +// =========================================================================== +// Download API +// =========================================================================== + +/// @defgroup OSP_DL Download API +/// OpenSync Download API +/// @{ + + +/** Enum osp_dl_status for status reporting */ +enum osp_dl_status +{ + OSP_DL_OK = 0, ///< Download OK + OSP_DL_DOWNLOAD_FAILED, ///< Download failed + OSP_DL_ERROR ///< General download error +}; + +/** + * Complete download callback function + * + * @param[in] status Status of finished download + * @param[in] cb_ctx Context struct of osp_dl_download caller. + * + */ +typedef void (*osp_dl_cb)(const enum osp_dl_status status, void *cb_ctx); + +/** + * Function to download a file from @p url to @p dst_path. + * Non-blocking implementation is expected. After a successful download, + * a failure, or an expired timeout, it is expected that dl_cb callback + * is called with the status. + * + * @param[in] url URL of file to download + * @param[in] dst_path Path where to download the file to + * @param[in] timeout Timeout for the download operation + * @param[in] dl_cb Callback for when downloading is finished, or failure or a timeout occurred + * @param[in] cb_ctx Caller context struct that is passed in dl_cb callback + * + * @return true if download is started successfully + * + */ +bool osp_dl_download(char *url, char *dst_path, int timeout, osp_dl_cb dl_cb, void *cb_ctx); + + +/// @} OSP_DL +/// @} OSP + +#endif /* OSP_DL_H_INCLUDED */ diff --git a/src/lib/osp/inc/osp_l2switch.h b/src/lib/osp/inc/osp_l2switch.h index 0141aeaa..a3132cd3 100644 --- a/src/lib/osp/inc/osp_l2switch.h +++ b/src/lib/osp/inc/osp_l2switch.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSP_L2SWITCH_H_INCLUDED) +#ifndef OSP_L2SWITCH_H_INCLUDED #define OSP_L2SWITCH_H_INCLUDED #include diff --git a/src/lib/osp/inc/osp_objm.h b/src/lib/osp/inc/osp_objm.h new file mode 100644 index 00000000..3ae08177 --- /dev/null +++ b/src/lib/osp/inc/osp_objm.h @@ -0,0 +1,90 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSP_OBJM_H_INCLUDED +#define OSP_OBJM_H_INCLUDED + +#include +#include + + +/// @file +/// @brief OSP Object Management API +/// +/// @addtogroup OSP +/// @{ + + +// =========================================================================== +// Object Management API +// =========================================================================== + +/// @defgroup OSP_OBJM Object Management API +/// OpenSync Object Management API +/// @{ + + +/** + * Install object to object storage + * + * @param[in] path Path where the file for installation is located + * @param[in] name Name of the object + * @param[in] version Version of object + * + * @return true if install is successful + * + */ +bool osp_objm_install(char *path, char *name, char *version); + +/** + * Remove object from object storage + * + * @param[in] name Name of the object + * @param[in] version Version of object + * + * @return true if removal is successful + * + */ +bool osp_objm_remove(char *name, char *version); + +/** + * Get path on filesystem where installed object is available + * + * @param[out] buf Buffer in which path of object is returned + * @param[in] buffsz Size of the provided buffer + * @param[in] name Name of the object + * @param[in] version Version of object + * + * @return true if buf is populated with path + * + */ +bool osp_objm_path(char *buf, size_t buffsz, char *name, char *version); + + +/// @} OSP_OBJM +/// @} OSP + +#endif /* OSP_OBJM_H_INCLUDED */ diff --git a/src/lib/osp/inc/osp_ps.h b/src/lib/osp/inc/osp_ps.h index 7d94b526..97f9fcea 100644 --- a/src/lib/osp/inc/osp_ps.h +++ b/src/lib/osp/inc/osp_ps.h @@ -151,6 +151,29 @@ ssize_t osp_ps_get( void *value, size_t value_sz); +/** + * Erase content of store @p ps (delete all keys and their values) + * + * @param[in] ps Store -- valid object returned by + * @ref osp_ps_open() with the flag + * OSP_PS_WRITE + * + * @note + * Stores opened with the same name but with or without the OPS_PS_PRESERVE + * flag are different stores. + * + * @return + * This function returns true on success, or false if any errors were + * encountered. If false is returned, it should be assumed that store + * was not erased. + * + * @note + * This function does not guarantee that the data was deleted from + * persistent store. To ensure that the change hits the storage, a + * call to @ref osp_ps_sync() or @ref osp_ps_close() is required. + */ +bool osp_ps_erase(osp_ps_t *ps); + /** * Flush all dirty data to persistent storage. When this function returns, * the data written by @ref osp_ps_set() should be considered safely stored. diff --git a/src/lib/osp/inc/osp_reboot.h b/src/lib/osp/inc/osp_reboot.h new file mode 100644 index 00000000..17d6a838 --- /dev/null +++ b/src/lib/osp/inc/osp_reboot.h @@ -0,0 +1,116 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSP_REBOOT_H_INCLUDED +#define OSP_REBOOT_H_INCLUDED + +#include +#include + + +/// @file +/// @brief Reboot API +/// +/// @addtogroup OSP +/// @{ + + +// =========================================================================== +// Reboot API +// =========================================================================== + +/// @defgroup OSP_REBOOT Reboot API +/// OpenSync Reboot API +/// @{ + +/** + * Reboot type + */ +enum osp_reboot_type +{ + OSP_REBOOT_UNKNOWN, /**< Unknown reboot reason */ + OSP_REBOOT_COLD_BOOT, /**< Power-on / cold boot */ + OSP_REBOOT_POWER_CYCLE, /**< Power cycle or spontaneous reset */ + OSP_REBOOT_WATCHDOG, /**< Watchdog triggered reboot */ + OSP_REBOOT_CRASH, /**< Reboot due to kernel/system/driver crash */ + OSP_REBOOT_USER, /**< Human triggered reboot (via shell or otherwise) */ + OSP_REBOOT_DEVICE, /**< Device initiated reboot (upgrade, health check or otherwise) */ + OSP_REBOOT_HEALTH_CHECK, /**< Health check failed */ + OSP_REBOOT_UPGRADE, /**< Reboot due to an upgrade */ + OSP_REBOOT_THERMAL, /**< Reboot due to a thermal event */ + OSP_REBOOT_CLOUD, /**< Cloud initiated reboot */ + OSP_REBOOT_CANCEL /**< Cancel last reboot record */ +}; + +/** + * Unit reboot + * + * @param[in] type Reboot type (request source) + * @param[in] reason Reboot reason (description) + * @param[in] ms_delay Delay actual reboot in ms + * + * @return true on success + * + * @note + * If the reboot type is OSP_REBOOT_CANCEL, the last record reboot record is + * invalidated. + */ +bool osp_unit_reboot_ex(enum osp_reboot_type type, const char *reason, int ms_delay); + +/** osp_unit_reboot() is a simplified alias to osp_unit_reboot_ex() */ +static inline bool osp_unit_reboot(const char *reason, int ms_delay) +{ + return osp_unit_reboot_ex(OSP_REBOOT_DEVICE, reason, ms_delay); +} + +/** + * Unit reboot & factory reset + * + * @param[in] reason Reboot reason (description) + * @param[in] ms_delay Delay actual factory reboot in ms + * + * @return true on success + */ +bool osp_unit_factory_reboot(const char *reason, int ms_delay); + +/** + * This function returns the last reboot type and reason + * + * @param[out] type Returns an enum of type osp_reboot_type + * @param[out] reason Returns the reboot reason (as string) + * @param[out] reason_sz Maximum size of @p reason + * + * @return + * This function returns true if it was able to successfully detect + * the reboot type, or false in case of an error. + */ +bool osp_unit_reboot_get(enum osp_reboot_type *type, char *reason, ssize_t reason_sz); + + +/// @} OSP_REBOOT +/// @} OSP + +#endif /* OSP_REBOOT_H_INCLUDED */ diff --git a/src/lib/osp/inc/osp_tm.h b/src/lib/osp/inc/osp_tm.h index f05e3475..b4ab26b7 100644 --- a/src/lib/osp/inc/osp_tm.h +++ b/src/lib/osp/inc/osp_tm.h @@ -24,7 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(OSP_TM_H_INCLUDED) +#ifndef OSP_TM_H_INCLUDED #define OSP_TM_H_INCLUDED #include diff --git a/src/lib/osp/inc/osp_unit.h b/src/lib/osp/inc/osp_unit.h new file mode 100644 index 00000000..5da976a6 --- /dev/null +++ b/src/lib/osp/inc/osp_unit.h @@ -0,0 +1,226 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSP_UNIT_H_INCLUDED +#define OSP_UNIT_H_INCLUDED + +#include +#include +#include + + +/// @file +/// @brief OSP Unit API +/// +/// @addtogroup OSP +/// @{ + + +// =========================================================================== +// Unit API +// =========================================================================== + +/// @defgroup OSP_UNIT Unit API +/// OpenSync Unit API +/// @{ + + +/** + * @brief Return device identification + * + * This function provides a null terminated byte string containing the device + * identification. The device identification is part of the AWLAN_Node table. + * In the simplest implementation, this function may be the same as + * osp_unit_serial_get(). + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_id_get(char *buff, size_t buffsz); + +/** + * @brief Return device serial number + * + * This function provides a null terminated byte string containing the serial + * number. The serial number is part of the AWLAN_Node table. + * For example, the serial number may be derived from the MAC address. + * Please see implementation inside osp_unit.c file for the reference. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_serial_get(char *buff, size_t buffsz); + +/** + * @brief Return device model + * + * This function provides a null terminated byte string containing the device + * model. The device model is a part of the AWLAN_Node table. + * + * In the simplest implementation, this function may return the value of + * CONFIG_TARGET_MODEL. + * + * It is safe to return false here. The TARGET_NAME will be used + * as a model name in that case. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_model_get(char *buff, size_t buffsz); + +/** + * @brief Return device stock keeping unit number + * + * This function provides a null terminated byte string containing the stock + * keeping unit number. It is usually used by stores to track inventory. + * The SKU is part of the AWLAN_Node table. + * + * If cloud doesn't support SKU for this target, this function should return + * false. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_sku_get(char *buff, size_t buffsz); + +/** + * @brief Return hardware version number + * + * This function provides a null terminated byte string containing the hardware + * version number. The hardware version is part of the AWLAN_Node table. + * If not needed this function should return false. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_hw_revision_get(char *buff, size_t buffsz); + +/** + * @brief Return platform version number + * + * This function provides a null terminated byte string containing the platform + * version number. The platform version number is part of the AWLAN_Node table. + * If not needed this function should return false. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_platform_version_get(char *buff, size_t buffsz); + +/** + * @brief Return software version number + * + * This function provides a null terminated byte string containing the software + * version number. + * Expected format: VERSION-BUILD_NUMBER-gGITSHA-PROFILE + * Sample: 1.0.0.0-200-g1a2b3c-devel + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_sw_version_get(char *buff, size_t buffsz); + +/** + * @brief Return vendor name + * + * This function provides a null terminated byte string containing the device's + * vendor name. The vendor name is part of the AWLAN_Node table. + * It is safe to return false here if not needed. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_vendor_name_get(char *buff, size_t buffsz); + +/** + * @brief Return vendor part number + * + * This function provides a null terminated byte string containing the device's + * vendor part number. The vendor part number is part of the AWLAN_Node table. + * It is safe to return false here if not needed. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_vendor_part_get(char *buff, size_t buffsz); + +/** + * @brief Return manufacturer name + * + * This function provides a null terminated byte string containing the + * manufacturer name who built the device. The manufacturer name is part of + * the AWLAN_Node table. + * It is safe to return false here if not needed or unknown. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_manufacturer_get(char *buff, size_t buffsz); + +/** + * @brief Return factory name + * + * This function provides a null terminated byte string containing the factory + * name where the device was built. The factory name is part of the AWLAN_Node + * table. + * It is safe to return false here if not needed or unknown. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_factory_get(char *buff, size_t buffsz); + +/** + * @brief Return manufacturing date + * + * This function provides a null terminated byte string containing the date + * when the device was built. The date should be in a format "YYYY/WW", where + * YYYY stands for year, and WW stands for work week of the year. + * The manufacturing date is part of the AWLAN_Node table. + * It is safe to return false here if not needed or unknown. + * + * @param buff pointer to a string buffer + * @param buffsz size of string buffer + * @return true on success + */ +bool osp_unit_mfg_date_get(char *buff, size_t buffsz); + + +/// @} OSP_UNIT +/// @} OSP + +#endif /* OSP_UNIT_H_INCLUDED */ diff --git a/src/lib/osp/inc/osp_upg.h b/src/lib/osp/inc/osp_upg.h new file mode 100644 index 00000000..a474a890 --- /dev/null +++ b/src/lib/osp/inc/osp_upg.h @@ -0,0 +1,131 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OSP_UPG_H_INCLUDED +#define OSP_UPG_H_INCLUDED + +#include +#include + + +/// @file +/// @brief Upgrade API +/// +/// @addtogroup OSP +/// @{ + + +// =========================================================================== +// Upgrade API +// =========================================================================== + +/// @defgroup OSP_UPG Upgrade API +/// OpenSync Upgrade API +/// @{ + +/** + * Type of upgrade operations + */ +typedef enum +{ + OSP_UPG_DL, /**< Download of the upgrade file */ + OSP_UPG_UPG /**< Upgrade process */ +} osp_upg_op_t; + + +/** + * Upgrade operations status + */ +typedef enum +{ + OSP_UPG_OK = 0, /**< Success */ + OSP_UPG_ARGS = 1, /**< Wrong arguments (app error) */ + OSP_UPG_URL = 3, /**< Error setting url */ + OSP_UPG_DL_FW = 4, /**< DL of FW image failed */ + OSP_UPG_DL_MD5 = 5, /**< DL of *.md5 sum failed */ + OSP_UPG_MD5_FAIL = 6, /**< md5 CS failed or platform */ + OSP_UPG_IMG_FAIL = 7, /**< Image check failed */ + OSP_UPG_FL_ERASE = 8, /**< Flash erase failed */ + OSP_UPG_FL_WRITE = 9, /**< Flash write failed */ + OSP_UPG_FL_CHECK = 10, /**< Flash verification failed */ + OSP_UPG_BC_SET = 11, /**< New FW commit failed */ + OSP_UPG_APPLY = 12, /**< Applying new FW failed */ + OSP_UPG_BC_ERASE = 14, /**< Clean FW commit info failed */ + OSP_UPG_SU_RUN = 15, /**< Upgrade in progress running */ + OSP_UPG_DL_NOFREE = 16, /**< Not enough free space on unit */ + OSP_UPG_WRONG_PARAM = 17, /**< Wrong flashing parameters */ + OSP_UPG_INTERNAL = 18 /**< Internal error */ +} osp_upg_status_t; + + +/** + * Callback invoked by target layer during download & upgrade process + * + * @param[in] op - operation: download, download CS file or upgrade + * @param[in] status status + * @param[in] completed percentage of completed work 0 - 100% + */ +typedef void (*osp_upg_cb)(const osp_upg_op_t op, + const osp_upg_status_t status, + uint8_t completed); + +/** + * Check system requirements for upgrade, like no upgrade in progress, + * available flash space etc. + */ +bool osp_upg_check_system(void); + +/** + * Download an image suitable for upgrade from @p uri and store it locally. + * Upon download and verification completion, invoke the @p dl_cb callback. + */ +bool osp_upg_dl(char *url, uint32_t timeout, osp_upg_cb dl_cb); + +/** + * Write the previously downloaded image to the system. If the image + * is encrypted, a password must be specified in @p password. + * + * After the image was successfully applied, the @p upg_cb callback is invoked. + */ +bool osp_upg_upgrade(char *password, osp_upg_cb upg_cb); + +/** + * On dual-boot system, flag the newly flashed image as the active one. + * This can be a no-op on single image systems. + */ +bool osp_upg_commit(void); + +/** + * Return a more detailed error code related to a failed osp_upg_*() function + * call. See osp_upg_status_t for a detailed list of error codes. + */ +int osp_upg_errno(void); + + +/// @} OSP_UPG +/// @} OSP + +#endif /* OSP_UPG_H_INCLUDED */ diff --git a/src/lib/osp/kconfig/Kconfig.osp_objm b/src/lib/osp/kconfig/Kconfig.osp_objm new file mode 100644 index 00000000..4d56549e --- /dev/null +++ b/src/lib/osp/kconfig/Kconfig.osp_objm @@ -0,0 +1,3 @@ +# Add objmfs options +# +source "src/lib/objmfs/kconfig/Kconfig" diff --git a/src/lib/osp/kconfig/Kconfig.osp_objm.backend b/src/lib/osp/kconfig/Kconfig.osp_objm.backend new file mode 100644 index 00000000..f6276bce --- /dev/null +++ b/src/lib/osp/kconfig/Kconfig.osp_objm.backend @@ -0,0 +1,5 @@ +config OSP_OBJM_OBJMFS + bool "Object management on filesystem (OBJMFS)" + select OBJMFS_ENABLED + help + Use the file system backend provided by the objmfs library diff --git a/src/lib/osp/kconfig/Kconfig.osp_unit.backend b/src/lib/osp/kconfig/Kconfig.osp_unit.backend new file mode 100644 index 00000000..179bc9b3 --- /dev/null +++ b/src/lib/osp/kconfig/Kconfig.osp_unit.backend @@ -0,0 +1,5 @@ +config OSP_UNIT_DEFAULT + bool "Default" + + help + Use a default implementation of OSP Unit API diff --git a/src/lib/osp/src/osp_led.c b/src/lib/osp/src/osp_led.c index 31acb123..62c371d2 100644 --- a/src/lib/osp/src/osp_led.c +++ b/src/lib/osp/src/osp_led.c @@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "osp.h" +#include "osp_led.h" static const char* led_state_str[OSP_LED_ST_LAST] = diff --git a/src/lib/osp/src/osp_objm_objmfs.c b/src/lib/osp/src/osp_objm_objmfs.c new file mode 100644 index 00000000..4adb39f3 --- /dev/null +++ b/src/lib/osp/src/osp_objm_objmfs.c @@ -0,0 +1,49 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "osp_objm.h" +#include "objmfs.h" + +/****************************************************************************** + * osp_objm API implementation + *****************************************************************************/ + +bool osp_objm_install(char *path, char *name, char *version) +{ + return objmfs_install(path, name, version); +} + +bool osp_objm_remove(char *name, char *version) +{ + return objmfs_remove(name, version); +} + +bool osp_objm_path(char *buf, size_t buffsz, char *name, char *version) +{ + return objmfs_path(buf, buffsz, name, version); +} diff --git a/src/lib/osp/src/osp_ps_psfs.c b/src/lib/osp/src/osp_ps_psfs.c index eb0c3392..5d203579 100644 --- a/src/lib/osp/src/osp_ps_psfs.c +++ b/src/lib/osp/src/osp_ps_psfs.c @@ -50,7 +50,7 @@ osp_ps_t* osp_ps_open( if (!psfs_open(&ps->ps_psfs, store, flags)) { - LOG(ERR, "osp_ps: %s: Error opening PSFS storage.", store); + LOG(DEBUG, "osp_ps: %s: Error opening PSFS storage.", store); goto error; } @@ -91,6 +91,11 @@ ssize_t osp_ps_get( return psfs_get(&ps->ps_psfs, key, value, value_sz); } +bool osp_ps_erase(osp_ps_t *ps) +{ + return psfs_erase(&ps->ps_psfs); +} + bool osp_ps_sync(osp_ps_t *ps) { return psfs_sync(&ps->ps_psfs, false); diff --git a/src/lib/osp/src/osp_reboot_pstore.c b/src/lib/osp/src/osp_reboot_pstore.c index 487de57f..3759cb7a 100644 --- a/src/lib/osp/src/osp_reboot_pstore.c +++ b/src/lib/osp/src/osp_reboot_pstore.c @@ -40,7 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "log.h" -#include "osp.h" +#include "osp_reboot.h" #include "const.h" #include "execsh.h" #include "kconfig.h" diff --git a/src/lib/osp/src/osp_unit_default.c b/src/lib/osp/src/osp_unit_default.c new file mode 100644 index 00000000..cca7c6e8 --- /dev/null +++ b/src/lib/osp/src/osp_unit_default.c @@ -0,0 +1,146 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "build_version.h" +#include "util.h" +#include "log.h" +#include "os_nif.h" + +#include "osp_unit.h" + +#ifndef TARGET_NATIVE +#pragma message("WARNING: you are using default osp_unit implementation") +#endif + + +bool osp_unit_serial_get(char *buff, size_t buffsz) +{ + memset(buff, 0, buffsz); + + os_macaddr_t mac; + size_t n; + + // get eth0 MAC address + if (true == os_nif_macaddr("eth0", &mac)) + { + n = snprintf(buff, buffsz, PRI(os_macaddr_plain_t), FMT(os_macaddr_t, mac)); + if (n >= buffsz) { + LOG(ERR, "buffer not large enough"); + return false; + } + return true; + } + + // eth0 not found, find en* interface + char interface[256]; + FILE *f; + int r; + *interface = 0; + f = popen("cd /sys/class/net; ls -d en* | head -1", "r"); + if (!f) return false; + r = fread(interface, 1, sizeof(interface), f); + if (r > 0) { + if (interface[r - 1] == '\n') r--; + interface[r] = 0; + } + pclose(f); + if (!*interface) return false; + if (true == os_nif_macaddr(interface, &mac)) + { + n = snprintf(buff, buffsz, PRI(os_macaddr_plain_t), FMT(os_macaddr_t, mac)); + if (n >= buffsz) { + LOG(ERR, "buffer not large enough"); + return false; + } + return true; + } + + return false; +} + +bool osp_unit_id_get(char *buff, size_t buffsz) +{ + return osp_unit_serial_get(buff, buffsz); +} + +bool osp_unit_model_get(char *buff, size_t buffsz) +{ + strscpy(buff, CONFIG_TARGET_MODEL, buffsz); + return true; +} + +bool osp_unit_sku_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_hw_revision_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_platform_version_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_sw_version_get(char *buff, size_t buffsz) +{ + strscpy(buff, app_build_ver_get(), buffsz); + return true; +} + +bool osp_unit_vendor_name_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_vendor_part_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_manufacturer_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_factory_get(char *buff, size_t buffsz) +{ + return false; +} + +bool osp_unit_mfg_date_get(char *buff, size_t buffsz) +{ + return false; +} + + + diff --git a/src/lib/osp/unit.mk b/src/lib/osp/unit.mk index ad9375e0..f1b441f2 100644 --- a/src/lib/osp/unit.mk +++ b/src/lib/osp/unit.mk @@ -34,7 +34,8 @@ UNIT_TYPE := LIB UNIT_CFLAGS += -I$(UNIT_PATH)/inc UNIT_EXPORT_CFLAGS := -I$(UNIT_PATH)/inc -$(eval $(if $(CONFIG_OSP_LED), UNIT_SRC += src/osp_led.c)) +UNIT_SRC += $(if $(CONFIG_OSP_UNIT_DEFAULT),src/osp_unit_default.c) +UNIT_SRC += $(if $(CONFIG_OSP_LED),src/osp_led.c) UNIT_DEPS += src/lib/common UNIT_DEPS += src/lib/log UNIT_DEPS += src/lib/schema @@ -50,4 +51,9 @@ UNIT_SRC += src/osp_ps_psfs.c UNIT_DEPS += src/lib/psfs endif +ifeq ($(CONFIG_OSP_OBJM_OBJMFS), y) +UNIT_SRC += src/osp_objm_objmfs.c +UNIT_DEPS += src/lib/objmfs +endif + UNIT_SRC += $(if $(CONFIG_OSP_L2SWITCH_NULL),src/osp_l2switch_null.c) diff --git a/src/lib/ovs_mac_learn/inc/ovs_mac_learn.h b/src/lib/ovs_mac_learn/inc/ovs_mac_learn.h index 2643ecba..1589342b 100644 --- a/src/lib/ovs_mac_learn/inc/ovs_mac_learn.h +++ b/src/lib/ovs_mac_learn/inc/ovs_mac_learn.h @@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * bridge name, interface name and MAC address */ #define OVSMAC_FLAG_ACTIVE (1 << 1) +#define FIELD_ARRAY_LEN(TYPE,FIELD) ARRAY_LEN(((TYPE*)0)->FIELD) struct ovsmac_node { @@ -47,12 +48,40 @@ struct ovsmac_node ds_tree_node_t mac_node; }; +/* + * Reduced structs. To save memory use reduced custom struct instead of complete schema struct. + * Custom reduced struct only has information that is needed for ovs mac learning to work. + */ +struct reduced_bridge +{ + char name[C_IFNAME_LEN]; + ovs_uuid_t _uuid; + ovs_uuid_t ports[FIELD_ARRAY_LEN(struct schema_Bridge, ports)]; + int ports_len; +}; + +struct reduced_port +{ + char name[C_IFNAME_LEN]; + ovs_uuid_t _uuid; + ovs_uuid_t interfaces[FIELD_ARRAY_LEN(struct schema_Port, interfaces)]; + int interfaces_len; +}; + +struct reduced_interface +{ + char name[C_IFNAME_LEN]; + ovs_uuid_t _uuid; + int ofport; + _Bool ofport_exists; +}; + /* * Bridge cache list */ struct bridge_node { - struct schema_Bridge br_bridge; + struct reduced_bridge br_bridge; ds_tree_node_t br_node; }; @@ -61,7 +90,7 @@ struct bridge_node */ struct port_node { - struct schema_Port pr_port; + struct reduced_port pr_port; ds_tree_node_t pr_node; }; @@ -70,7 +99,7 @@ struct port_node */ struct iface_node { - struct schema_Interface if_iface; + struct reduced_interface if_iface; ds_tree_node_t if_node; }; diff --git a/src/lib/ovs_mac_learn/src/ovs_mac_learn.c b/src/lib/ovs_mac_learn/src/ovs_mac_learn.c index 883e0f94..88978071 100644 --- a/src/lib/ovs_mac_learn/src/ovs_mac_learn.c +++ b/src/lib/ovs_mac_learn/src/ovs_mac_learn.c @@ -313,7 +313,7 @@ bool ovsmac_scan_br(char *brif) } } - LOG(DEBUG, "bridge:%s ofport:%s vlan:%s mac:%s\n", brif, ifname, svlan, smac); + LOG(DEBUG, "OVSMAC: bridge:%s ofport:%s vlan:%s mac:%s\n", brif, ifname, svlan, smac); /* * Check if given interface is in interface filter list @@ -488,11 +488,41 @@ int ovsmac_cmp_fn(void *_a, void *_b) * Bridge table functions * =========================================================================== */ +static void bridge_schema_to_reduced(const struct schema_Bridge *s_br, struct reduced_bridge *r_br) +{ + int i; + int len; + int dst_buf_len; + + /* Copy data from schema to reduced struct */ + STRSCPY_WARN(r_br->name, s_br->name); + r_br->_uuid = s_br->_uuid; + len = s_br->ports_len; + + dst_buf_len = ARRAY_LEN(r_br->ports); + + if (dst_buf_len < s_br->ports_len) + { + LOG(WARN, "OVSMAC: Destination buffer too small (%d vs %d), skip copying part of Bridge ports", + dst_buf_len, s_br->ports_len); + + len = dst_buf_len; + } + + for (i = 0; i < len; i++) + { + r_br->ports[i] = s_br->ports[i]; + } + + r_br->ports_len = len; +} + void bridge_mon_fn(ovsdb_update_monitor_t *self) { pjs_errmsg_t pjerr; struct bridge_node *bn = NULL; + struct schema_Bridge btmp; switch (self->mon_type) { @@ -506,7 +536,7 @@ void bridge_mon_fn(ovsdb_update_monitor_t *self) } if (!schema_Bridge_from_json( - &bn->br_bridge, + &btmp, self->mon_json_new, false, pjerr)) @@ -516,6 +546,8 @@ void bridge_mon_fn(ovsdb_update_monitor_t *self) return; } + bridge_schema_to_reduced(&btmp, &(bn->br_bridge)); + /* Insert interface into tree */ ds_tree_insert(&bridge_list, bn, bn->br_bridge._uuid.uuid); @@ -532,9 +564,8 @@ void bridge_mon_fn(ovsdb_update_monitor_t *self) return; } - /* Update entry */ if (!schema_Bridge_from_json( - &bn->br_bridge, + &btmp, self->mon_json_new, true, pjerr)) @@ -543,6 +574,9 @@ void bridge_mon_fn(ovsdb_update_monitor_t *self) return; } + /* Update entry */ + bridge_schema_to_reduced(&btmp, &(bn->br_bridge)); + LOG(DEBUG, "OVSMAC: Modified bridge interface: %s", bn->br_bridge.name); break; @@ -574,11 +608,41 @@ void bridge_mon_fn(ovsdb_update_monitor_t *self) * Port table functions * =========================================================================== */ +static void port_schema_to_reduced(const struct schema_Port *s_pr, struct reduced_port *r_pr) +{ + int i; + int len; + int dst_buf_len; + + /* Copy data from schema to reduced struct */ + STRSCPY_WARN(r_pr->name, s_pr->name); + r_pr->_uuid = s_pr->_uuid; + len = s_pr->interfaces_len; + + dst_buf_len = ARRAY_LEN(r_pr->interfaces); + + if (dst_buf_len < s_pr->interfaces_len) + { + LOG(WARN, "OVSMAC: Destination buffer too small (%d vs %d), skip copying part of Port interfaces", + dst_buf_len, s_pr->interfaces_len); + + len = dst_buf_len; + } + + for (i = 0; i < len; i++) + { + r_pr->interfaces[i] = s_pr->interfaces[i]; + } + + r_pr->interfaces_len = len; +} + void port_mon_fn(ovsdb_update_monitor_t *self) { pjs_errmsg_t pjerr; struct port_node *pr = NULL; + struct schema_Port prtmp; switch (self->mon_type) { @@ -591,7 +655,7 @@ void port_mon_fn(ovsdb_update_monitor_t *self) } if (!schema_Port_from_json( - &pr->pr_port, + &prtmp, self->mon_json_new, false, pjerr)) @@ -601,6 +665,10 @@ void port_mon_fn(ovsdb_update_monitor_t *self) return; } + /* Copy data to reduced struct */ + port_schema_to_reduced(&prtmp, &(pr->pr_port)); + + /* Insert interface into tree */ ds_tree_insert(&port_list, pr, pr->pr_port._uuid.uuid); LOG(DEBUG, "OVSMAC: Added Port added: %s", pr->pr_port.name); @@ -616,9 +684,8 @@ void port_mon_fn(ovsdb_update_monitor_t *self) return; } - /* Update entry */ if (!schema_Port_from_json( - &pr->pr_port, + &prtmp, self->mon_json_new, true, pjerr)) @@ -627,6 +694,9 @@ void port_mon_fn(ovsdb_update_monitor_t *self) return; } + /* Update entry */ + port_schema_to_reduced(&prtmp, &(pr->pr_port)); + LOG(DEBUG, "OVSMAC: Modified port: %s", pr->pr_port.name); break; @@ -659,11 +729,21 @@ void port_mon_fn(ovsdb_update_monitor_t *self) * Interface table functions * =========================================================================== */ +static void iface_schema_to_reduced(const struct schema_Interface *s_if, struct reduced_interface *r_if) +{ + /* Copy data from schema to reduced struct */ + STRSCPY_WARN(r_if->name, s_if->name); + r_if->_uuid = s_if->_uuid; + r_if->ofport = s_if->ofport; + r_if->ofport_exists = s_if->ofport_exists; +} + void iface_mon_fn(ovsdb_update_monitor_t *self) { pjs_errmsg_t pjerr; struct iface_node *ifn = NULL; + struct schema_Interface iftmp; switch (self->mon_type) { @@ -676,7 +756,7 @@ void iface_mon_fn(ovsdb_update_monitor_t *self) } if (!schema_Interface_from_json( - &ifn->if_iface, + &iftmp, self->mon_json_new, false, pjerr)) @@ -685,6 +765,10 @@ void iface_mon_fn(ovsdb_update_monitor_t *self) return; } + /* Copy data to reduced struct */ + iface_schema_to_reduced(&iftmp, &(ifn->if_iface)); + + /* Insert interface into tree */ ds_tree_insert(&iface_list, ifn, ifn->if_iface._uuid.uuid); LOG(DEBUG, "OVSMAC: Added interface: %s", ifn->if_iface.name); @@ -700,9 +784,8 @@ void iface_mon_fn(ovsdb_update_monitor_t *self) return; } - /* Update entry */ if (!schema_Interface_from_json( - &ifn->if_iface, + &iftmp, self->mon_json_new, true, pjerr)) @@ -711,6 +794,9 @@ void iface_mon_fn(ovsdb_update_monitor_t *self) return; } + /* Update entry */ + iface_schema_to_reduced(&iftmp, &(ifn->if_iface)); + LOG(DEBUG, "OVSMAC: Modified interface: %s", ifn->if_iface.name); break; diff --git a/src/lib/policy_tags/inc/policy_tags.h b/src/lib/policy_tags/inc/policy_tags.h index 3b8502f5..0a1fcfe6 100644 --- a/src/lib/policy_tags/inc/policy_tags.h +++ b/src/lib/policy_tags/inc/policy_tags.h @@ -52,6 +52,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define TEMPLATE_GROUP_END ']' #define TEMPLATE_DEVICE_CHAR '@' +#define TEMPLATE_LOCAL_CHAR '*' #define TEMPLATE_CLOUD_CHAR '#' typedef enum { @@ -84,6 +85,7 @@ typedef struct { ds_tree_t updated; } om_tag_list_diff_t; +extern char *om_tag_get_tle_flag(int flag_enum); extern bool om_tag_list_entry_add(ds_tree_t *list, char *value, uint8_t flags); extern bool om_tag_list_append_list(ds_tree_t *dest, @@ -109,12 +111,22 @@ extern om_tag_list_entry_t * /****************************************************************************** * Tag Definitions *****************************************************************************/ +enum om_tle_flag +{ + OM_TLE_FLAG_DEVICE = 1 << 0, + OM_TLE_FLAG_LOCAL = 1 << 1, + OM_TLE_FLAG_CLOUD = 1 << 2, + OM_TLE_FLAG_GROUP = 1 << 3, + OM_TLE_FLAG_NONE = 1 << 4, +}; -#define OM_TLE_FLAG_DEVICE (1 << 0) -#define OM_TLE_FLAG_CLOUD (1 << 1) -#define OM_TLE_FLAG_GROUP (1 << 2) +struct om_mapping_tle_flag +{ + char *flag; + int flag_enum; +}; -#define OM_TLE_VAR_FLAGS(x) (x & (OM_TLE_FLAG_DEVICE | OM_TLE_FLAG_CLOUD)) +#define OM_TLE_VAR_FLAGS(x) (x & (OM_TLE_FLAG_LOCAL | OM_TLE_FLAG_DEVICE | OM_TLE_FLAG_CLOUD)) typedef struct { char *name; @@ -132,6 +144,9 @@ extern bool om_tag_update(om_tag_t *tag, ds_tree_t *new_values); extern bool om_tag_add_from_schema(struct schema_Openflow_Tag *stag); extern bool om_tag_remove_from_schema(struct schema_Openflow_Tag *stag); extern bool om_tag_update_from_schema(struct schema_Openflow_Tag *stag); +extern bool om_local_tag_add_from_schema(struct schema_Openflow_Local_Tag *stag); +extern bool om_local_tag_remove_from_schema(struct schema_Openflow_Local_Tag *stag); +extern bool om_local_tag_update_from_schema(struct schema_Openflow_Local_Tag *stag); extern om_tag_t * om_tag_alloc(const char *name, bool group); extern om_tag_t * @@ -180,6 +195,15 @@ extern om_tag_group_t * */ int om_tag_get_type(char *name); +/** + * @brief return the tag source based on its name + * + * Lets the caller know if the string is a device tag, cloud tag or local tag. + * @param name the string to check. + */ +int +om_get_type_of_tag(char *name); + /** * @brief checks if a string is included in an opensync tag diff --git a/src/lib/policy_tags/src/policy_tag_groups.c b/src/lib/policy_tags/src/policy_tag_groups.c index 54104169..3e36d5c5 100644 --- a/src/lib/policy_tags/src/policy_tag_groups.c +++ b/src/lib/policy_tags/src/policy_tag_groups.c @@ -107,6 +107,11 @@ om_tag_group_create_list_from_schema(ds_tree_t *list, name++; flags |= OM_TLE_FLAG_CLOUD; } + else if (*name == TEMPLATE_LOCAL_CHAR) { + name++; + flags |= OM_TLE_FLAG_LOCAL; + } + if (!om_tag_list_entry_add(list, name, flags)) { goto alloc_err; } diff --git a/src/lib/policy_tags/src/policy_tag_list.c b/src/lib/policy_tags/src/policy_tag_list.c index 96f96738..1b6f050f 100644 --- a/src/lib/policy_tags/src/policy_tag_list.c +++ b/src/lib/policy_tags/src/policy_tag_list.c @@ -327,6 +327,9 @@ om_tag_list_to_buf(ds_tree_t *list, uint8_t flags, char *buf, int buf_len) if (tle->flags & OM_TLE_FLAG_CLOUD) { strcat(fstr, "C"); } + if (tle->flags & OM_TLE_FLAG_LOCAL) { + strcat(fstr, "L"); + } if (tle->flags & OM_TLE_FLAG_GROUP) { strcat(fstr, "G"); } diff --git a/src/lib/policy_tags/src/policy_tag_utils.c b/src/lib/policy_tags/src/policy_tag_utils.c index bd75feaa..a4ecdc1a 100644 --- a/src/lib/policy_tags/src/policy_tag_utils.c +++ b/src/lib/policy_tags/src/policy_tag_utils.c @@ -29,6 +29,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "log.h" #include "policy_tags.h" +static const struct om_mapping_tle_flag tle_flag_map[] = +{ + { + .flag = "device", + .flag_enum = OM_TLE_FLAG_DEVICE, + }, + { + .flag = "cloud", + .flag_enum = OM_TLE_FLAG_CLOUD, + }, + { + .flag = "local", + .flag_enum = OM_TLE_FLAG_LOCAL, + }, + { + .flag = "group", + .flag_enum = OM_TLE_FLAG_GROUP, + } +}; + +/** + * @brief return the flag based on its enum value + * + * @param flag_enum the flag represented as an integer. + */ +char * +om_tag_get_tle_flag(int flag_enum) +{ + const struct om_mapping_tle_flag *map; + size_t nelems; + size_t i; + + /* Walk the known flags */ + nelems = (sizeof(tle_flag_map) / sizeof(tle_flag_map[0])); + map = tle_flag_map; + for (i = 0; i < nelems; i++) + { + if (flag_enum == map->flag_enum) return map->flag; + map++; + } + + return NULL; +} + /** * @brief return the tag type based on its name * @@ -67,6 +111,28 @@ om_tag_get_type(char *name) return NOT_A_OPENSYNC_TAG; } +/** + * @brief return the tag source based on its name + * + * Lets the caller know if the string is a device tag, cloud tag or local tag. + * @param name the string to check. + */ +int +om_get_type_of_tag(char *name) +{ + if (name == NULL) return -1; + + if(om_tag_get_type(name) == NOT_A_OPENSYNC_TAG) return OM_TLE_FLAG_NONE; + + if (name[2] == TEMPLATE_DEVICE_CHAR) + return OM_TLE_FLAG_DEVICE; + else if (name[2] == TEMPLATE_CLOUD_CHAR) + return OM_TLE_FLAG_CLOUD; + else if (name[2] == TEMPLATE_LOCAL_CHAR) + return OM_TLE_FLAG_LOCAL; + else + return OM_TLE_FLAG_NONE; +} /** * @brief checks if a string is included in an opensync tag @@ -105,6 +171,11 @@ om_tag_in(char *value, char *tag_name) match_flags = OM_TLE_FLAG_CLOUD; tag_s += 1; } + else if (*tag_s == TEMPLATE_LOCAL_CHAR) + { + match_flags = OM_TLE_FLAG_LOCAL; + tag_s += 1; + } /* Copy tag name, remove end marker */ STRSCPY_LEN(name, tag_s, -1); diff --git a/src/lib/policy_tags/src/policy_tags.c b/src/lib/policy_tags/src/policy_tags.c index 851a1c8b..43afb3cd 100644 --- a/src/lib/policy_tags/src/policy_tags.c +++ b/src/lib/policy_tags/src/policy_tags.c @@ -97,6 +97,26 @@ om_tag_add_list_from_schema(ds_tree_t *list, struct schema_Openflow_Tag *stag) return false; } +// Fill in a local tag list from schema +static bool +om_local_tag_add_list_from_schema(ds_tree_t *list, struct schema_Openflow_Local_Tag *stag) +{ + int i; + + // Local Value Array + for(i = 0;i < stag->values_len;i++) { + if (!om_tag_list_entry_add(list, stag->values[i], OM_TLE_FLAG_LOCAL)) { + goto err; + } + } + + return true; + +err: + return false; +} + + // Allocate a new tag, using data from schema row static om_tag_t * @@ -124,6 +144,33 @@ om_tag_alloc_from_schema(struct schema_Openflow_Tag *stag) return NULL; } +// Allocate a new tag, using data from schema row +static om_tag_t * +om_local_tag_alloc_from_schema(struct schema_Openflow_Local_Tag *stag) +{ + om_tag_t *tag; + + if (!(tag = om_tag_alloc(stag->name, false))) { + goto alloc_err; + } + + // Cloud and Device Value Arrays + if (!om_local_tag_add_list_from_schema(&tag->values, stag)) { + LOGEM("Failed to add list for local tag '%s'", stag->name); + goto alloc_err; + } + + return tag; + +alloc_err: + if (tag) { + om_tag_free(tag); + } + + return NULL; +} + + /****************************************************************************** * Public Functions @@ -360,6 +407,65 @@ om_tag_update_from_schema(struct schema_Openflow_Tag *stag) return ret; } +// Add a new local tag from schema row +bool +om_local_tag_add_from_schema(struct schema_Openflow_Local_Tag *new) +{ + om_tag_t *tag; + + if (!(tag = om_local_tag_alloc_from_schema(new))) { + // Allocation failure -- reported already + return false; + } + + if (!om_tag_add(tag)) { + om_tag_free(tag); + return false; + } + + return true; +} + +// Remove a tag from schema flow +bool +om_local_tag_remove_from_schema(struct schema_Openflow_Local_Tag *stag) +{ + om_tag_t *tag; + + if (!(tag = om_tag_find_by_name(stag->name, false))) { + // Not found + return false; + } + + return om_tag_remove(tag); +} + +// Update a tag from schema flow +bool +om_local_tag_update_from_schema(struct schema_Openflow_Local_Tag *stag) +{ + ds_tree_t new_values; + om_tag_t *tag; + bool ret; + + if (!(tag = om_tag_find_by_name(stag->name, false))) { + // Not found + return false; + } + + // Build new list + om_tag_list_init(&new_values); + if (!om_local_tag_add_list_from_schema(&new_values, stag)) { + LOGE("[%s] Failed to allocate memory to handle update!", tag->name); + return false; + } + + ret = om_tag_update(tag, &new_values); + om_tag_list_free(&new_values); + + return ret; +} + void om_tag_init(struct tag_mgr *mgr) { memcpy(&my_mgr_s, mgr, sizeof(my_mgr_s)); diff --git a/src/lib/policy_tags/ut/test_schema_tags.c b/src/lib/policy_tags/ut/test_schema_tags.c index 1b30b0ed..b7dd671e 100644 --- a/src/lib/policy_tags/ut/test_schema_tags.c +++ b/src/lib/policy_tags/ut/test_schema_tags.c @@ -160,6 +160,70 @@ test_tag_type(void) } } +void +test_type_of_tag(void) +{ + struct tag_validate + { + char *name; + int flag; + } tag_types[] = + { + { + .name = "coucou", + .flag = OM_TLE_FLAG_NONE, + }, + { + .name = "${&}", + .flag = OM_TLE_FLAG_NONE, + }, + { + .name = "${@}", + .flag = OM_TLE_FLAG_DEVICE, + }, + { + .name = "${#}", + .flag = OM_TLE_FLAG_CLOUD, + }, + { + .name = "${*}", + .flag = OM_TLE_FLAG_LOCAL, + }, + { + .name = "$[&]", + .flag = OM_TLE_FLAG_NONE, + }, + { + .name = "$[@]", + .flag = OM_TLE_FLAG_DEVICE, + }, + { + .name = "$[#]", + .flag = OM_TLE_FLAG_CLOUD, + }, + { + .name = "$[*]", + .flag = OM_TLE_FLAG_LOCAL, + }, + }; + + int expected; + char *name; + size_t len; + int flag; + size_t i; + + len = sizeof(tag_types) / sizeof(tag_types[0]); + + for (i = 0; i < len; i++) + { + name = tag_types[i].name; + expected = tag_types[i].flag; + flag = om_get_type_of_tag(name); + TEST_ASSERT_EQUAL_INT(expected, flag); + } +} + void setUp(void) @@ -296,6 +360,7 @@ main(int argc, char *argv[]) UnityBegin(g_test_name); RUN_TEST(test_tag_type); + RUN_TEST(test_type_of_tag); RUN_TEST(test_val_in_tag); RUN_TEST(test_val_in_tag_group); diff --git a/src/lib/psfs/inc/psfs.h b/src/lib/psfs/inc/psfs.h index decfdcfb..6b332b18 100644 --- a/src/lib/psfs/inc/psfs.h +++ b/src/lib/psfs/inc/psfs.h @@ -59,6 +59,7 @@ bool psfs_open(psfs_t *ps, const char *name, int flags); bool psfs_close(psfs_t *ps); bool psfs_load(psfs_t *ps); bool psfs_sync(psfs_t *ps, bool force_prune); +bool psfs_erase(psfs_t *ps); ssize_t psfs_set(psfs_t *ps, const char *key, const void *value, size_t value_sz); ssize_t psfs_get(psfs_t *ps, const char *key, void *value, size_t value_sz); diff --git a/src/lib/psfs/src/psfs.c b/src/lib/psfs/src/psfs.c index f165441a..70024281 100644 --- a/src/lib/psfs/src/psfs.c +++ b/src/lib/psfs/src/psfs.c @@ -147,7 +147,7 @@ bool psfs_open(psfs_t *ps, const char *name, int flags) ps->psfs_fd = openat(ps->psfs_dirfd, name, oflags, 0600); if (ps->psfs_fd < 0) { - LOG(ERR, "psfs: %s: Error opening store. Error: %s", + LOG(DEBUG, "psfs: %s: Error opening store. Error: %s", ps->psfs_name, strerror(errno)); goto error; @@ -390,6 +390,53 @@ bool psfs_load(psfs_t *ps) return true; } +/** + * Erase a PSFS store (delete all keys and their values). This flags the store + * as dirty and will be written to disk at the first psfs_sync() or psfs_close() + * operation. + * + * @return + * This function will return true on success, or false on error. + * + * @note + * If the store is opened in read-only mode (OSP_PS_READ), it will return an + * error. + */ +bool psfs_erase(psfs_t *ps) +{ + struct psfs_record *pr; + ds_tree_iter_t iter; + + if ((ps->psfs_flags & OSP_PS_WRITE) == 0) + { + /* psfs_erase() not supported in read-only mode */ + return false; + } + + /* Truncate file to 0 bytes */ + if (ftruncate(ps->psfs_fd, 0) != 0) + { + LOG(ERR, "psfs: %s: Error truncating store (erase).", ps->psfs_name); + return false; + } + + /* Move file pointer to the beginning of the file */ + if (lseek(ps->psfs_fd, 0, SEEK_SET) != 0) + { + LOG(ERR, "psfs: %s: Error seeking to the beginning of file (erase).", ps->psfs_name); + return false; + } + + /* Drop all in-memory records */ + ds_tree_foreach_iter(&ps->psfs_root, pr, &iter) + { + LOG(DEBUG, "psfs: %s: Deleting record '%s'.", ps->psfs_name, pr->pr_key); + psfs_drop_record(ps, pr, &iter); + } + + return true; +} + /** * Set the value of a single key. This flags the record associated with the key * as dirty and will be written to disk at the first psfs_sync() or psfs_close() diff --git a/src/lib/stam/README.md b/src/lib/stam/README.md new file mode 100644 index 00000000..2f8b9c9e --- /dev/null +++ b/src/lib/stam/README.md @@ -0,0 +1,489 @@ +# State Machine Library (libstam) + +`libstam` is a finite state machine library. The majority of the library is +implemented as a header file using +[Xmacros](https://en.wikipedia.org/wiki/X_Macro). + +See the [Example](#example) below. + +## Design Principles + +Each state machine using `libstam` must define a set of states and a set of +actions. Optionally it can define a set of exceptions. Using this information, +`libstam` will automatically create the following code for you: + + - State structure + - State and exception enums and associated helper functions + - State machine functions (action and state switch/dispatcher) + - State handlers prototypes (the actual implementation must be provided by + the user) + +### Code and header generation + +Before including the `libstam` header file, the user of the library must define +the following macros: + + - `STAM_NAME` to define the state machine name; this is used to prefix most + of the generate C symbols + - `STAM_STATES` to define all possible state machine states, this is an Xmacro + list + - `STAM_ACTIONS` to define all possible actions (or messages), this is an + Xmacro list + +And optionally: + - `STAM_EXCEPTIONS` is used to define possible actions that force a fast + switch to the `EXCEPTION` state. If this macro is defined, the `EXCEPTION` + state will be implicitly generated. However, the user must still implement + a state handler. + +Using the `STAM_NAME`, `STAM_STATES` and `STAM_ACTIONS` user-defined macros, +`libstam` will automatically generate the state structure and enums describing +all states and actions. + +Additionally, the user must select what kind of source code must be generated +by using the following two macros: + + - `STAM_GENERATE_HEADER` will generate only code that should be present in + header files + - `STAM_GENERATE_SOURCE` will generate the code body + +#### States Enum Generation + +If STAM_GENERATE_HEADER is defined, for each state defined in `STAM_STATES`, a C +symbol will be generated as follows: + + - Concatenate `STAM_NAME` and append `_state` to generate the enum name + - Concatenate `STAM_NAME` and append `_` and the state name to generate an enum + entry + - Concatenate `STAM_NAME` and append `_state_str` to generate the helper + function for converting state constants to strings + +Using the [example](#example) below, the following code will be generated: + + enum foo_state + { + foo_INIT, + foo_IDLE, + foo_RUNNING + }; + + const char *foo_state_str(enum foo_state state); + +_Note: If `STAM_EXCEPTIONS` is defined, one additional state is implicitly +generated: `foo_EXCEPTION`._ + +#### Actions Enum Generation + +If STAM_GENERATE_HEADER is defined, for each action defined in `STAM_ACTION`, a C +symbol will be generated as follows: + + - Concatenate `STAM_NAME` and append `_action` to generate the enum name + - Concatenate `STAM_NAME` and append `_do_STATE_INIT` to generate + an implicit `STATE_INIT` action + - Concatenate `STAM_NAME` and append `_do_` and the action name to generate an + enum entry + - Concatenate `STAM_NAME` and append `_action_str` to generate the helper + function for converting state constants to strings + +Using the [example](#example) below, the following code will be generated: + + enum foo_action + { + foo_do_STATE_INIT = 0, /* Implicitly generated */ + foo_do_RUN, + foo_do_STOP, + foo_do_EXIT + }; + + const char *foo_action_str(enum foo_state state); + +##### STATE_INIT Action + +`foo_do_STATE_INIT` is implicitly generated. The action is issued to the state +handler when the state machine switches to the new state, which can be used to +initialize the state as this action is called exactly once. The STATE_INIT +action is execute for each normal state transitions. + +An exception to this is the EXCEPTION state. Exceptions break the current flow +of the state machine and fast transition to the EXCEPTION state, without sending +the STATE_INIT action first. The EXCEPTION state transitions to other states +normally. + +#### State Structure Generation + +If `STAM_GENERATE_HEADER` is defined, single structure will be generated that +will be used for state tracking. The structure is generated as follows: + + - Conctenate `STAM_NAME` and append `_state_t`, this will be the name of the + typedeffed anonymous structure. + +#### State Machine Function Generation + +If `STAM_GENERATE_SOURCE` is defined, state switch and state disaptcher functions +(switch-case to translate the states enum to function calls) will be generated +according to the following rules: + + - Use `STAM_NAME` and append `_state_do` to generate the main state switch + function. + - Use `STAM_NAME` and append `_state_get` to generate the function to + return the current state. + - Use `STAM_NAME` and append `_state_prev` to generate the function to + return the previous state. + +The `_state_do` is the state switch/dispatcher function. The state machine +itself should be considered a black-box and `_state_do` should be used to send +actions to it. `_state_do` will return the current state or a negative number +if an error occurred. + +The `_state_get` function is used to retrieve the current state of the state +machine. + +The pseudo code that will be generated for [example](#example): + + enum foo_state foo_state_do(foo_state_t *state, enum foo_action, void *data); + enum foo_state foo_state_get(foo_state_t *state); + +Example code usage (send the action STOP to the state machine): + + foo_state_do(&state, FOO_do_STOP, NULL); + +### State Handlers + +Each state must have a corresponding state handler. `libstam` takes care of +generating prototypes and dispatcher functions for state handlers, however, the +state handler implementation must be provided by the user. + +The state handler C symbol name is generated according to the following rules: + + - Use `STAM_NAME` and append `_state_` and the state name + +Using the [example](#example) below, the following prototypes will be generated: + + enum foo_state foo_state_INIT(foo_state_t *state, enum foo_action action, void *data); + enum foo_state foo_state_IDLE(foo_state_t *state, enum foo_action action, void *data); + enum foo_state foo_state_RUNNING(foo_state_t *state, enum foo_action action, void *data); + +The first call to the state handler will always be the `STATE_INIT` action (with +the exception of the EXCEPTION state, which executes the action immediately). +This is used as state initializer. Otherwise the action will be the one supplied +by the `_state_do()` function. + +State handlers must react to actions and will be invoked by the `_state_do()` +function. The state handlers are also able to switch states by returning the +state they wish to switch to. The return value is interpreted as follows: + + - 0 or the current state -- this informs `_state_do()` that the state is + currently busy and is waiting for an external event or action + - A new state that the state machine must switch to (`_state_do()` will be + responsible for turning the wheels and, for example, sending the `STATE_INIT` + action first) + - Returning the current state will cause a re-transition to itself + - Negative values are treated as errors and `_state_do()` returns immediately + by forwarding the negative value to the caller + +## Usage + +The `_state_t` structure must be initialized to 0 (memset or otherwise). The +state machine will be initialized by default to the first state defined in the +`STAM_STATES` macro. The state machine should be considered a black box -- it can +only accept actions, not actual forced state switches. It is up to the state +handlers to react to the requested action and switch to the desired state. + +The main API for sending actions to the state machine is the `_state_do()` +function. This function will loop and dispatch the actions to the current state +handler until the state handler either returns 0 or the current state. This +indicates that the current state is busy waiting for an external event/action. + +# Example + +This is a simple example of the `libstam` usage. It is used throughout +this README as reference. + + #include + #include + + /* + * Define the state machine name; the name will be prepended to the + * generated C symbols + */ + #define STAM_NAME foo + + /* Define the list of possible states */ + #define STAM_STATES(state) \ + state(INIT) \ + state(IDLE) \ + state(RUNNING) + + /* Define list of actions */ + #define STAM_ACTIONS(action) \ + action(START) \ + action(STOP) \ + action(EXIT) + + /* + * Define list of exceptions -- exceptions are actions that fast switch + * to the EXCEPTION state. If exceptions are defined, an EXCEPTION state + * will be implicitly generated. + */ + + /* Generate headers */ + #define STAM_GENERATE_HEADER + + /* Generate soruce */ + #define STAM_GENERATE_SOURCE + + /* Debugging function */ + #define STAM_LOG(...) do { printf(__VA_ARGS__); printf("\n"); } while (0) + + #include "inc/stam.h" + + enum foo_state foo_state_INIT(foo_state_t *state, enum foo_action act, void *data) + { + (void)state; + (void)data; + + printf("INIT state received %s.\n", foo_action_str(act)); + + switch (act) + { + case foo_do_START: + return foo_RUNNING; + + case foo_do_STOP: + return foo_IDLE; + + case foo_do_EXIT: + printf("Warning: foo was never started.\n"); + exit(1); + + default: + break; + } + + return 0; + } + + enum foo_state foo_state_RUNNING(foo_state_t *state, enum foo_action act, void *data) + { + (void)state; + (void)data; + + printf("RUNNING state received %s.\n", foo_action_str(act)); + + switch (act) + { + case foo_do_STATE_INIT: + printf("STARTING SERVICE\n"); + break; + + case foo_do_START: + printf("Already running, nothing to do.\n"); + break; + + case foo_do_STOP: + return foo_IDLE; + + case foo_do_EXIT: + printf("Service must be stopped first.\n"); + break; + } + return 0; + } + + enum foo_state foo_state_IDLE(foo_state_t *state, enum foo_action act, void *data) + { + (void)state; + (void)data; + + printf("IDLE state received %s.\n", foo_action_str(act)); + + switch (act) + { + case foo_do_STATE_INIT: + /* + * The state switches after STATE_INIT is processed; we can + * inspect the previous state here. + */ + if (foo_state_get(state) != foo_INIT) + { + printf("STOPPING SERVICE\n"); + } + break; + + case foo_do_START: + return foo_RUNNING; + + case foo_do_STOP: + printf("Service already stopped.\n"); + break; + + case foo_do_EXIT: + printf("Exiting...\n"); + exit(1); + } + return 0; + } + + int main(void) + { + char *rl; + + foo_state_t state = {0}; + + printf("Available commands: start stop exit\n\n"); + + while ((rl = readline("> ")) != NULL) + { + if (strcasecmp(rl, "start") == 0) + { + printf("Action START\n"); + foo_state_do(&state, foo_do_START, NULL); + } + else if (strcasecmp(rl, "stop") == 0) + { + printf("Action STOP\n"); + foo_state_do(&state, foo_do_STOP, NULL); + } + else if (strcasecmp(rl, "exit") == 0) + { + printf("Action EXIT\n"); + foo_state_do(&state, foo_do_EXIT, NULL); + } + else + { + printf("Unknown command: %s\n", rl); + } + + free(rl); + } + } + +_Warning: libreadline is required for the example to compile._ + +## Code generation +STAM comes with optional code generator capable of genertaing C source code for state machines defined in DOT format. Here's sample executable unit called `foo` showing how to integrate STAM + code generation with OpenSync build system. + +The code generstor is written in Python 3 and requires [PyDot](https://pypi.org/project/pydot/) package. + +Unit structure: +``` +$ tree src/foo/ +src/foo/ +├── foo.dot +├── src +│   └── foo.c +└── unit.mk +``` + +`foo.dot`: +``` +digraph { + a -> b [label="START"]; + a -> b [label="QUICK_START"]; + a -> d [label="STOP"]; + b -> b [label="IDLE"]; + b -> c [label="DO_STH"], + c -> d [label="STOP"]; + d -> a; +} +``` +To define the default (initial) state, a node has to be defined with the `init` +attribute set. For example: + +``` +digraph { + a[init=true]; + ... +} +``` + +Exceptions are defined by prefixing the action name with `!`. Exceptions are +legal only when transition to or from the `EXCEPTION` state. When the `EXCEPTION` +state is defined in the .dot file, the `STAM_EXCEPTIONS` macro will be +automatically generated. Any state transitioning to the `EXCEPTION` state is +ignored -- legally any state can transition to `EXCEPTION`, so the +`X -> EXCEPTION` is used only to generate the exception list. The node `X` +however may be used to describe in more detail the exception (the mechanic, why +it happens, etc.). + +The example below defines a `TIMEOUT` and a `HARD_RESET` exception. The +`EXCEPTION` state can transition immediately to the `INIT` state upon receiving +the `HARD_RESET` exception. However, it will remain in the `EXCEPTION` state when +a `TIMEOUT` exception has occurred. To recover from this situation, a `RESTART` +action must be issued. + +digraph { + .... + + EX_TIMEOUT[label="The TIMEOUT exceptions occurrs after 30 seconds."]; + EX_TIMEOUT -> EXCEPTION [label="!TIMEOUT"]; + EX_HARD_RESET[label="Forcibly restart the sequence."]; + EX_HARD_RESET -> EXCEPTION [label="!HARD_RESET"]; + + EXCEPTION -> INIT [label="RESTART"]; + EXCEPTION -> INIT [label="!HARD_RESET"]; + .... +} + +Only exceptions can transition to the `EXCEPTION` state. However, the `EXCEPTION` +state can transition to other states using exceptions OR actions. + +`foo.c`: +``` +#include + +#define LOG(x, ... ) printf(__VA_ARGS__);printf("\n") + +#define STAM_GENERATE_SOURCE +#define STAM_GENERATE_HEADER +#include "foo_gen.h" +#include "stam.h" + +enum foo_state foo_state_A(foo_state_t *state, enum foo_action act, void *data) { + if (act == foo_do_STATE_INIT) + return 0; + else if (act == foo_do_START) + return foo_B; + else + return -1; +} +enum foo_state foo_state_B(foo_state_t *state, enum foo_action act, void *data) { + if (act == foo_do_DO_STH) + return foo_A; // This is expected to fail + else + return foo_B; // This is expected to fail +} +enum foo_state foo_state_C(foo_state_t *state, enum foo_action act, void *data) { + return foo_B; +} +enum foo_state foo_state_D(foo_state_t *state, enum foo_action act, void *data) { + return foo_D; +} + +int main() +{ + foo_state_t state = {0}; + foo_state_do(&state, foo_do_START, NULL); + foo_state_do(&state, foo_do_START, NULL); + foo_state_do(&state, foo_do_STOP, NULL); // This is expected to fail + foo_state_do(&state, foo_do_DO_STH, NULL); +} +``` + +The STAM generator fully supports unit.mk files and adding a state machine to +your project is just a matter of calling `stam_generate` make template: + +``` +UNIT_NAME := foo +UNIT_TYPE := BIN + +UNIT_CFLAGS := -I$(UNIT_BUILD) +UNIT_CFLAGS += -I$(TOP_DIR)/src/lib/stam/inc/ + +UNIT_SRC := src/foo.c + +# Generate state machine foo +$(eval $(call stam_generate, foo.dot)) + +``` + diff --git a/src/lib/stam/devtest/stamtest.c b/src/lib/stam/devtest/stamtest.c new file mode 100644 index 00000000..eead553f --- /dev/null +++ b/src/lib/stam/devtest/stamtest.c @@ -0,0 +1,160 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "log.h" + +#include "test_stam.h" + +#define FAIL(...) \ + do \ + { \ + LOG(ERR, "[FAIL] " __VA_ARGS__); \ + exit(1); \ + } \ + while (0) + +#define PASS(...) \ + do \ + { \ + LOG(NOTICE, "[PASS] " __VA_ARGS__); \ + } \ + while (0) + + +enum test_state test_state_INIT(test_state_t *state, enum test_action action, void *data) +{ + (void)state; + (void)action; + (void)data; + + if (action == test_do_STATE_INIT) + { + PASS("STATE_INIT in INIT state.\n"); + return test_RETRANSITION; + } + + FAIL("INIT state received action: %s", test_action_str(action)); + + return 0; +} + +enum test_state test_state_RETRANSITION(test_state_t *state, enum test_action action, void *data) +{ + static int count = 0; + + if (action != test_do_STATE_INIT) + { + FAIL("RETRANSIITON state received invalid action: %s", test_action_str(action)); + return -1; + } + + if (count++ >= 2) + { + FAIL("RETRANSITION state has too many retransitions\n"); + } + + if (test_state_prev(state) == test_INIT) + { + return test_RETRANSITION; + } + else if (test_state_prev(state) == test_RETRANSITION) + { + PASS("Retransition success\n"); + PASS("This also means that STAM_state_prev() works.\n"); + return test_RUNNING; + } + + return 0; +} + +enum test_state test_state_RUNNING(test_state_t *state, enum test_action action, void *data) +{ + (void)state; + (void)action; + (void)data; + + printf("RUNNING: %s\n", test_action_str(action)); + + return test_STOPPED; +} + +enum test_state test_state_STOPPED(test_state_t *state, enum test_action action, void *data) +{ + (void)state; + (void)action; + (void)data; + + printf("STOPPED: %s\n", test_action_str(action)); + + return 0; +} + +enum test_state test_state_EXCEPTION(test_state_t *state, enum test_action action, void *data) +{ + switch (action) + { + case test_do_STATE_INIT: + FAIL("EXCEPTION state never calls STATE_INIT"); + break; + + case test_exception_TIMEOUT: + return test_STOPPED; + + default: + /* Invalid transition */ + return test_RUNNING; + } + + return 0; +} + +int main(void) +{ + test_state_t test = { 0 }; + + log_open("STAM", LOG_OPEN_STDOUT); + + if (test_state_do(&test, test_do_START, NULL) < 0) + { + LOG(ERR, "State machine error"); + } + + if (test_state_do(&test, test_exception_TIMEOUT, NULL) < 0) + { + LOG(ERR, "Error executing exception"); + } + + printf("CANCELLING...\n"); + if (test_state_do(&test, test_exception_CANCEL, NULL) < 0) + { + LOG(ERR, "Error executing exception"); + } + + return 0; +} diff --git a/src/lib/stam/devtest/test.dot b/src/lib/stam/devtest/test.dot new file mode 100644 index 00000000..d872faf3 --- /dev/null +++ b/src/lib/stam/devtest/test.dot @@ -0,0 +1,11 @@ +digraph { + INIT -> RETRANSITION; + RETRANSITION -> RUNNING[label="STATE_INIT,START"]; + RUNNING -> STOPPED[label="STATE_INIT,STOP"]; + + STOPPED -> RUNNING[label="START"]; + + EXCEPTION -> STOPPED[label="!CANCEL"]; + EXCEPTION -> STOPPED[label="!TIMEOUT"]; + EXCEPTION -> RUNNING; +} diff --git a/src/lib/stam/devtest/unit.mk b/src/lib/stam/devtest/unit.mk new file mode 100644 index 00000000..27dfdf84 --- /dev/null +++ b/src/lib/stam/devtest/unit.mk @@ -0,0 +1,35 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := stamtest +UNIT_TYPE := BIN + +UNIT_DISABLE := y + +UNIT_SRC += stamtest.c + +UNIT_DEPS := src/lib/stam +UNIT_DEPS += src/lib/osa + +$(eval $(call stam_generate,test.dot)) diff --git a/src/lib/stam/inc/stam.h b/src/lib/stam/inc/stam.h new file mode 100644 index 00000000..4055dd0d --- /dev/null +++ b/src/lib/stam/inc/stam.h @@ -0,0 +1,440 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +/* + * Sanity checks + */ +#if !defined(STAM_NAME) +#error STAM_NAME not defined. \ + See src/lib/stam/README.md for usage info. +#endif + +#if !defined(STAM_STATES) +#error STAM_STATES not defined. \ + See src/lib/stam/README.md for usage info. +#endif + +#if !defined(STAM_ACTIONS) +#error STAM_ACTIONS not defined. \ + See src/lib/stam/README.md for usage info. +#endif + +#if !defined(STAM_GENERATE_HEADER) && !defined(STAM_GENERATE_SOURCE) +#error Either STAM_GENERATE_HEADER or STAM_GENERATE_SOURCE must be defined. \ + See src/liub/stam/README.md for usage info. +#endif + +/* + * Appending macros strings + */ +#define _STAM_CAT(x, y) x ## y +#define STAM_CAT(x, y) _STAM_CAT(x, y) +#define _STAM_STR(x) #x +#define STAM_STR(x) _STAM_STR(x) + +/* Append y to STAM_NAME */ +#define STAM_NC(y) STAM_CAT(STAM_NAME, y) + +/* Shortcut macros to make it a bit easier to read the code */ +#define STAM_state_t STAM_NC(_state_t) +#define STAM_state STAM_NC(_state) +#define STAM_state_str STAM_NC(_state_str) +#define STAM_action STAM_NC(_action) +#define STAM_action_str STAM_NC(_action_str) +#define STAM_state_call STAM_NC(_state_call) +#define STAM_state_get STAM_NC(_state_get) +#define STAM_state_prev STAM_NC(_state_prev) +#define STAM_state_do STAM_NC(_state_do) +#define STAM_STATE_EXCEPTION STAM_NC(_EXCEPTION) +#define STAM_ACTION_STATE_INIT STAM_NC(_do_STATE_INIT) +#define STAM_ACTION__END STAM_NC(_do__END) +#define STAM_EXCEPTION__BEGIN STAM_NC(_exception__BEGIN) +#define STAM_STATE__ERROR STAM_NC(__ERROR) +#define STAM_STATE__BUSY STAM_NC(__BUSY) +#define STAM_STATE__END STAM_NC(__END) +#define STAM_name STAM_STR(STAM_NAME) +#define STAM_validate_transition STAM_NC(_validate_transition) +#define STAM_validate_action STAM_NC(_validate_action) + +#if defined(STAM_GENERATE_HEADER) + +/* + * List of states + */ +#define STAM_STATE_ENUM(state) \ + STAM_NC(_ ## state), + +enum STAM_state { + STAM_STATE__ERROR = INT8_MIN, + STAM_STATE__BUSY = 0, + STAM_STATES(STAM_STATE_ENUM) +#if defined(STAM_EXCEPTIONS) + STAM_STATE_EXCEPTION, +#endif + STAM_STATE__END +}; + +/* + * List of actions + */ +#define STAM_ACTION_ENUM(act) \ + STAM_NC(_do_ ## act), + +#define STAM_EXCEPTION_ENUM(exc) \ + STAM_NC(_exception_ ## exc), + +enum STAM_action +{ + STAM_ACTION_STATE_INIT = 0, + STAM_ACTIONS(STAM_ACTION_ENUM) +#if defined(STAM_EXCEPTIONS) + STAM_EXCEPTION__BEGIN, + STAM_EXCEPTIONS(STAM_EXCEPTION_ENUM) +#endif + STAM_ACTION__END +}; + +typedef struct +{ + enum STAM_state state; + enum STAM_state prev; + uint32_t guard; +} +STAM_state_t; + +/* + * Create state handlers + */ + +#define STAM_STATE_HANDLER(state) \ + enum STAM_state STAM_NC(_state_ ## state)(STAM_state_t *stam, enum STAM_action action, void *data); + +STAM_STATES(STAM_STATE_HANDLER) + +#if defined(STAM_EXCEPTIONS) +enum STAM_state STAM_NC(_state_EXCEPTION)(STAM_state_t *stam, enum STAM_action action, void *data); +#endif + +const char *STAM_action_str(enum STAM_action act); +const char *STAM_state_str(enum STAM_state state); + +/* + * Return current state + */ +enum STAM_state STAM_state_get(STAM_state_t *stam); + +/* + * Return previous state + */ +enum STAM_state STAM_state_prev(STAM_state_t *stam); + +/* + * Create the action function definition + */ +enum STAM_state STAM_state_do(STAM_state_t *stam, enum STAM_action action, void *data); + +#if defined(STAM_transitions_checks) +bool STAM_validate_transition(enum STAM_state entry_state, enum STAM_state exit_state, enum STAM_action action); +#endif + +#if defined(STAM_actions_checks) +bool STAM_validate_action(enum STAM_state entry_state, enum STAM_action action); +#endif + +#include "stam_gen.h" + +#endif /* STAM_GENERATE_HEADER */ + +#if defined(STAM_GENERATE_SOURCE) + +/* + * Debugs + */ +#if !defined(STAM_LOG) +#include "log.h" +#define STAM_LOG(...) LOG(TRACE, __VA_ARGS__) +#endif + +#if !defined(STAM_WARN) +#include "log.h" +#define STAM_WARN(...) LOG(WARN, __VA_ARGS__) +#endif + +/* + * Descriptive array of actions + */ +#define STAM_ACTION_SWITCH_STR(action) \ + case STAM_NC(_do_ ## action): return "do_" #action; + +#define STAM_EXCEPTION_SWITCH_STR(action) \ + case STAM_NC(_exception_ ## action): return "exception_" #action; + +const char* STAM_action_str(enum STAM_action act) +{ + switch (act) + { + case STAM_ACTION__END: + return "(end)"; + + STAM_ACTION_SWITCH_STR(STATE_INIT) + STAM_ACTIONS(STAM_ACTION_SWITCH_STR) +#if defined(STAM_EXCEPTIONS) + case STAM_EXCEPTION__BEGIN: + return "(exception begin)"; + + STAM_EXCEPTIONS(STAM_EXCEPTION_SWITCH_STR) +#endif + } + + return "do_?????"; +} + +#define STAM_STATE_SWITCH_STR(state) \ + case STAM_NC(_ ## state): return #state; + +const char* STAM_state_str(enum STAM_state state) +{ + switch (state) + { + case STAM_STATE__BUSY: + return "(init)"; + case STAM_STATE__END: + return "(end)"; + case STAM_STATE__ERROR: + return "(error)"; + + STAM_STATES(STAM_STATE_SWITCH_STR) +#if defined(STAM_EXCEPTIONS) + STAM_STATE_SWITCH_STR(EXCEPTION) +#endif + } + + return "?????"; +} + +/** + * + * @return true on success + */ +#define STAM_STATE_SWITCH(state) \ + case STAM_NC(_ ## state): \ + return STAM_NC(_state_ ## state)(stam, action, data); + +enum STAM_state STAM_state_call(STAM_state_t *stam, enum STAM_state state, enum STAM_action action, void *data) +{ +#if defined(LOG_H_INCLUDED) + STAM_LOG("STAM: %s: [%s].%s", STAM_name, STAM_state_str(state), STAM_action_str(action)); +#endif + + switch (state) + { + STAM_STATES(STAM_STATE_SWITCH) +#if defined(STAM_EXCEPTIONS) + STAM_STATE_SWITCH(EXCEPTION) +#endif + case STAM_STATE__ERROR: + case STAM_STATE__BUSY: + case STAM_STATE__END: + return -1; + } + + return -1; +} + +enum STAM_state STAM_state_get(STAM_state_t *stam) +{ + return stam->state; +} + +enum STAM_state STAM_state_prev(STAM_state_t *stam) +{ + return stam->prev; +} + +enum STAM_state STAM_state_do(STAM_state_t *stam, enum STAM_action action, void *data) +{ + uint32_t cguard; + + enum STAM_state retval = 0; + enum STAM_state next_state = 0; + + /* First call to STAM_state_do(), initialize the default state */ + if (stam->state == 0) + { + /* + * Shift state to the first valid state (always number 1), all states implicitly + * accepts STAM_ACTION_STATE_INIT action + */ + stam->state = 1; + next_state = STAM_state_do(stam, STAM_ACTION_STATE_INIT, NULL); + /* In case an error occurred, stop processing here */ + if (next_state < 0) + { + return next_state; + } + } + + cguard = stam->guard; + + next_state = 0; +#if defined(STAM_EXCEPTIONS) + /* + * Fast transition to exception state + */ + if (action > STAM_EXCEPTION__BEGIN) + { + next_state = STAM_STATE_EXCEPTION; + } +#endif + + /* + * Transition to a new state -- note that a transition to itself may + * trigger a new transition + */ + while (next_state >= 0) + { + if (next_state > 0) + { + STAM_LOG("STAM: %s: [%s -> %s] via %s", + STAM_name, + STAM_state_str(stam->state), + STAM_state_str(next_state), + STAM_action_str(action)); + + stam->prev = stam->state; + stam->state = next_state; + } + +#if defined(STAM_actions_checks) +#if defined(STAM_EXCEPTIONS) + if (action < STAM_EXCEPTION__BEGIN) +#endif + if (!STAM_validate_action(stam->state, action)) + { + STAM_WARN("STAM: %s: Illegal action [%s at %s]", + STAM_name, + STAM_action_str(action), + STAM_state_str(stam->state)); + + return STAM_STATE__ERROR; + } +#endif + /* + * If the return code is 0 or error, do not touch the stam structure in + * any way. It is allowed to free the current structure while returning + * 0 or error. For this reason, remember the current state in case we + * have to return it. + */ + retval = stam->state; + next_state = STAM_state_call(stam, stam->state, action, data); + if (next_state == 0) + { + return retval; + } + else if (next_state < 0) + { + /* + * In case of error just forward the error code returned from the + * state handler + */ + return next_state; + } + + /* + * Check for re-entrancy. It is allowed to call STAM_state_do() + * recursively as long as a maximum of 1 call changes the state. + */ + if (stam->guard != cguard) + { + STAM_WARN("STAM: %s: Re-entrancy detected. [%s(%s)]", + STAM_name, + STAM_state_str(stam->state), + STAM_action_str(action)); + + return STAM_STATE__ERROR; + } + cguard = ++stam->guard; + +#if defined(STAM_transitions_checks) + if (!STAM_validate_transition(stam->state, next_state, action)) + { + STAM_WARN("STAM: %s: Illegal transition [%s(%s) -> %s]", + STAM_name, + STAM_state_str(stam->state), + STAM_action_str(action), + STAM_state_str(next_state)); + + return STAM_STATE__ERROR; + } +#endif + /* Transition successful, the next action is always STATE_INIT */ + action = STAM_ACTION_STATE_INIT; + } + + /* + * The code above should not be able to reach this point. Future proof it + * by showing an error message. + */ + STAM_WARN("STAM: %s: Internal error [%s at %s]", + STAM_name, + STAM_action_str(action), + STAM_state_str(stam->state)); + + return STAM_STATE__ERROR; +} + +#endif + +#undef STAM_state_t +#undef STAM_state +#undef STAM_state_str +#undef STAM_action +#undef STAM_action_str +#undef STAM_state_call +#undef STAM_state_get +#undef STAM_state_prev +#undef STAM_state_do +#undef STAM_STATE_EXCEPTION +#undef STAM_ACTION_STATE_INIT +#undef STAM_ACTION__END +#undef STAM_validate_transition +#undef STAM_validate_action +#undef STAM_STATE__ERROR +#undef STAM_STATE__BUSY +#undef STAM_STATE__END + +#undef STAM_GENERATE_HEADER +#undef STAM_GENERATE_SOURCE + +#undef STAM_NAME +#undef STAM_STATES +#undef STAM_ACTIONS +#undef STAM_EXCEPTIONS + diff --git a/src/lib/stam/inc/stam_gen.h b/src/lib/stam/inc/stam_gen.h new file mode 100644 index 00000000..ce54ca49 --- /dev/null +++ b/src/lib/stam/inc/stam_gen.h @@ -0,0 +1,50 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STAM_GEN_H_INCLUDED +#define STAM_GEN_H_INCLUDED + +#include + +/* + * libstam internal helpers, do not use them directly. + */ +struct stam_trans +{ + int entry_state; + int exit_state; + const int* valid_actions; +}; + +bool stam_validate_relation( + int entry_state, + int exit_state, + int action, + const struct stam_trans* id_transitions, + int state_terminator, + int action_terminator); + +#endif /* STAM_GEN_H_INCLUDED */ diff --git a/src/lib/stam/src/stam.c b/src/lib/stam/src/stam.c new file mode 100644 index 00000000..3ff44bc1 --- /dev/null +++ b/src/lib/stam/src/stam.c @@ -0,0 +1,61 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Define dummy state machine just to get common declarations */ +#include +#include + +#include "stam_gen.h" + +bool stam_validate_relation(int entry_state, int exit_state, int action, const struct stam_trans* valid_transitions, int state_terminator, int action_terminator) +{ + const struct stam_trans *transition; + const int *valid_action; + + for (transition = valid_transitions; transition->entry_state != state_terminator; transition++) { + if (transition->entry_state != entry_state) + continue; + + /* Check exit_state only if it was specified */ + if (exit_state != state_terminator) + { + if (transition->exit_state != exit_state) + continue; + } + + /* No actions were assigned to this transition */ + if (!transition->valid_actions) + return true; + + for (valid_action = transition->valid_actions; *valid_action != action_terminator; valid_action++) + { + if (*valid_action == action) + return true; + } + } + + return false; +} diff --git a/src/lib/stam/tools/libstam_gen.py b/src/lib/stam/tools/libstam_gen.py new file mode 100755 index 00000000..ca6ef442 --- /dev/null +++ b/src/lib/stam/tools/libstam_gen.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +import argparse +import os +import re +from collections import OrderedDict +import pydot +import sys + +class TransitionKey: + def __init__(self, src, dest): + self.src = src + self.dest = dest + + def __hash__(self): + return hash((self.src, self.dest)) + + def __eq__(self, other): + return self.src == other.src and self.dest == other.dest + + +def to_array_name(node, suffix): + return 'valid_{node.lower()}_{suffix}'.format(locals()) + + +# Bunch of string helpers making names more "C-friendly" +# e.g. to_upper("ab C-D") -> "ab_c_d" +def to_upper(text): + return re.sub(r'[ .-]', '_', text).upper() + + +def to_lower(text): + return re.sub(r'[ .-]', '_', text).lower() + + +def parse_file(file_path): + with open(file_path, 'r') as handle: + data = handle.read() + graph = pydot.graph_from_dot_data(data) + + # Compatibility with older versions + if isinstance(graph, list): + graph = graph[0] + + transactions = {} + states = OrderedDict() # I want to keep the order in which 'entry' states appear in DOT file + all_actions = set() + + for state in graph.get_node_list(): + if state.obj_dict['attributes'].get('init'): + states[state.get_name()] = None + + # Edge is a state machine transition + for edge in graph.get_edges(): + # Extract action names from "label" property + actions = edge.obj_dict['attributes'].get('label', str()).strip('"').split(',') + actions = set([action for action in actions if action != '']) + all_actions |= actions + + # We need to know all actions to generate enum + if edge.get_destination() == "EXCEPTION": + # The exception state is a special case -- it's implicit when + # an "exception" list is defined. + # Ignore any state transitions to the EXCEPTION state as those + # are probably just placeholders for generating the EXCEPTION + # list + + # Verify that all actions leading to the EXCEPTION state are + # exceptions (the ! syntax) + for a in actions: + if not a.startswith('!'): + raise Exception("Action {} leading to EXCEPTION must be defined as an exception (prefix it with !)".format(a)) + else: + # We need to know all states to generate enum, but ignore the "EXCEPTION" state -- it is autogenerated + # if needed + if edge.get_source() != 'EXCEPTION': + states[edge.get_source()] = None + + # Verify that actions are not exceptions (the ! syntax) + for a in actions: + if a.startswith('!'): + raise Exception("Exception {} does not reference the EXCEPTION state.".format(a)) + + states[edge.get_destination()] = None + + # DOT allows to define the same transition (e.g. "a -> b") multiple times. libstam doesn't allow that, + # so we're combining the same transitions. + key = TransitionKey(edge.get_source(), edge.get_destination()) + if key in transactions: + transactions[key] |= actions + else: + transactions[key] = actions + + return states.keys(), transactions, all_actions + + +def gen_define_states(states): + buf = '#define STAM_STATES(state) \\\n' + buf += ' \\\n'.join([' state({})'.format(to_upper(key)) for key in states]) + return buf + + +def gen_define_actions(actions): + buf = '#define STAM_ACTIONS(action) \\\n' + belem = [] + for key in actions: + if key == 'STATE_INIT': + continue + + if key.startswith('!'): + continue + + belem.append(' action({})'.format(to_upper(key))) + + buf += ' \\\n'.join(belem) + buf += '\n\n' + + belem = [] + for key in actions: + if not key.startswith('!'): + continue + + belem.append(' except({})'.format(to_upper(key[1:]))) + + if len(belem) > 0: + buf += '#define STAM_EXCEPTIONS(except) \\\n' + buf += ' \\\n'.join(belem) + buf += '\n\n' + + return buf + +def gen_transition_arrays(base_name, transitions): + actions_buf = '' + transitions_buf = '' + for i, key in enumerate(transitions.keys()): + actions = transitions[key] + lo_base_name = to_lower(base_name) + if actions: + array_name = 'transition_{}_actions'.format(i) + + actions_buf += '/* Actions for {}_{} -> {}_{} */\n'.format( + lo_base_name, key.src, lo_base_name, key.dest) + actions_buf += 'static const int {}[] =\n{{\n'.format(array_name) + action_list = [] + for action in actions: + if action.startswith('!'): + action_list.append(' {}_exception_{}'.format(lo_base_name, to_upper(action[1:]))) + else: + action_list.append(' {}_do_{}'.format(lo_base_name, to_upper(action))) + + actions_buf += ',\n'.join(action_list) + actions_buf += ',\n {}_do__END\n'.format(lo_base_name) + actions_buf += '};\n\n' + + transitions_buf += ' {{ {}_{}, {}_{}, {} }},\n'.format( + lo_base_name, to_upper(key.src), lo_base_name, to_upper(key.dest), array_name) + else: + transitions_buf += ' {{ {}_{}, {}_{}, NULL }},\n'.format( + lo_base_name, to_upper(key.src), lo_base_name, to_upper(key.dest)) + + return actions_buf, transitions_buf + + +def gen_header( + base_name, + states, + actions, + disable_actions_checks, + disable_transitions_checks): + + lo_base_name = to_lower(base_name) + buf = \ + '/* DO NOT EDIT FILE (it was autogenerated)! */\n' \ + '#ifndef {lo_base_name}_GEN_H\n' \ + '#define {lo_base_name}_GEN_H\n' \ + '\n' \ + '#define STAM_NAME {lo_base_name}\n' \ + '\n' \ + '{states}\n' \ + '\n' \ + '{actions}\n' \ + '\n'.format( + lo_base_name = lo_base_name, + states = gen_define_states(states), + actions = gen_define_actions(actions)) + + if not disable_actions_checks: + buf += \ + '#define STAM_actions_checks\n' + + if not disable_transitions_checks: + buf += \ + '#define STAM_transitions_checks\n' + + buf += '#if !defined(STAM_GENERATE_SOURCE) && !defined(STAM_GENERATE_HEADER)\n' + buf += '/* By default, generate the header */\n' + buf += '#define STAM_GENERATE_HEADER\n' + buf += '#endif\n\n' + buf += '#include "stam.h"\n\n' + + buf += '#endif /* {}_GEN_H */\n'.format(lo_base_name) + return buf + + +def gen_source(base_name, transactions, disable_actions_checks, disable_transitions_checks): + actions_buf, transactions_buf = gen_transition_arrays(base_name, transactions) + + lo_base_name = to_lower(base_name) + + buf = \ + '/* DO NOT EDIT FILE (it was autogenerated)! */\n' \ + '\n' \ + '#define STAM_GENERATE_HEADER\n' \ + '#define STAM_GENERATE_SOURCE\n' \ + '#include "{}_stam.h"\n' \ + '\n'.format(lo_base_name, lo_base_name) + + if not (disable_actions_checks and disable_transitions_checks): + # Don't emit any arrays when both actions & transitions verification is disabled. Otherwise + # compiler will complain about unused variables. + buf += \ + '{actions_buf}' \ + 'static const struct stam_trans valid_transitions[] =\n{{\n' \ + '{transactions_buf}' \ + ' {{ {lo_base_name}__END, {lo_base_name}__END, NULL }}\n' \ + '}};\n' \ + '\n'.format(**locals()) + + if not disable_actions_checks: + buf += 'bool {lo_base_name}_validate_transition(enum {lo_base_name}_state entry_state, enum {lo_base_name}_state exit_state, enum {lo_base_name}_action action)\n' \ + '{{\n' \ + ' /* {lo_base_name}_do_STATE_INIT action is implicitly allowed for all states */\n' \ + ' if (entry_state == exit_state && action == {lo_base_name}_do_STATE_INIT)\n' \ + ' return true;\n\n' \ + ' return stam_validate_relation((int) entry_state, (int) exit_state, (int) action, valid_transitions, (int) {lo_base_name}__END, (int) {lo_base_name}_do__END);\n' \ + '}}\n' \ + '\n'.format(**locals()) + + if not disable_transitions_checks: + buf += \ + 'bool {lo_base_name}_validate_action(enum {lo_base_name}_state entry_state, enum {lo_base_name}_action action) \n' \ + '{{\n' \ + ' /* {lo_base_name}_do_STATE_INIT action is implicitly allowed for all states */\n' \ + ' if (action == {lo_base_name}_do_STATE_INIT)\n' \ + ' return true;\n\n' \ + ' return stam_validate_relation((int) entry_state, (int) {lo_base_name}__END, (int) action, valid_transitions, (int) {lo_base_name}__END, (int) {lo_base_name}_do__END);\n' \ + '}}\n'.format(**locals()) + + return buf + + +def get_base_name(dot_file): + file_name = os.path.basename(dot_file) + file_name = os.path.splitext(file_name) + return file_name[0] + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('input_dot', help='DOT file defining FSM') + parser.add_argument('--header', help='Generate header file', action="store_true") + parser.add_argument('--source', help='Generate source file', action="store_true") + parser.add_argument('--stdout', help='Print result on stdout', action="store_true") + parser.add_argument('--file', help='Write result to file', action="store_true") + parser.add_argument('--dest', help='Destination directory', type=str, default='.') + parser.add_argument('--disable-actions-checks', help='Do not verify actions at runtime', action="store_true") + parser.add_argument('--disable-transitions-checks', help='Do not verify transitions at runtime', + action="store_true") + + args = parser.parse_args() + base_name = get_base_name(args.input_dot) + states, transactions, actions = parse_file(args.input_dot) + + header = None + source = None + + if args.header: + header = gen_header(base_name, states, actions, args.disable_actions_checks, args.disable_transitions_checks) + + if args.source: + source = gen_source(base_name, transactions, args.disable_actions_checks, args.disable_transitions_checks) + + if args.stdout: + if header: + print(header) + if source: + print(source) + + if args.file: + if header: + file_path = os.path.join(args.dest, '{}_stam.h'.format(base_name)) + with open(file_path, 'w') as handle: + handle.write(header) + if source: + file_path = os.path.join(args.dest, '{}_stam.c'.format(base_name)) + with open(file_path, 'w') as handle: + handle.write(source) + + +if __name__ == '__main__': + main() diff --git a/src/lib/stam/unit.mk b/src/lib/stam/unit.mk new file mode 100644 index 00000000..185e99d2 --- /dev/null +++ b/src/lib/stam/unit.mk @@ -0,0 +1,33 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := stam +UNIT_TYPE := LIB + +UNIT_CFLAGS := -I$(UNIT_PATH)/inc/ +UNIT_SRC := src/stam.c + +UNIT_EXPORT_CFLAGS := -I$(UNIT_PATH)/inc + +UNIT_DEPS += src/lib/log diff --git a/src/lib/target/inc/target.h b/src/lib/target/inc/target.h index ba4b9503..a63dfabc 100644 --- a/src/lib/target/inc/target.h +++ b/src/lib/target/inc/target.h @@ -37,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "os_types.h" #include "schema.h" #include "os_backtrace.h" -#include "osp.h" #include "target_bsal.h" @@ -224,115 +223,6 @@ const char **target_ethclient_brlist_get(); /// @} LIB_TARGET_ETHCLIENT -/// @defgroup LIB_TARGET_ENTITY Entity API -/// API for retrieval of basic information about the device. -/// @{ - -/****************************************************************************** - * ENTITY definitions - *****************************************************************************/ -/** - * @brief Return device identification - * - * This function provides a null terminated byte string containing the device - * identification. The device identification is a part of AWLAN_Node table. - * In the simplest implementation, this function may be the same as - * target_serial_get(). - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_id_get(void *buff, size_t buffsz); - -/** - * @brief Return device serial number - * - * This function provides a null terminated byte string containing the serial number. - * The serial number is a part of AWLAN_Node table. - * For example, the serial number may be derived from the MAC address. - * Please see implementation inside target_native.c file for the reference. - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_serial_get(void *buff, size_t buffsz); - -/** - * @brief Return device stock keeping unit number - * - * This function provides a null terminated byte string containing the stock keeping - * unit number. It is usually used by stores to track inventory. - * The SKU is a part of AWLAN_Node table. - * If cloud doesn't support SKU for this target, this function should - * return false. The fixed SKU can be provided by setting CONFIG_TARGET_FIXED_SKU - * and CONFIG_TARGET_SKU_STRING. - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_sku_get(void *buff, size_t buffsz); - -/** - * @brief Return device model - * - * This function provides a null terminated byte string containing the device model. - * The device model is a part of AWLAN_Node table. - * For example, this function may return just the serial number (see target_serial_get()). - * The fixed model name can be provided by setting CONFIG_TARGET_MODEL_GET and - * CONFIG_TARGET_MODEL. It is safe to return false here. The TARGET_NAME will be used - * as a model name in that case. - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_model_get(void *buff, size_t buffsz); - -/** - * @brief Return software version number - * - * This function provides a null terminated byte string containing the software version number. - * Expected format: VERSION-BUILD_NUMBER-gGITSHA-PROFILE - * Sample: 1.0.0.0-200-g1a2b3c-devel - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_sw_version_get(void *buff, size_t buffsz); - -/** - * @brief Return hardware version number - * - * This function provides a null terminated byte string containing the hardware - * version number. The hardware version is a part of AWLAN_Node table. - * If not needed this function should return false. - * Fixed HWREV can be provided by setting CONFIG_TARGET_FIXED_HWREV and - * CONFIG_TARGET_FIXED_HWREV_STRING. - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_hw_revision_get(void *buff, size_t buffsz); - -/** - * @brief Return platform version number - * - * This function provides a null terminated byte string containing the platform - * version number. The platform version number is a part of AWLAN_Node table. - * If not needed this function should return false. - * - * @param buff pointer to a string buffer - * @param buffsz size of string buffer - * @return true on success - */ -bool target_platform_version_get(void *buff, size_t buffsz); - -/// @} LIB_TARGET_ENTITY /// @defgroup LIB_TARGET_MAP Interface Mapping API /// API for mapping of interface names that the cloud uses to actual interface @@ -448,6 +338,19 @@ bool target_log_open(char *name, int flags); */ bool target_log_pull(const char *upload_location, const char *upload_token); +/** + * @brief Collect logs (using specified method). + * + * An extended variant of the basic target_log_pull() function. + * + * @param upload_location URL + * @param upload_token filename to upload + * @param upload_method method/procedure required to upload a logpull + * with the specified type of URL. + * @return true on success + */ +bool target_log_pull_ext(const char *upload_location, const char *upload_token, const char *upload_method); + /// @cond INTERNAL /** * @brief return the printf-style path to the LED sysfs diff --git a/src/lib/target/inc/target_common.h b/src/lib/target/inc/target_common.h index a0a722f6..cfb512a2 100644 --- a/src/lib/target/inc/target_common.h +++ b/src/lib/target/inc/target_common.h @@ -43,22 +43,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// @addtogroup LIB_TARGET /// @{ -typedef struct { - struct schema_Wifi_Radio_Config rconf; - ds_dlist_t vifs_cfg; - ds_dlist_node_t dsl_node; -} target_radio_cfg_t; - -typedef struct { - struct schema_Wifi_VIF_Config vconf; - ds_dlist_node_t dsl_node; -} target_vif_cfg_t; - -typedef struct { - struct schema_Wifi_Route_State rstate; - ds_dlist_node_t dsl_node; -} target_route_state_init_t; - /// @defgroup LIB_TARGET_RADIO Radio API /// Definitions and API related to control of radios. /// @{ @@ -123,22 +107,6 @@ struct target_radio_ops { */ bool target_radio_init(const struct target_radio_ops *ops); -/** - * @brief Initialize radio interfaces config - * - * Initialize the target library radio configuration layer and return a list - * of currently configured radio interfaces. init_cfg is a double linked list - * of target_radio_cfg_t structures. This list is used to pre-populate - * the Wifi_Radio_Config table. - * - * @note - * The init_cfg linked list is dynamically allocated, it must be freed by the caller. - * - * @param init_cfg linked list of radio interfaces config (target_radio_cfg_t) - * @return true on success - */ -bool target_radio_config_init(ds_dlist_t *init_cfg); - /** * @brief Initialize radio interface configuration * @@ -170,17 +138,6 @@ bool target_radio_config_init2(void); */ bool target_radio_config_need_reset(void); -/** - * @brief Apply the configuration for the radio interface - * - * The interface ifname must already exist on the system. - * - * @param ifname interface name - * @param rconf radio interface config - * @return true on success - */ -bool target_radio_config_set (char *ifname, struct schema_Wifi_Radio_Config *rconf); - /** * @brief Apply the configuration for the radio interface * @@ -211,36 +168,6 @@ bool target_radio_config_set2(const struct schema_Wifi_Radio_Config *rconf, */ bool target_radio_state_get(char *ifname, struct schema_Wifi_Radio_State *rstate); -/** @brief Radio state change callback type */ -typedef void target_radio_state_cb_t(struct schema_Wifi_Radio_State *rstate, schema_filter_t *filter); - -/** - * @brief Subscribe to radio interface state change events. - * - * @note - * The interface state is typically polled - * - * @param ifname interface name - * @param radio_state_cb a callback function - * @return true on success - */ -bool target_radio_state_register(char *ifname, target_radio_state_cb_t *radio_state_cb); - -/** @brief Radio config change callback type */ -typedef void target_radio_config_cb_t(struct schema_Wifi_Radio_Config *rconf, schema_filter_t *filter); - -/** - * @brief Subscribe to radio interface config change events. - * - * @note - * The interface state is typically polled - * - * @param ifname interface name - * @param radio_config_cb a callback function - * @return true on success - */ -bool target_radio_config_register(char *ifname, target_radio_config_cb_t *radio_config_cb); - /// @} LIB_TARGET_RADIO /// @defgroup LIB_TARGET_VIF VIF API @@ -251,15 +178,6 @@ bool target_radio_config_register(char *ifname, target_radio_config_cb_t *radio_ * VIF definitions *****************************************************************************/ -/** - * @brief Apply the configuration for the vif interface - * - * @param ifname interface name - * @param vconf vif interface config - * @return true on success - */ -bool target_vif_config_set (char *ifname, struct schema_Wifi_VIF_Config *vconf); - /** * @brief Apply the configuration for the vif interface * @@ -294,60 +212,8 @@ bool target_vif_config_set2(const struct schema_Wifi_VIF_Config *vconf, */ bool target_vif_state_get(char *ifname, struct schema_Wifi_VIF_State *vstate); -/** @brief VIF state change callback type */ -typedef void target_vif_state_cb_t(struct schema_Wifi_VIF_State *rstate, schema_filter_t *filter); - -/** - * @brief Subscribe to vif interface state change events. - * - * @note - * The interface state is typically polled - * - * @param ifname interface name - * @param vstate_cb a callback function - * @return true on success - */ -bool target_vif_state_register(char *ifname, target_vif_state_cb_t *vstate_cb); - -/** @brief VIF config change callback type */ -typedef void target_vif_config_cb_t(struct schema_Wifi_VIF_Config *vconf, schema_filter_t *filter); - -/** - * @brief Subscribe to vif interface config change events. - * - * @note - * The interface state is typically polled - * - * @param ifname interface name - * @param vconfig_cb a callback function - * @return true on success - */ -bool target_vif_config_register(char *ifname, target_vif_config_cb_t *vconfig_cb); - /// @} LIB_TARGET_VIF -/// @defgroup LIB_TARGET_CLIENTS Clients API -/// Definitions and API related to control of clients. -/// @{ - -/****************************************************************************** - * CLIENTS definitions - *****************************************************************************/ - -/** @brief Client change callback type */ -typedef bool target_clients_cb_t(struct schema_Wifi_Associated_Clients *schema, char *ifname, bool status); - -/** - * @brief Subscribe to client change events. - * - * @param ifname interface name - * @param clients_cb a callback function - * @return true on success - */ -bool target_clients_register(char *ifname, target_clients_cb_t *clients_cb); - -/// @} LIB_TARGET_CLIENTS - /// @defgroup LIB_TARGET_STATS Statistics Related APIs /// Definitions and API related to statistics. /// @{ @@ -813,30 +679,28 @@ typedef struct mcproxyd_params { } target_mcproxy_params_t; /** - * @brief Applies config to mcproxy - * and reloads the corresponding daemon. - * @param target_mcproxyd_params_t contains protocol,upstream and downstream ifs info. + * @brief Applies config to mcproxy and reloads the corresponding daemon. + * @param mcparams contains protocol, upstream, and downstream ifs info. * @return true on success */ bool target_set_igmp_mcproxy_params(target_mcproxy_params_t *mcparams); /** * @brief Get config from the mcproxy. - * @param target_mcproxyd_params_t contains protocol,upstream and downstream ifs info. + * @param mcparams contains protocol, upstream, and downstream ifs info. * @return true on success */ bool target_get_igmp_mcproxy_params(target_mcproxy_params_t *mcparams); /** - * @brief Applies config to mcproxy - * and reloads the corresponding daemon. - * @param target_mcproxyd_params_t contains protocol,upstream and downstream ifs info. + * @brief Applies config to mcproxy and reloads the corresponding daemon. + * @param mcparams contains protocol, upstream, and downstream ifs info. * @return true on success */ bool target_set_mld_mcproxy_params(target_mcproxy_params_t *mcparams); /** * @brief Get config from the mcproxy. - * @param target_mcproxyd_params_t contains protocol,upstream and downstream ifs info. + * @param mcparams contains protocol, upstream, and downstream ifs info. * @return true on success */ bool target_get_mld_mcproxy_params(target_mcproxy_params_t *mcparams); @@ -844,30 +708,29 @@ bool target_get_mld_mcproxy_params(target_mcproxy_params_t *mcparams); /** * @brief Applies mcproxy system parameters and reloads the corresponding * proxy daemon. - * @param schema_IGMP_Config contains all the IGMP params required. - * @return true on sucess. + * @param iccfg contains all required IGMP params. + * @return true on success */ bool target_set_igmp_mcproxy_sys_params(struct schema_IGMP_Config *iccfg); /** * @brief Get mcproxy system parameters. - * @param schema_IGMP_Config contains all the IGMP params required. - * @return true on sucess. + * @param iccfg contains all required IGMP params. + * @return true on success */ bool target_get_igmp_mcproxy_sys_params(struct schema_IGMP_Config *iccfg); /** * @brief Applies mcproxy system parameters and reloads the corresponding * proxy daemon. - * @param schema_MLD_Config contains all the IGMP params required. - * @return true on sucess. + * @param mlcfg contains all required IGMP params. + * @return true on success */ bool target_set_mld_mcproxy_sys_params(struct schema_MLD_Config *mlcfg); /** * @brief Get mcproxy system parameters. - * @param schema_IGMP_Config contains all the IGMP params required. - * @param schema_MLD_Config contains all the IGMP params required. - * @return true on sucess. + * @param iccfg contains all required IGMP params. + * @return true on success */ bool target_get_mld_mcproxy_sys_params(struct schema_MLD_Config *iccfg); diff --git a/src/lib/target/kconfig/Kconfig b/src/lib/target/kconfig/Kconfig index 02a96182..29dda455 100644 --- a/src/lib/target/kconfig/Kconfig +++ b/src/lib/target/kconfig/Kconfig @@ -8,7 +8,7 @@ menu "Capabilities" bool "Gateway" default y help - This device can act as a gateway (residential or otherwisE). + This device can act as a gateway (residential or otherwise). config TARGET_CAP_EXTENDER bool "Extender" @@ -122,11 +122,19 @@ config TARGET_LAN_BRIDGE_NAME help LAN bridge name that will be used -config TARGET_WAN_BRIDGE_NAME - string "WAN bridge name" - default "br-wan" +config TARGET_USE_WAN_BRIDGE + bool "Use WAN bridge" + default y help - WAN bridge name that will be used + Use additional bridge for WAN link + +if TARGET_USE_WAN_BRIDGE + config TARGET_WAN_BRIDGE_NAME + string "WAN bridge name" + default "br-wan" + help + WAN bridge name that will be used +endif menuconfig TARGET_LED_SUPPORT bool "Enable LED support" @@ -172,60 +180,6 @@ menuconfig TARGET_LED_SUPPORT depends on TARGET_LED3 endif -menu "Model/Serial Number/SKU ..." - -config TARGET_MODEL_GET - bool "Use TARGET_MODEL as the model name" - default y - - help - Implement the target_model_get() function. - - This returns the TARGET_MODEL as the model. TARGET_MODEL - is a top-level configuration option. - -config TARGET_SERIAL_FROM_MAC - bool "Use network interface MAC for serial number" - default y - help - This is a rather common case for devices that have no easy access - to their serial number or for early development stages. - - This option implements the target_serial_get() function. - -config TARGET_SERIAL_FROM_MAC_IFNAME - string "Interface name" - default "eth0" - depends on TARGET_SERIAL_FROM_MAC - help - Interface name that will be used for calculating the serial - number from the MAC address - -config TARGET_FIXED_HWREV - bool "Use a fixed HW revision number" - default y - help - This implements the target_hw_revision_get() function and returns the - string as defined by TARGET_FIXED_HWREV_STRING - -config TARGET_FIXED_HWREV_STRING - string "HW revision number" - default "1" - depends on TARGET_FIXED_HWREV - -config TARGET_FIXED_SKU - bool "Use a fixed SKU number" - default y - help - This option implements the target_sku_get() function and returns the - string as defined by TARGET_SKU_STRING. - -config TARGET_SKU_STRING - string "SKU number" - default "SKU123456" - depends on TARGET_FIXED_SKU -endmenu - menu "Misc..." config TARGET_RESTART_SCRIPT bool "Use a script to restart managers" @@ -263,7 +217,7 @@ config TARGET_LINUX_EXECUTE This implements the target_device_execute() function using the standard Linux system() call. - You may want to select Y here for most linux-based SDKs. + You may want to select 'Y' here for most Linux-based SDKs. config TARGET_CM_LINUX_SUPPORT_PACKAGE bool "CM Linux support package" @@ -281,5 +235,4 @@ config TARGET_IMC help Select this option if the platform enables zeromq - endmenu diff --git a/src/lib/target/src/target_kconfig.c b/src/lib/target/src/target_kconfig.c index 1cb19183..5ff51b61 100644 --- a/src/lib/target/src/target_kconfig.c +++ b/src/lib/target/src/target_kconfig.c @@ -91,49 +91,6 @@ const char **target_ethclient_iflist_get() } #endif -#if defined(CONFIG_TARGET_SERIAL_FROM_MAC) -/* - * Returns true if device serial name is correctly read - */ -bool target_serial_get(void *buff, size_t buffsz) -{ - size_t n; - memset(buff, 0, buffsz); - - os_macaddr_t mac; - - /* get eth0 MAC address */ - if (!os_nif_macaddr(CONFIG_TARGET_SERIAL_FROM_MAC_IFNAME, &mac)) - { - LOG(ERR, "Unable to retrieve MAC address for %s.", CONFIG_TARGET_SERIAL_FROM_MAC_IFNAME); - return false; - } - - /* convert this to string and set id & serial_number */ - n = snprintf(buff, buffsz, PRI(os_macaddr_plain_t), FMT(os_macaddr_t, mac)); - if (n >= buffsz) - { - LOG(ERR, "buffer not large enough"); - return false; - } - - return true; -} -#endif /* CONFIG_TARGET_SERIAL_FROM_MAC */ - -#if defined(CONFIG_TARGET_MODEL_GET) -bool target_model_get(void *buff, size_t buffsz) -{ - snprintf( - buff, - buffsz, - "%s", - CONFIG_TARGET_MODEL); - - return true; -} -#endif /* CONFIG_TARGET_MODEL_GET */ - #if defined(CONFIG_TARGET_PATH_BIN) const char *target_bin_dir(void) { @@ -187,13 +144,16 @@ bool target_device_restart_managers() #endif #if defined(CONFIG_TARGET_LINUX_LOGPULL) -bool target_log_pull(const char *upload_location, const char *upload_token) +bool target_log_pull_ext( + const char *upload_location, + const char *upload_token, + const char *upload_method) { // TODO: command cleanup (remove hc params, etc...) char shell_cmd[1024]; snprintf(shell_cmd, sizeof(shell_cmd), "sh "CONFIG_TARGET_PATH_SCRIPTS"/lm_logs_collector.sh" - " %s" + " \"%s\"" " %s" " "CONFIG_TARGET_PATH_LOG_LM " syslog" @@ -201,13 +161,20 @@ bool target_log_pull(const char *upload_location, const char *upload_token) " tmp" " crash" " /tmp/etc/openvswitch/conf.db" - " /tmp/ovsdb.log", + " /tmp/ovsdb.log" + " %s", upload_location, - upload_token); + upload_token, + upload_method); // On success we return true return !cmd_log(shell_cmd); } + +bool target_log_pull(const char *upload_location, const char *upload_token) +{ + return target_log_pull_ext(upload_location, upload_token, "lm-awlan"); +} #endif #if !defined(CONFIG_TARGET_WATCHDOG) @@ -229,35 +196,6 @@ bool target_device_execute(const char *cmd) } #endif -#if defined(CONFIG_TARGET_FIXED_HWREV) -bool target_hw_revision_get(void *buff, size_t buffsz) -{ - snprintf( - buff, - buffsz, - "%s", - CONFIG_TARGET_FIXED_HWREV_STRING); - - return true; -} -#endif - -#if defined(CONFIG_TARGET_FIXED_SKU) -/* - * Dummy function - */ -bool target_sku_get(void *buff, size_t buffsz) -{ - snprintf( - buff, - buffsz, - "%s", - CONFIG_TARGET_SKU_STRING); - - return true; -} -#endif - #if defined(CONFIG_TARGET_LED_SUPPORT) const char *target_led_device_dir(void) { @@ -312,8 +250,23 @@ int target_led_names(const char **leds[]) #define DEFAULT_BACKHAUL_PREFIX "169.254." -// Internet IP Addresses +/* Root Servers based on https://www.iana.org/domains/root/servers */ static char *util_connectivity_check_inet_addrs[] = { + "a.root-servers.net", + "b.root-servers.net", + "c.root-servers.net", + "d.root-servers.net", + "f.root-servers.net", + "h.root-servers.net", + "i.root-servers.net", + "j.root-servers.net", + "k.root-servers.net", + "m.root-servers.net", + NULL +}; + +/* IPv4 Root Servers */ +static char *util_connectivity_check_inet_ipv4_addrs[] = { "198.41.0.4", "192.228.79.201", "192.33.4.12", @@ -328,9 +281,25 @@ static char *util_connectivity_check_inet_addrs[] = { NULL }; -static int util_connectivity_get_inet_addr_cnt(void) +/* IPv6 Root Servers */ +static char *util_connectivity_check_inet_ipv6_addrs[] = { + "2001:503:ba3e::2:30", + "2001:500:200::b", + "2001:500:2::c", + "2001:500:2d::d", + "2001:500:2f::f", + "2001:500:1::53", + "2001:7fe::53", + "2001:503:c27::2:30", + "2001:7fd::1", + "2001:500:9f::42", + "2001:dc3::35", + NULL +}; + +static int util_connectivity_get_inet_addr_cnt(char **addr) { - char **p = util_connectivity_check_inet_addrs; + char **p = addr; int n = 0; while (*p) { @@ -398,13 +367,16 @@ util_ntp_check(void) } static bool -util_ping_cmd(const char *ipstr) +util_ping_cmd(const char *ipstr, bool ipv6) { char cmd[256]; + char *ipv6_s; bool rc; - snprintf(cmd, sizeof(cmd), "ping %s -s %d -c %d -w %d >/dev/null 2>&1", - ipstr, DEFAULT_PING_PACKET_SIZE, DEFAULT_PING_PACKET_CNT, + ipv6_s = ipv6 ? "-6" : ""; + + snprintf(cmd, sizeof(cmd), "ping %s %s -s %d -c %d -w %d >/dev/null 2>&1", + ipv6_s, ipstr, DEFAULT_PING_PACKET_SIZE, DEFAULT_PING_PACKET_CNT, DEFAULT_PING_TIMEOUT); rc = target_device_execute(cmd); @@ -437,7 +409,7 @@ util_arping_cmd(const char *ipstr) } static bool -util_get_router_ip(struct in_addr *dest) +util_get_router_ipv4(struct in_addr *dest) { FILE *f1; char line[128]; @@ -472,19 +444,56 @@ util_get_router_ip(struct in_addr *dest) fclose(f1); if (rc) { - LOGD("%s: Found router IP %s", PROC_NET_ROUTE, inet_ntoa(*dest)); + LOGD("%s: Found router IPv4 %s", PROC_NET_ROUTE, inet_ntoa(*dest)); } else { - LOGW("%s: No router IP found", PROC_NET_ROUTE); + LOGD("%s: No router IPv4 found", PROC_NET_ROUTE); } } else { - LOGE("Failed to get router IP, unable to open %s", PROC_NET_ROUTE); + LOGE("Failed to get router IPv4, unable to open %s", PROC_NET_ROUTE); } return rc; } +static bool +util_get_router_ipv6(char *dest, int size) +{ + FILE *f1; + char line[128]; + bool retval; + char cmd[128]; + + f1 = NULL; + retval = false; + + snprintf(cmd, sizeof(cmd), "ip -6 r | awk '$1 == \"default\" && $3 != \"::\" {print $5 \"%%\" $7}'"); + f1 = popen(cmd, "r"); + if (!f1) { + LOGE("Failed to get ipv6 route info"); + goto done; + } + + if (fgets(line, sizeof(line), f1) == NULL) { + LOGD("IPv6 default route not available"); + goto done; + } + + while(line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n') { + line[strlen(line)-1] = '\0'; + } + + retval = true; + strscpy(dest, line, size); + +done: + if (f1 != NULL) + pclose(f1); + + return retval; +} + static bool util_is_gretap_softwds_link(const char *ifname) { @@ -561,7 +570,7 @@ util_connectivity_link_check(const char *ifname) if (util_get_link_ip(ifname + 2, &link_ip)) { - if (util_ping_cmd(inet_ntoa(link_ip)) == false) + if (util_ping_cmd(inet_ntoa(link_ip), false) == false) { /* ARP traffic tends to be treated differently, i.e. * it lands on different TID in Wi-Fi driver. @@ -579,38 +588,107 @@ util_connectivity_link_check(const char *ifname) } static bool -util_connectivity_router_check() +util_get_ipv6_global_interface(char *ifn, int ifn_size) { - struct in_addr r_addr; - bool ret; + FILE *f1; + char line[128]; + bool retval; + char cmd[128]; - if (util_get_router_ip(&r_addr) == false) { - // If we don't have a router, that's considered a failure - return false; + f1 = NULL; + retval = false; + + snprintf(cmd, sizeof(cmd), "ip -6 r | awk '$1 == \"default\" && $3 != \"::\" {print $7}'"); + f1 = popen(cmd, "r"); + if (!f1) { + LOGE("Failed to get ipv6 route info"); + goto done; } - ret = util_ping_cmd(inet_ntoa(r_addr)); - if (!ret) { - LOGI("Router check: ping failed, arping checking"); - ret = util_arping_cmd(inet_ntoa(r_addr)); + if (fgets(line, sizeof(line), f1) == NULL) { + LOGD("IPv6 default route not available"); + goto done; } - return ret; + + while(line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n') { + line[strlen(line)-1] = '\0'; + } + + retval = true; + strscpy(ifn, line, ifn_size); + + LOGI("Global IPv6 interface: %s", ifn); +done: + if (f1 != NULL) + pclose(f1); + + return retval; +} + +static bool +util_connectivity_router_check(void) +{ + struct in_addr r_addr; + char r_6addr[128]; + bool cipv4; + bool cipv6; + + cipv6 = util_get_router_ipv6(r_6addr, sizeof(r_6addr)); + if (cipv6) + cipv6 = util_ping_cmd(r_6addr, true); + + if (util_get_router_ipv4(&r_addr) == false) { + /* If we don't have a router, that's considered a failure for IPv4 */ + return cipv6; + } + cipv4 = util_ping_cmd(inet_ntoa(r_addr), false); + if (!cipv4) { + cipv4 = util_arping_cmd(inet_ntoa(r_addr)); + LOGI("Router check: ping ipv4 failed, arping ret = %d", cipv4); + } + + return cipv4 || cipv6; } static bool -util_connectivity_internet_check() { - int r; - int cnt_addr = util_connectivity_get_inet_addr_cnt(); - - r = os_rand() % cnt_addr; - if (util_ping_cmd(util_connectivity_check_inet_addrs[r]) == false) { - // Try again.. Some of these DNS root servers are a little flakey - r = os_rand() % cnt_addr; - if (util_ping_cmd(util_connectivity_check_inet_addrs[r]) == false) { - return false; +util_connectivity_internet_check(void) { + char ipv6_addr[256]; + char ipv6_if[126]; + bool ipv6; + bool ret; + int cnt_addr1; + int cnt_addr2; + int tries; + int r1, r2; + + cnt_addr1 = util_connectivity_get_inet_addr_cnt(util_connectivity_check_inet_addrs); + ipv6 = util_get_ipv6_global_interface(ipv6_if, sizeof(ipv6_if)); + ret = false; + tries = 2; + + while (tries--) { + r1 = os_rand() % cnt_addr1; + if (ipv6) { + ret = util_ping_cmd(util_connectivity_check_inet_addrs[r1], true); + if (ret) + break; + LOGW("DNS [%s] Internet checking failed", util_connectivity_check_inet_addrs[r1]); + cnt_addr2 = util_connectivity_get_inet_addr_cnt(util_connectivity_check_inet_ipv6_addrs); + r2 = os_rand() % cnt_addr2; + snprintf(ipv6_addr, sizeof(ipv6_addr), "%s%%%s", util_connectivity_check_inet_ipv6_addrs[r2], ipv6_if); + ret = util_ping_cmd(ipv6_addr, true); + if (ret) + break; + } + + ret = util_ping_cmd(util_connectivity_check_inet_addrs[r1], false); + if (!ret) { + cnt_addr2 = util_connectivity_get_inet_addr_cnt(util_connectivity_check_inet_ipv4_addrs); + r2 = os_rand() % cnt_addr2; + ret = util_ping_cmd(util_connectivity_check_inet_ipv4_addrs[r2], true); } } - return true; + return ret; } /****************************************************************************** @@ -621,33 +699,35 @@ bool target_device_connectivity_check(const char *ifname, target_connectivity_check_t *cstate, target_connectivity_check_option_t opts) { + int ret; + memset(cstate, 0 , sizeof(target_connectivity_check_t)); + ret = true; if (opts & LINK_CHECK) { cstate->link_state = util_connectivity_link_check(ifname); if (!cstate->link_state) - return false; + ret = false; } if (opts & ROUTER_CHECK) { cstate->router_state = util_connectivity_router_check(); if (!cstate->router_state) - return false; + ret = false; } if (opts & INTERNET_CHECK) { cstate->internet_state = util_connectivity_internet_check(); if (!cstate->internet_state) - return false; + ret = false; } if (opts & NTP_CHECK) { cstate->ntp_state = util_ntp_check(); if (!cstate->ntp_state) - return false; + ret = false; } - return true; + return ret; } #endif - diff --git a/src/lib/target/src/target_native.c b/src/lib/target/src/target_native.c index 5e752f57..6b631004 100644 --- a/src/lib/target/src/target_native.c +++ b/src/lib/target/src/target_native.c @@ -50,54 +50,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * TARGET definitions */ -/** - * Returns true if device serial name is correctly read - */ -bool target_serial_get(void *buff, size_t buffsz) -{ - memset(buff, 0, buffsz); - - os_macaddr_t mac; - size_t n; - - // get eth0 MAC address - if (true == os_nif_macaddr("eth0", &mac)) - { - n = snprintf(buff, buffsz, PRI(os_macaddr_plain_t), FMT(os_macaddr_t, mac)); - if (n >= buffsz) { - LOG(ERR, "buffer not large enough"); - return false; - } - return true; - } - - // eth0 not found, find en* interface - char interface[256]; - FILE *f; - int r; - *interface = 0; - f = popen("cd /sys/class/net; ls -d en* | head -1", "r"); - if (!f) return false; - r = fread(interface, 1, sizeof(interface), f); - if (r > 0) { - if (interface[r - 1] == '\n') r--; - interface[r] = 0; - } - pclose(f); - if (!*interface) return false; - if (true == os_nif_macaddr(interface, &mac)) - { - n = snprintf(buff, buffsz, PRI(os_macaddr_plain_t), FMT(os_macaddr_t, mac)); - if (n >= buffsz) { - LOG(ERR, "buffer not large enough"); - return false; - } - return true; - } - - return false; -} - void target_managers_restart(void) { } diff --git a/src/lib/target/src/target_stub.c b/src/lib/target/src/target_stub.c index 39bd7a94..34a0dcaa 100644 --- a/src/lib/target/src/target_stub.c +++ b/src/lib/target/src/target_stub.c @@ -66,60 +66,6 @@ bool target_close(target_init_opt_t opt, struct ev_loop *loop) } #endif -/****************************************************************************** - * Identity - *****************************************************************************/ - -#ifndef IMPL_target_serial_get -bool target_serial_get(void *buff, size_t buffsz) -{ - strscpy(((char*)buff), "STUB_SERIAL", buffsz); - return true; -} -#endif - -#ifndef IMPL_target_id_get -bool target_id_get(void *buff, size_t buffsz) -{ - return target_serial_get(buff, buffsz); -} -#endif - -#ifndef IMPL_target_sku_get -bool target_sku_get(void *buff, size_t buffsz) -{ - return false; -} -#endif - -#ifndef IMPL_target_model_get -bool target_model_get(void *buff, size_t buffsz) -{ - return false; -} -#endif - -#ifndef IMPL_target_sw_version_get -bool target_sw_version_get(void *buff, size_t buffsz) -{ - snprintf(buff, buffsz, "%s", app_build_ver_get()); - return true; -} -#endif - -#ifndef IMPL_target_hw_revision_get -bool target_hw_revision_get(void *buff, size_t buffsz) -{ - return false; -} -#endif - -#ifndef IMPL_target_platform_version_get -bool target_platform_version_get(void *buff, size_t buffsz) -{ - return false; -} -#endif #ifndef IMPL_target_log_open bool target_log_open(char *name, int flags) @@ -135,6 +81,13 @@ bool target_log_pull(const char *upload_location, const char *upload_token) } #endif +#ifndef IMPL_target_log_pull_ext +bool target_log_pull_ext(const char *upload_location, const char *upload_token, const char *upload_method) +{ + return true; +} +#endif + #ifndef IMPL_target_log_state_file // target_log_state_file is obsolete, not providing a stub #else @@ -247,18 +200,6 @@ bool target_radio_init(const struct target_radio_ops *ops) } #endif -#ifndef IMPL_target_radio_config_init -bool target_radio_config_init(ds_dlist_t *init_cfg) -{ - memset(init_cfg, 0, sizeof(*init_cfg)); - return false; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_radio_config_init is deprecated") -#endif -#endif - #ifndef IMPL_target_radio_config_init2 bool target_radio_config_init2(void) { @@ -273,17 +214,6 @@ bool target_radio_config_need_reset(void) } #endif -#ifndef IMPL_target_radio_config_set -bool target_radio_config_set(char *ifname, struct schema_Wifi_Radio_Config *rconf) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_radio_config_set is deprecated") -#endif -#endif - #ifndef IMPL_target_radio_config_set2 bool target_radio_config_set2(const struct schema_Wifi_Radio_Config *rconf, const struct schema_Wifi_Radio_Config_flags *changed) @@ -292,17 +222,6 @@ bool target_radio_config_set2(const struct schema_Wifi_Radio_Config *rconf, } #endif -#ifndef IMPL_target_radio_config_get -bool target_radio_config_get(char *ifname, struct schema_Wifi_Radio_Config *rconf) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_radio_config_get is deprecated") -#endif -#endif - #ifndef IMPL_target_radio_state_get bool target_radio_state_get(char *ifname, struct schema_Wifi_Radio_State *rstate) { @@ -314,28 +233,6 @@ bool target_radio_state_get(char *ifname, struct schema_Wifi_Radio_State *rstate #endif #endif -#ifndef IMPL_target_radio_state_register -bool target_radio_state_register(char *ifname, target_radio_state_cb_t *rstate_cb) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_radio_state_register is deprecated") -#endif -#endif - -#ifndef IMPL_target_radio_config_register -bool target_radio_config_register(char *ifname, target_radio_config_cb_t *rconf_cb) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_radio_config_register is deprecated") -#endif -#endif - /****************************************************************************** * INTERFACE *****************************************************************************/ @@ -352,17 +249,6 @@ const char *target_wan_interface_name() * VIF *****************************************************************************/ -#ifndef IMPL_target_vif_config_set -bool target_vif_config_set (char *ifname, struct schema_Wifi_VIF_Config *vconf) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_vif_config_set is deprecated") -#endif -#endif - #ifndef IMPL_target_vif_config_set2 bool target_vif_config_set2(const struct schema_Wifi_VIF_Config *vconf, const struct schema_Wifi_Radio_Config *rconf, @@ -374,17 +260,6 @@ bool target_vif_config_set2(const struct schema_Wifi_VIF_Config *vconf, } #endif -#ifndef IMPL_target_vif_config_get -bool target_vif_config_get(char *ifname, struct schema_Wifi_VIF_Config *vconf) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_vif_config_get is deprecated") -#endif -#endif - #ifndef IMPL_target_vif_state_get bool target_vif_state_get(char *ifname, struct schema_Wifi_VIF_State *vstate) { @@ -396,43 +271,6 @@ bool target_vif_state_get(char *ifname, struct schema_Wifi_VIF_State *vstate) #endif #endif -#ifndef IMPL_target_vif_state_register -bool target_vif_state_register(char *ifname, target_vif_state_cb_t *vstate_cb) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_vif_state_register is deprecated") -#endif -#endif - -#ifndef IMPL_target_vif_config_register -bool target_vif_config_register(char *ifname, target_vif_config_cb_t *rconf_cb) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_vif_config_register is deprecated") -#endif -#endif - -/****************************************************************************** - * CLIENTS definitions - *****************************************************************************/ - -#ifndef IMPL_target_clients_register -bool target_clients_register(char *ifname, target_clients_cb_t *clients_update_cb) -{ - return true; -} -#else -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#pragma message("target_clients_register is deprecated") -#endif -#endif - /****************************************************************************** * Ethernet clients *****************************************************************************/ diff --git a/src/lib/unity/inc/unity.h b/src/lib/unity/inc/unity.h index 64342383..8caa7852 100644 --- a/src/lib/unity/inc/unity.h +++ b/src/lib/unity/inc/unity.h @@ -1,6 +1,6 @@ /* ========================================== Unity Project - A Test Framework for C - Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams [Released under MIT License. Please refer to license.txt for details] ========================================== */ @@ -8,6 +8,11 @@ #define UNITY_FRAMEWORK_H #define UNITY +#define UNITY_VERSION_MAJOR 2 +#define UNITY_VERSION_MINOR 5 +#define UNITY_VERSION_BUILD 1 +#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD) + #ifdef __cplusplus extern "C" { @@ -15,9 +20,38 @@ extern "C" #include "unity_internals.h" +/*------------------------------------------------------- + * Test Setup / Teardown + *-------------------------------------------------------*/ + +/* These functions are intended to be called before and after each test. + * If using unity directly, these will need to be provided for each test + * executable built. If you are using the test runner generator and/or + * Ceedling, these are optional. */ void setUp(void); void tearDown(void); +/* These functions are intended to be called at the beginning and end of an + * entire test suite. suiteTearDown() is passed the number of tests that + * failed, and its return value becomes the exit code of main(). If using + * Unity directly, you're in charge of calling these if they are desired. + * If using Ceedling or the test runner generator, these will be called + * automatically if they exist. */ +void suiteSetUp(void); +int suiteTearDown(int num_failures); + +/*------------------------------------------------------- + * Test Reset and Verify + *-------------------------------------------------------*/ + +/* These functions are intended to be called before during tests in order + * to support complex test loops, etc. Both are NOT built into Unity. Instead + * the test runner generator will create them. resetTest will run teardown and + * setup again, verifying any end-of-test needs between. verifyTest will only + * run the verification. */ +void resetTest(void); +void verifyTest(void); + /*------------------------------------------------------- * Configuration Options *------------------------------------------------------- @@ -68,11 +102,16 @@ void tearDown(void); #define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) #define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) #define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) +#define TEST_MESSAGE(message) UnityMessage((message), __LINE__) #define TEST_ONLY() +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__) +#endif /* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ #define TEST_PASS() TEST_ABORT() +#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while(0) /* This macro does nothing, but it is useful for build tools (like Ceedling) to make use of this to figure out * which files should be linked to in order to perform a test. Use it like TEST_FILE("sandwiches.c") */ @@ -89,6 +128,8 @@ void tearDown(void); #define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") #define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") #define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") +#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty") +#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty") /* Integers (of all sizes) */ #define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) @@ -96,24 +137,115 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") #define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, NULL) #define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, NULL) #define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, NULL) #define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, NULL) +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) @@ -125,11 +257,33 @@ void tearDown(void); #define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_size_t_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_CHAR_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, NULL) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_size_t_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) + /* Structs and Strings */ #define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) @@ -148,6 +302,7 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) @@ -156,6 +311,7 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) /* Arrays Compared To Single Value */ #define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL) @@ -168,6 +324,7 @@ void tearDown(void); #define TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_size_t(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_HEX(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, NULL) @@ -176,6 +333,7 @@ void tearDown(void); #define TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, NULL) /* Floating Point (If Enabled) */ #define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL) @@ -205,6 +363,28 @@ void tearDown(void); #define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) #define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, " Expected Equal") +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + /*------------------------------------------------------- * Test Asserts (with additional messages) *-------------------------------------------------------*/ @@ -216,6 +396,8 @@ void tearDown(void); #define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) #define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) #define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) +#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message)) /* Integers (of all sizes) */ #define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) @@ -223,13 +405,12 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) @@ -240,6 +421,99 @@ void tearDown(void); #define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message)) #define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) #define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message)) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) @@ -252,11 +526,33 @@ void tearDown(void); #define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_size_t_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_CHAR_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, (message)) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_size_t_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) + /* Structs and Strings */ #define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) @@ -275,6 +571,7 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) @@ -283,6 +580,7 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) /* Arrays Compared To Single Value*/ #define TEST_ASSERT_EACH_EQUAL_INT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, (message)) @@ -295,7 +593,8 @@ void tearDown(void); #define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_size_t_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) @@ -303,6 +602,7 @@ void tearDown(void); #define TEST_ASSERT_EACH_EQUAL_PTR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_STRING_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_MEMORY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_CHAR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, (message)) /* Floating Point (If Enabled) */ #define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message)) @@ -332,6 +632,28 @@ void tearDown(void); #define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) #define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + /* end of UNITY_FRAMEWORK_H */ #ifdef __cplusplus } diff --git a/src/lib/unity/inc/unity_internals.h b/src/lib/unity/inc/unity_internals.h index 9504451a..d7c2116c 100644 --- a/src/lib/unity/inc/unity_internals.h +++ b/src/lib/unity/inc/unity_internals.h @@ -1,6 +1,6 @@ /* ========================================== Unity Project - A Test Framework for C - Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams [Released under MIT License. Please refer to license.txt for details] ========================================== */ @@ -19,6 +19,14 @@ #include #endif +#ifndef UNITY_EXCLUDE_STDDEF_H +#include +#endif + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#include +#endif + /* Unity Attempts to Auto-Detect Integer Types * Attempt 1: UINT_MAX, ULONG_MAX in , or default to 32 bits * Attempt 2: UINTPTR_MAX in , or default to same size as long @@ -39,6 +47,8 @@ /* Determine the size of an int, if not already specified. * We cannot use sizeof(int), because it is not yet defined * at this stage in the translation of the C program. + * Also sizeof(int) does return the size in addressable units on all platforms, + * which may not necessarily be the size in bytes. * Therefore, infer it from UINT_MAX if possible. */ #ifndef UNITY_INT_WIDTH #ifdef UINT_MAX @@ -110,19 +120,21 @@ * 64-bit Support *-------------------------------------------------------*/ +/* Auto-detect 64 Bit Support */ #ifndef UNITY_SUPPORT_64 #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64 #define UNITY_SUPPORT_64 #endif #endif +/* 64-Bit Support Dependent Configuration */ #ifndef UNITY_SUPPORT_64 /* No 64-bit Support */ typedef UNITY_UINT32 UNITY_UINT; - typedef UNITY_INT32 UNITY_INT; + typedef UNITY_INT32 UNITY_INT; + #define UNITY_MAX_NIBBLES (8) /* Maximum number of nibbles in a UNITY_(U)INT */ #else - - /* 64-bit Support */ + /* 64-bit Support */ #if (UNITY_LONG_WIDTH == 32) typedef unsigned long long UNITY_UINT64; typedef signed long long UNITY_INT64; @@ -133,8 +145,8 @@ #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) #endif typedef UNITY_UINT64 UNITY_UINT; - typedef UNITY_INT64 UNITY_INT; - + typedef UNITY_INT64 UNITY_INT; + #define UNITY_MAX_NIBBLES (16) /* Maximum number of nibbles in a UNITY_(U)INT */ #endif /*------------------------------------------------------- @@ -142,24 +154,24 @@ *-------------------------------------------------------*/ #if (UNITY_POINTER_WIDTH == 32) -#define UNITY_PTR_TO_INT UNITY_INT32 -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 + #define UNITY_PTR_TO_INT UNITY_INT32 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 #elif (UNITY_POINTER_WIDTH == 64) -#define UNITY_PTR_TO_INT UNITY_INT64 -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 + #define UNITY_PTR_TO_INT UNITY_INT64 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 #elif (UNITY_POINTER_WIDTH == 16) -#define UNITY_PTR_TO_INT UNITY_INT16 -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 + #define UNITY_PTR_TO_INT UNITY_INT16 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 #else - #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) + #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) #endif #ifndef UNITY_PTR_ATTRIBUTE -#define UNITY_PTR_ATTRIBUTE + #define UNITY_PTR_ATTRIBUTE #endif #ifndef UNITY_INTERNAL_PTR -#define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* + #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* #endif /*------------------------------------------------------- @@ -241,30 +253,30 @@ typedef UNITY_FLOAT_TYPE UNITY_FLOAT; * Output Method: stdout (DEFAULT) *-------------------------------------------------------*/ #ifndef UNITY_OUTPUT_CHAR -/* Default to using putchar, which is defined in stdio.h */ -#include -#define UNITY_OUTPUT_CHAR(a) (void)putchar(a) + /* Default to using putchar, which is defined in stdio.h */ + #include + #define UNITY_OUTPUT_CHAR(a) (void)putchar(a) #else /* If defined as something else, make sure we declare it here so it's ready for use */ #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION -extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; + extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; #endif #endif #ifndef UNITY_OUTPUT_FLUSH -#ifdef UNITY_USE_FLUSH_STDOUT -/* We want to use the stdout flush utility */ -#include -#define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) -#else -/* We've specified nothing, therefore flush should just be ignored */ -#define UNITY_OUTPUT_FLUSH() -#endif + #ifdef UNITY_USE_FLUSH_STDOUT + /* We want to use the stdout flush utility */ + #include + #define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) + #else + /* We've specified nothing, therefore flush should just be ignored */ + #define UNITY_OUTPUT_FLUSH() + #endif #else -/* We've defined flush as something else, so make sure we declare it here so it's ready for use */ -#ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION -extern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION; -#endif + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION + extern void UNITY_OUTPUT_FLUSH_HEADER_DECLARATION; + #endif #endif #ifndef UNITY_OUTPUT_FLUSH @@ -285,6 +297,69 @@ extern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION; #define UNITY_OUTPUT_COMPLETE() #endif +#ifdef UNITY_INCLUDE_EXEC_TIME + #if !defined(UNITY_EXEC_TIME_START) && \ + !defined(UNITY_EXEC_TIME_STOP) && \ + !defined(UNITY_PRINT_EXEC_TIME) && \ + !defined(UNITY_TIME_TYPE) + /* If none any of these macros are defined then try to provide a default implementation */ + + #if defined(UNITY_CLOCK_MS) + /* This is a simple way to get a default implementation on platforms that support getting a millisecond counter */ + #define UNITY_TIME_TYPE UNITY_UINT + #define UNITY_EXEC_TIME_START() Unity.CurrentTestStartTime = UNITY_CLOCK_MS() + #define UNITY_EXEC_TIME_STOP() Unity.CurrentTestStopTime = UNITY_CLOCK_MS() + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(_WIN32) + #include + #define UNITY_TIME_TYPE clock_t + #define UNITY_GET_TIME(t) t = (clock_t)((clock() * 1000) / CLOCKS_PER_SEC) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(__unix__) + #include + #define UNITY_TIME_TYPE struct timespec + #define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = ((Unity.CurrentTestStopTime.tv_sec - Unity.CurrentTestStartTime.tv_sec) * 1000L); \ + execTimeMs += ((Unity.CurrentTestStopTime.tv_nsec - Unity.CurrentTestStartTime.tv_nsec) / 1000000L); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #endif + #endif +#endif + +#ifndef UNITY_EXEC_TIME_START +#define UNITY_EXEC_TIME_START() do{}while(0) +#endif + +#ifndef UNITY_EXEC_TIME_STOP +#define UNITY_EXEC_TIME_STOP() do{}while(0) +#endif + +#ifndef UNITY_TIME_TYPE +#define UNITY_TIME_TYPE UNITY_UINT +#endif + +#ifndef UNITY_PRINT_EXEC_TIME +#define UNITY_PRINT_EXEC_TIME() do{}while(0) +#endif + /*------------------------------------------------------- * Footprint *-------------------------------------------------------*/ @@ -297,23 +372,6 @@ extern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION; #define UNITY_COUNTER_TYPE UNITY_UINT #endif -/*------------------------------------------------------- - * Language Features Available - *-------------------------------------------------------*/ -#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) -# ifdef __GNUC__ /* includes clang */ -# if !(defined(__WIN32__) && defined(__clang__)) && !defined(__TMS470__) -# define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) -# endif -# endif -#endif - -#ifdef UNITY_NO_WEAK -# undef UNITY_WEAK_ATTRIBUTE -# undef UNITY_WEAK_PRAGMA -#endif - - /*------------------------------------------------------- * Internal Structs Needed *-------------------------------------------------------*/ @@ -323,10 +381,11 @@ typedef void (*UnityTestFunction)(void); #define UNITY_DISPLAY_RANGE_INT (0x10) #define UNITY_DISPLAY_RANGE_UINT (0x20) #define UNITY_DISPLAY_RANGE_HEX (0x40) +#define UNITY_DISPLAY_RANGE_CHAR (0x80) typedef enum { -UNITY_DISPLAY_STYLE_INT = sizeof(int)+ UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, @@ -334,7 +393,7 @@ UNITY_DISPLAY_STYLE_INT = sizeof(int)+ UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, #endif -UNITY_DISPLAY_STYLE_UINT = sizeof(unsigned) + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, @@ -349,9 +408,23 @@ UNITY_DISPLAY_STYLE_UINT = sizeof(unsigned) + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, #endif + UNITY_DISPLAY_STYLE_CHAR = 1 + UNITY_DISPLAY_RANGE_CHAR + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_UNKNOWN } UNITY_DISPLAY_STYLE_T; +typedef enum +{ + UNITY_WITHIN = 0x0, + UNITY_EQUAL_TO = 0x1, + UNITY_GREATER_THAN = 0x2, + UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO, + UNITY_SMALLER_THAN = 0x4, + UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO, + UNITY_NOT_EQUAL = 0x0, + UNITY_UNKNOWN +} UNITY_COMPARISON_T; + #ifndef UNITY_EXCLUDE_FLOAT typedef enum UNITY_FLOAT_TRAIT { @@ -370,7 +443,8 @@ typedef enum UNITY_FLOAT_TRAIT typedef enum { UNITY_ARRAY_TO_VAL = 0, - UNITY_ARRAY_TO_ARRAY + UNITY_ARRAY_TO_ARRAY, + UNITY_ARRAY_UNKNOWN } UNITY_FLAGS_T; struct UNITY_STORAGE_T @@ -387,6 +461,10 @@ struct UNITY_STORAGE_T UNITY_COUNTER_TYPE TestIgnores; UNITY_COUNTER_TYPE CurrentTestFailed; UNITY_COUNTER_TYPE CurrentTestIgnored; +#ifdef UNITY_INCLUDE_EXEC_TIME + UNITY_TIME_TYPE CurrentTestStartTime; + UNITY_TIME_TYPE CurrentTestStopTime; +#endif #ifndef UNITY_EXCLUDE_SETJMP_H jmp_buf AbortFrame; #endif @@ -400,8 +478,14 @@ extern struct UNITY_STORAGE_T Unity; void UnityBegin(const char* filename); int UnityEnd(void); +void UnitySetTestFile(const char* filename); void UnityConcludeTest(void); + +#ifndef RUN_TEST void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); +#else +#define UNITY_SKIP_DEFAULT_RUNNER +#endif /*------------------------------------------------------- * Details Support @@ -413,8 +497,8 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int #define UNITY_SET_DETAILS(d1,d2) #else #define UNITY_CLR_DETAILS() { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } -#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = d1; Unity.CurrentDetail2 = 0; } -#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = d1; Unity.CurrentDetail2 = d2; } +#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = (d2); } #ifndef UNITY_DETAIL1_NAME #define UNITY_DETAIL1_NAME "Function" @@ -425,17 +509,26 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int #endif #endif +#ifdef UNITY_PRINT_TEST_CONTEXT +void UNITY_PRINT_TEST_CONTEXT(void); +#endif + /*------------------------------------------------------- * Test Output *-------------------------------------------------------*/ void UnityPrint(const char* string); + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...); +#endif + void UnityPrintLen(const char* string, const UNITY_UINT32 length); void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number); void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style); -void UnityPrintNumber(const UNITY_INT number); +void UnityPrintNumber(const UNITY_INT number_to_print); void UnityPrintNumberUnsigned(const UNITY_UINT number); -void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles); +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print); #ifndef UNITY_EXCLUDE_FLOAT_PRINT void UnityPrintFloat(const UNITY_DOUBLE input_number); @@ -455,6 +548,13 @@ void UnityAssertEqualNumber(const UNITY_INT expected, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, const UNITY_UINT32 num_elements, @@ -502,9 +602,18 @@ void UnityAssertNumbersWithin(const UNITY_UINT delta, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); -void UnityFail(const char* message, const UNITY_LINE_TYPE line); +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags); +void UnityFail(const char* message, const UNITY_LINE_TYPE line); void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +void UnityMessage(const char* message, const UNITY_LINE_TYPE line); #ifndef UNITY_EXCLUDE_FLOAT void UnityAssertFloatsWithin(const UNITY_FLOAT delta, @@ -562,9 +671,15 @@ UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num); * Error Strings We Might Need *-------------------------------------------------------*/ +extern const char UnityStrOk[]; +extern const char UnityStrPass[]; +extern const char UnityStrFail[]; +extern const char UnityStrIgnore[]; + extern const char UnityStrErrFloat[]; extern const char UnityStrErrDouble[]; extern const char UnityStrErr64[]; +extern const char UnityStrErrShorthand[]; /*------------------------------------------------------- * Test Running Macros @@ -582,6 +697,10 @@ extern const char UnityStrErr64[]; #ifndef RUN_TEST #ifdef __STDC_VERSION__ #if __STDC_VERSION__ >= 199901L +#define UNITY_SUPPORT_VARIADIC_MACROS +#endif +#endif +#ifdef UNITY_SUPPORT_VARIADIC_MACROS #define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__)) #define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway) #define RUN_TEST_FIRST_HELPER(first, ...) (first), #first @@ -589,7 +708,6 @@ extern const char UnityStrErr64[]; #define RUN_TEST_SECOND_HELPER(first, second, ...) (second) #endif #endif -#endif /* If we can't do the tricky version, we'll just have to require them to always include the line number */ #ifndef RUN_TEST @@ -615,6 +733,16 @@ extern const char UnityStrErr64[]; #define UNITY_END() UnityEnd() #endif +#ifndef UNITY_SHORTHAND_AS_INT +#ifndef UNITY_SHORTHAND_AS_MEM +#ifndef UNITY_SHORTHAND_AS_NONE +#ifndef UNITY_SHORTHAND_AS_RAW +#define UNITY_SHORTHAND_AS_OLD +#endif +#endif +#endif +#endif + /*----------------------------------------------- * Command Line Argument Support *-----------------------------------------------*/ @@ -635,9 +763,11 @@ int UnityTestMatches(void); * Test Asserts *-------------------------------------------------------*/ -#define UNITY_TEST_ASSERT(condition, line, message) if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));} +#define UNITY_TEST_ASSERT(condition, line, message) do {if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}} while(0) #define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) #define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) == 0), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) != 0), (UNITY_LINE_TYPE)(line), (message)) #define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) #define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) @@ -650,19 +780,100 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) #define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) #define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) #define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16) (threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32) (threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16) (expected), (UNITY_INT)(UNITY_INT16) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32) (expected), (UNITY_INT)(UNITY_INT32) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) #define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) #define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) #define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) #define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) #define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) #define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_CHAR_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + #define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_PTR_TO_INT)(expected), (UNITY_PTR_TO_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) #define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message) UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line)) @@ -683,21 +894,23 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) - -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) expected, sizeof(int)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )expected, 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )expected, 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )expected, 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) expected, sizeof(unsigned int)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT8 )expected, 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT16)expected, 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT32)expected, 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )expected, 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )expected, 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )expected, 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_PTR_TO_INT) expected, sizeof(int*)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT16)(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT32)(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_PTR_TO_INT) (expected), (UNITY_POINTER_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_VAL) #define UNITY_TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) #define UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_VAL) #ifdef UNITY_SUPPORT_64 #define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) @@ -706,12 +919,30 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_VAL) #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) #else #define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) @@ -722,6 +953,21 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #endif #ifdef UNITY_EXCLUDE_FLOAT @@ -766,10 +1012,10 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) #define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) #else -#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)line) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual, (UNITY_LINE_TYPE)(line), message) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((UNITY_DOUBLE*)(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_ARRAY_TO_ARRAY) -#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray(UnityDoubleToPtr(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((UNITY_DOUBLE*)(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray(UnityDoubleToPtr(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) #define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) #define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) #define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) diff --git a/src/lib/unity/src/unity.c b/src/lib/unity/src/unity.c index 177af0f4..ffa5cf0d 100644 --- a/src/lib/unity/src/unity.c +++ b/src/lib/unity/src/unity.c @@ -1,61 +1,131 @@ /* ========================================================================= Unity Project - A Test Framework for C - Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams [Released under MIT License. Please refer to license.txt for details] ============================================================================ */ #include "unity.h" #include +#ifdef AVR +#include +#else +#define PROGMEM +#endif + /* If omitted from header, declare overrideable prototypes here so they're ready for use */ #ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION void UNITY_OUTPUT_CHAR(int); #endif /* Helpful macros for us to use here in Assert functions */ -#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; TEST_ABORT(); } -#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; TEST_ABORT(); } -#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) return +#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } +#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } +#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) TEST_ABORT() struct UNITY_STORAGE_T Unity; -static const char UnityStrOk[] = "OK"; -static const char UnityStrPass[] = "PASS"; -static const char UnityStrFail[] = "FAIL"; -static const char UnityStrIgnore[] = "IGNORE"; -static const char UnityStrNull[] = "NULL"; -static const char UnityStrSpacer[] = ". "; -static const char UnityStrExpected[] = " Expected "; -static const char UnityStrWas[] = " Was "; -static const char UnityStrElement[] = " Element "; -static const char UnityStrByte[] = " Byte "; -static const char UnityStrMemory[] = " Memory Mismatch."; -static const char UnityStrDelta[] = " Values Not Within Delta "; -static const char UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; -static const char UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; -static const char UnityStrNullPointerForActual[] = " Actual pointer was NULL"; +#ifdef UNITY_OUTPUT_COLOR +const char PROGMEM UnityStrOk[] = "\033[42mOK\033[00m"; +const char PROGMEM UnityStrPass[] = "\033[42mPASS\033[00m"; +const char PROGMEM UnityStrFail[] = "\033[41mFAIL\033[00m"; +const char PROGMEM UnityStrIgnore[] = "\033[43mIGNORE\033[00m"; +#else +const char PROGMEM UnityStrOk[] = "OK"; +const char PROGMEM UnityStrPass[] = "PASS"; +const char PROGMEM UnityStrFail[] = "FAIL"; +const char PROGMEM UnityStrIgnore[] = "IGNORE"; +#endif +static const char PROGMEM UnityStrNull[] = "NULL"; +static const char PROGMEM UnityStrSpacer[] = ". "; +static const char PROGMEM UnityStrExpected[] = " Expected "; +static const char PROGMEM UnityStrWas[] = " Was "; +static const char PROGMEM UnityStrGt[] = " to be greater than "; +static const char PROGMEM UnityStrLt[] = " to be less than "; +static const char PROGMEM UnityStrOrEqual[] = "or equal to "; +static const char PROGMEM UnityStrNotEqual[] = " to be not equal to "; +static const char PROGMEM UnityStrElement[] = " Element "; +static const char PROGMEM UnityStrByte[] = " Byte "; +static const char PROGMEM UnityStrMemory[] = " Memory Mismatch."; +static const char PROGMEM UnityStrDelta[] = " Values Not Within Delta "; +static const char PROGMEM UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; +static const char PROGMEM UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; +static const char PROGMEM UnityStrNullPointerForActual[] = " Actual pointer was NULL"; #ifndef UNITY_EXCLUDE_FLOAT -static const char UnityStrNot[] = "Not "; -static const char UnityStrInf[] = "Infinity"; -static const char UnityStrNegInf[] = "Negative Infinity"; -static const char UnityStrNaN[] = "NaN"; -static const char UnityStrDet[] = "Determinate"; -static const char UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; +static const char PROGMEM UnityStrNot[] = "Not "; +static const char PROGMEM UnityStrInf[] = "Infinity"; +static const char PROGMEM UnityStrNegInf[] = "Negative Infinity"; +static const char PROGMEM UnityStrNaN[] = "NaN"; +static const char PROGMEM UnityStrDet[] = "Determinate"; +static const char PROGMEM UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; #endif -const char UnityStrErrFloat[] = "Unity Floating Point Disabled"; -const char UnityStrErrDouble[] = "Unity Double Precision Disabled"; -const char UnityStrErr64[] = "Unity 64-bit Support Disabled"; -static const char UnityStrBreaker[] = "-----------------------"; -static const char UnityStrResultsTests[] = " Tests "; -static const char UnityStrResultsFailures[] = " Failures "; -static const char UnityStrResultsIgnored[] = " Ignored "; -static const char UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; -static const char UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; +const char PROGMEM UnityStrErrShorthand[] = "Unity Shorthand Support Disabled"; +const char PROGMEM UnityStrErrFloat[] = "Unity Floating Point Disabled"; +const char PROGMEM UnityStrErrDouble[] = "Unity Double Precision Disabled"; +const char PROGMEM UnityStrErr64[] = "Unity 64-bit Support Disabled"; +static const char PROGMEM UnityStrBreaker[] = "-----------------------"; +static const char PROGMEM UnityStrResultsTests[] = " Tests "; +static const char PROGMEM UnityStrResultsFailures[] = " Failures "; +static const char PROGMEM UnityStrResultsIgnored[] = " Ignored "; +static const char PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; +static const char PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; /*----------------------------------------------- * Pretty Printers & Test Result Output Handlers *-----------------------------------------------*/ +/*-----------------------------------------------*/ +/* Local helper function to print characters. */ +static void UnityPrintChar(const char* pch) +{ + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); + } +} + +/*-----------------------------------------------*/ +/* Local helper function to print ANSI escape strings e.g. "\033[42m". */ +#ifdef UNITY_OUTPUT_COLOR +static UNITY_UINT UnityPrintAnsiEscapeString(const char* string) +{ + const char* pch = string; + UNITY_UINT count = 0; + + while (*pch && (*pch != 'm')) + { + UNITY_OUTPUT_CHAR(*pch); + pch++; + count++; + } + UNITY_OUTPUT_CHAR('m'); + count++; + + return count; +} +#endif + +/*-----------------------------------------------*/ void UnityPrint(const char* string) { const char* pch = string; @@ -64,6 +134,28 @@ void UnityPrint(const char* string) { while (*pch) { +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + UnityPrintChar(pch); + pch++; + } + } +} +/*-----------------------------------------------*/ +void UnityPrintLen(const char* string, const UNITY_UINT32 length) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch && ((UNITY_UINT32)(pch - string) < length)) + { /* printable characters plus CR & LF are printed */ if ((*pch <= 126) && (*pch >= 32)) { @@ -93,27 +185,27 @@ void UnityPrint(const char* string) } } -void UnityPrintLen(const char* string, const UNITY_UINT32 length) +/*-----------------------------------------------*/ +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style) { - const char* pch = string; - - if (pch != NULL) + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) { - while (*pch && (UNITY_UINT32)(pch - string) < length) + if (style == UNITY_DISPLAY_STYLE_CHAR) { /* printable characters plus CR & LF are printed */ - if ((*pch <= 126) && (*pch >= 32)) + UNITY_OUTPUT_CHAR('\''); + if ((number <= 126) && (number >= 32)) { - UNITY_OUTPUT_CHAR(*pch); + UNITY_OUTPUT_CHAR((int)number); } /* write escaped carriage returns */ - else if (*pch == 13) + else if (number == 13) { UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('r'); } /* write escaped line feeds */ - else if (*pch == 10) + else if (number == 10) { UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('n'); @@ -123,19 +215,14 @@ void UnityPrintLen(const char* string, const UNITY_UINT32 length) { UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)*pch, 2); + UnityPrintNumberHex((UNITY_UINT)number, 2); } - pch++; + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrintNumber(number); } - } -} - -/*-----------------------------------------------*/ -void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style) -{ - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - UnityPrintNumber(number); } else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) { @@ -158,7 +245,7 @@ void UnityPrintNumber(const UNITY_INT number_to_print) { /* A negative number, including MIN negative */ UNITY_OUTPUT_CHAR('-'); - number = (UNITY_UINT)(-number_to_print); + number = (~number) + 1; } UnityPrintNumberUnsigned(number); } @@ -188,8 +275,11 @@ void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) { int nibble; char nibbles = nibbles_to_print; - if ((unsigned)nibbles > (2 * sizeof(number))) - nibbles = 2 * sizeof(number); + + if ((unsigned)nibbles > UNITY_MAX_NIBBLES) + { + nibbles = UNITY_MAX_NIBBLES; + } while (nibbles > 0) { @@ -235,95 +325,162 @@ void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number) /*-----------------------------------------------*/ #ifndef UNITY_EXCLUDE_FLOAT_PRINT -static void UnityPrintDecimalAndNumberWithLeadingZeros(UNITY_INT32 fraction_part, UNITY_INT32 divisor) +/* + * This function prints a floating-point value in a format similar to + * printf("%.7g") on a single-precision machine or printf("%.9g") on a + * double-precision machine. The 7th digit won't always be totally correct + * in single-precision operation (for that level of accuracy, a more + * complicated algorithm would be needed). + */ +void UnityPrintFloat(const UNITY_DOUBLE input_number) { - UNITY_OUTPUT_CHAR('.'); - while (divisor > 0) - { - UNITY_OUTPUT_CHAR('0' + fraction_part / divisor); - fraction_part %= divisor; - divisor /= 10; - if (fraction_part == 0) break; /* Truncate trailing 0's */ - } -} -#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO -/* If rounds up && remainder 0.5 && result odd && below cutoff for double precision issues */ - #define ROUND_TIES_TO_EVEN(orig, num_int, num) \ - if (num_int > (num) && (num) - (num_int-1) <= 0.5 && (num_int & 1) == 1 && orig < 1e22) \ - num_int -= 1 /* => a tie to round down to even */ +#ifdef UNITY_INCLUDE_DOUBLE + static const int sig_digits = 9; + static const UNITY_INT32 min_scaled = 100000000; + static const UNITY_INT32 max_scaled = 1000000000; #else - #define ROUND_TIES_TO_EVEN(orig, num_int, num) /* Remove macro */ + static const int sig_digits = 7; + static const UNITY_INT32 min_scaled = 1000000; + static const UNITY_INT32 max_scaled = 10000000; #endif -/* Printing floating point numbers is hard. Some goals of this implementation: works for embedded - * systems, floats or doubles, and has a reasonable format. The key paper in this area, - * 'How to Print Floating-Point Numbers Accurately' by Steele & White, shows an approximation by - * scaling called Dragon 2. This code uses a similar idea. The other core algorithm uses casts and - * floating subtraction to give exact remainders after the decimal, to be scaled into an integer. - * Extra trailing 0's are excluded. The output defaults to rounding to nearest, ties to even. You - * can enable rounding ties away from zero. Note: UNITY_DOUBLE param can typedef to float or double - - * The old version required compiling in snprintf. For reference, with a similar format as now: - * char buf[19]; - * if (number > 4294967296.0 || -number > 4294967296.0) snprintf(buf, sizeof buf, "%.8e", number); - * else snprintf(buf, sizeof buf, "%.6f", number); - * UnityPrint(buf); - */ -void UnityPrintFloat(const UNITY_DOUBLE input_number) -{ - UNITY_DOUBLE number; + UNITY_DOUBLE number = input_number; - if (input_number < 0) + /* print minus sign (does not handle negative zero) */ + if (number < 0.0f) { UNITY_OUTPUT_CHAR('-'); - number = -input_number; - } else - { - number = input_number; + number = -number; } - if (isnan(number)) UnityPrint(UnityStrNaN); - else if (isinf(number)) UnityPrintLen(UnityStrInf, 3); - else if (number <= 0.0000005 && number > 0) UnityPrint("0.000000..."); /* Small number */ - else if (number < 4294967295.9999995) /* Rounded result fits in 32 bits, "%.6f" format */ + /* handle zero, NaN, and +/- infinity */ + if (number == 0.0f) + { + UnityPrint("0"); + } + else if (isnan(number)) { - const UNITY_INT32 divisor = 1000000/10; - UNITY_UINT32 integer_part = (UNITY_UINT32)number; - UNITY_INT32 fraction_part = (UNITY_INT32)((number - (UNITY_DOUBLE)integer_part)*1000000.0 + 0.5); - /* Double precision calculation gives best performance for six rounded decimal places */ - ROUND_TIES_TO_EVEN(number, fraction_part, (number - (UNITY_DOUBLE)integer_part)*1000000.0); + UnityPrint("nan"); + } + else if (isinf(number)) + { + UnityPrint("inf"); + } + else + { + UNITY_INT32 n_int = 0, n; + int exponent = 0; + int decimals, digits; + char buf[16] = {0}; + + /* + * Scale up or down by powers of 10. To minimize rounding error, + * start with a factor/divisor of 10^10, which is the largest + * power of 10 that can be represented exactly. Finally, compute + * (exactly) the remaining power of 10 and perform one more + * multiplication or division. + */ + if (number < 1.0f) + { + UNITY_DOUBLE factor = 1.0f; + + while (number < (UNITY_DOUBLE)max_scaled / 1e10f) { number *= 1e10f; exponent -= 10; } + while (number * factor < (UNITY_DOUBLE)min_scaled) { factor *= 10.0f; exponent--; } + + number *= factor; + } + else if (number > (UNITY_DOUBLE)max_scaled) + { + UNITY_DOUBLE divisor = 1.0f; + + while (number > (UNITY_DOUBLE)min_scaled * 1e10f) { number /= 1e10f; exponent += 10; } + while (number / divisor > (UNITY_DOUBLE)max_scaled) { divisor *= 10.0f; exponent++; } - if (fraction_part == 1000000) /* Carry across the decimal point */ + number /= divisor; + } + else { - fraction_part = 0; - integer_part += 1; + /* + * In this range, we can split off the integer part before + * doing any multiplications. This reduces rounding error by + * freeing up significant bits in the fractional part. + */ + UNITY_DOUBLE factor = 1.0f; + n_int = (UNITY_INT32)number; + number -= (UNITY_DOUBLE)n_int; + + while (n_int < min_scaled) { n_int *= 10; factor *= 10.0f; exponent--; } + + number *= factor; } - UnityPrintNumberUnsigned(integer_part); - UnityPrintDecimalAndNumberWithLeadingZeros(fraction_part, divisor); - } - else /* Number is larger, use exponential format of 9 digits, "%.8e" */ - { - const UNITY_INT32 divisor = 1000000000/10; - UNITY_INT32 integer_part; - UNITY_DOUBLE_TYPE divide = 10.0; - int exponent = 9; + /* round to nearest integer */ + n = ((UNITY_INT32)(number + number) + 1) / 2; - while (number / divide >= 1000000000.0 - 0.5) +#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO + /* round to even if exactly between two integers */ + if ((n & 1) && (((UNITY_DOUBLE)n - number) == 0.5f)) + n--; +#endif + + n += n_int; + + if (n >= max_scaled) { - divide *= 10; + n = min_scaled; exponent++; } - integer_part = (UNITY_INT32)(number / divide + 0.5); - /* Double precision calculation required for float, to produce 9 rounded digits */ - ROUND_TIES_TO_EVEN(number, integer_part, number / divide); - UNITY_OUTPUT_CHAR('0' + integer_part / divisor); - UnityPrintDecimalAndNumberWithLeadingZeros(integer_part % divisor, divisor / 10); - UNITY_OUTPUT_CHAR('e'); - UNITY_OUTPUT_CHAR('+'); - if (exponent < 10) UNITY_OUTPUT_CHAR('0'); - UnityPrintNumber(exponent); + /* determine where to place decimal point */ + decimals = ((exponent <= 0) && (exponent >= -(sig_digits + 3))) ? (-exponent) : (sig_digits - 1); + exponent += decimals; + + /* truncate trailing zeroes after decimal point */ + while ((decimals > 0) && ((n % 10) == 0)) + { + n /= 10; + decimals--; + } + + /* build up buffer in reverse order */ + digits = 0; + while ((n != 0) || (digits < (decimals + 1))) + { + buf[digits++] = (char)('0' + n % 10); + n /= 10; + } + while (digits > 0) + { + if (digits == decimals) { UNITY_OUTPUT_CHAR('.'); } + UNITY_OUTPUT_CHAR(buf[--digits]); + } + + /* print exponent if needed */ + if (exponent != 0) + { + UNITY_OUTPUT_CHAR('e'); + + if (exponent < 0) + { + UNITY_OUTPUT_CHAR('-'); + exponent = -exponent; + } + else + { + UNITY_OUTPUT_CHAR('+'); + } + + digits = 0; + while ((exponent != 0) || (digits < 2)) + { + buf[digits++] = (char)('0' + exponent % 10); + exponent /= 10; + } + while (digits > 0) + { + UNITY_OUTPUT_CHAR(buf[--digits]); + } + } } } #endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */ @@ -331,12 +488,44 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number) /*-----------------------------------------------*/ static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) { +#ifdef UNITY_OUTPUT_FOR_ECLIPSE + UNITY_OUTPUT_CHAR('('); UnityPrint(file); UNITY_OUTPUT_CHAR(':'); UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(')'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); UNITY_OUTPUT_CHAR(':'); +#else +#ifdef UNITY_OUTPUT_FOR_IAR_WORKBENCH + UnityPrint("'); UnityPrint(Unity.CurrentTestName); + UnityPrint(" "); +#else +#ifdef UNITY_OUTPUT_FOR_QT_CREATOR + UnityPrint("file://"); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else + UnityPrint(file); UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(':'); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#endif +#endif +#endif } /*-----------------------------------------------*/ @@ -366,6 +555,7 @@ void UnityConcludeTest(void) Unity.CurrentTestFailed = 0; Unity.CurrentTestIgnored = 0; + UNITY_PRINT_EXEC_TIME(); UNITY_PRINT_EOL(); UNITY_FLUSH_CALL(); } @@ -376,6 +566,10 @@ static void UnityAddMsgIfSpecified(const char* msg) if (msg) { UnityPrint(UnityStrSpacer); + +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif #ifndef UNITY_EXCLUDE_DETAILS if (Unity.CurrentDetail1) { @@ -453,12 +647,14 @@ static void UnityPrintExpectedAndActualStringsLen(const char* expected, * Assertion & Control Helpers *-----------------------------------------------*/ +/*-----------------------------------------------*/ static int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, const UNITY_LINE_TYPE lineNumber, const char* msg) { - if (expected == actual) return 0; /* Both are NULL or same pointer */ + /* Both are NULL or same pointer */ + if (expected == actual) { return 0; } /* print and return true if just expected is NULL */ if (expected == NULL) @@ -485,6 +681,7 @@ static int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected, * Assertion Functions *-----------------------------------------------*/ +/*-----------------------------------------------*/ void UnityAssertBits(const UNITY_INT mask, const UNITY_INT expected, const UNITY_INT actual, @@ -526,6 +723,46 @@ void UnityAssertEqualNumber(const UNITY_INT expected, } } +/*-----------------------------------------------*/ +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + int failed = 0; + RETURN_IF_FAIL_OR_IGNORE; + + if ((threshold == actual) && (compare & UNITY_EQUAL_TO)) { return; } + if ((threshold == actual)) { failed = 1; } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if ((actual > threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if ((actual < threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + else /* UINT or HEX */ + { + if (((UNITY_UINT)actual > (UNITY_UINT)threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if (((UNITY_UINT)actual < (UNITY_UINT)threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + + if (failed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(actual, style); + if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } + if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } + if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } + if (compare == UNITY_NOT_EQUAL) { UnityPrint(UnityStrNotEqual); } + UnityPrintNumberByStyle(threshold, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + #define UnityPrintPointlessAndBail() \ { \ UnityTestResultsFailBegin(lineNumber); \ @@ -542,8 +779,9 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, const UNITY_DISPLAY_STYLE_T style, const UNITY_FLAGS_T flags) { - UNITY_UINT32 elements = num_elements; - unsigned int length = style & 0xF; + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; RETURN_IF_FAIL_OR_IGNORE; @@ -552,40 +790,55 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UnityPrintPointlessAndBail(); } - if (expected == actual) return; /* Both are NULL or same pointer */ + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { UNITY_FAIL_AND_BAIL; + } - while (elements--) + while ((elements > 0) && (elements--)) { UNITY_INT expect_val; UNITY_INT actual_val; + switch (length) { case 1: expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); break; + case 2: expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); break; + #ifdef UNITY_SUPPORT_64 case 8: expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected; actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual; + increment = sizeof(UNITY_INT64); break; #endif - default: /* length 4 bytes */ + + default: /* default is length 4 bytes */ + case 4: expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); length = 4; break; } if (expect_val != actual_val) { - if (style & UNITY_DISPLAY_RANGE_UINT && length < sizeof(expect_val)) + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ UNITY_INT mask = 1; mask = (mask << 8 * length) - 1; @@ -602,24 +855,25 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } + /* Walk through array by incrementing the pointers */ if (flags == UNITY_ARRAY_TO_ARRAY) { - expected = (UNITY_INTERNAL_PTR)(length + (const char*)expected); + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); } - actual = (UNITY_INTERNAL_PTR)(length + (const char*)actual); + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); } } /*-----------------------------------------------*/ #ifndef UNITY_EXCLUDE_FLOAT /* Wrap this define in a function with variable types as float or double */ -#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ - if (isinf(expected) && isinf(actual) && ((expected < 0) == (actual < 0))) return 1; \ - if (UNITY_NAN_CHECK) return 1; \ - diff = actual - expected; \ - if (diff < 0) diff = -diff; \ - if (delta < 0) delta = -delta; \ - return !(isnan(diff) || isinf(diff) || (diff > delta)) +#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ + if (isinf(expected) && isinf(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \ + if (UNITY_NAN_CHECK) return 1; \ + (diff) = (actual) - (expected); \ + if ((diff) < 0) (diff) = -(diff); \ + if ((delta) < 0) (delta) = -(delta); \ + return !(isnan(diff) || isinf(diff) || ((diff) > (delta))) /* This first part of this condition will catch any NaN or Infinite values */ #ifndef UNITY_NAN_NOT_EQUAL_NAN #define UNITY_NAN_CHECK isnan(expected) && isnan(actual) @@ -639,12 +893,14 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UnityPrint(UnityStrDelta) #endif /* UNITY_EXCLUDE_FLOAT_PRINT */ +/*-----------------------------------------------*/ static int UnityFloatsWithin(UNITY_FLOAT delta, UNITY_FLOAT expected, UNITY_FLOAT actual) { UNITY_FLOAT diff; UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); } +/*-----------------------------------------------*/ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual, const UNITY_UINT32 num_elements, @@ -663,9 +919,15 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, UnityPrintPointlessAndBail(); } - if (expected == actual) return; /* Both are NULL or same pointer */ + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { UNITY_FAIL_AND_BAIL; + } while (elements--) { @@ -750,14 +1012,18 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual, UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrExpected); if (!should_be_trait) + { UnityPrint(UnityStrNot); + } UnityPrint(trait_names[trait_index]); UnityPrint(UnityStrWas); #ifndef UNITY_EXCLUDE_FLOAT_PRINT UnityPrintFloat((UNITY_DOUBLE)actual); #else if (should_be_trait) + { UnityPrint(UnityStrNot); + } UnityPrint(trait_names[trait_index]); #endif UnityAddMsgIfSpecified(msg); @@ -775,6 +1041,7 @@ static int UnityDoublesWithin(UNITY_DOUBLE delta, UNITY_DOUBLE expected, UNITY_D UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); } +/*-----------------------------------------------*/ void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, const UNITY_UINT32 num_elements, @@ -793,9 +1060,15 @@ void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expecte UnityPrintPointlessAndBail(); } - if (expected == actual) return; /* Both are NULL or same pointer */ + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { UNITY_FAIL_AND_BAIL; + } while (elements--) { @@ -835,7 +1108,6 @@ void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, } /*-----------------------------------------------*/ - void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, const char* msg, const UNITY_LINE_TYPE lineNumber, @@ -880,14 +1152,18 @@ void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrExpected); if (!should_be_trait) + { UnityPrint(UnityStrNot); + } UnityPrint(trait_names[trait_index]); UnityPrint(UnityStrWas); #ifndef UNITY_EXCLUDE_FLOAT_PRINT UnityPrintFloat(actual); #else if (should_be_trait) + { UnityPrint(UnityStrNot); + } UnityPrint(trait_names[trait_index]); #endif UnityAddMsgIfSpecified(msg); @@ -910,16 +1186,24 @@ void UnityAssertNumbersWithin(const UNITY_UINT delta, if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) { if (actual > expected) - Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(actual - expected) > delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } else - Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(expected - actual) > delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } } else { if ((UNITY_UINT)actual > (UNITY_UINT)expected) - Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(actual - expected) > delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } else - Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(expected - actual) > delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } } if (Unity.CurrentTestFailed) @@ -936,6 +1220,126 @@ void UnityAssertNumbersWithin(const UNITY_UINT delta, } } +/*-----------------------------------------------*/ +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; + + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while ((elements > 0) && (elements--)) + { + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) + { + case 1: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); + break; + + case 2: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); + break; + +#ifdef UNITY_SUPPORT_64 + case 8: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual; + increment = sizeof(UNITY_INT64); + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); + length = 4; + break; + } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual_val > expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + else + { + if ((UNITY_UINT)actual_val > (UNITY_UINT)expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + + if (Unity.CurrentTestFailed) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((UNITY_INT)delta, style); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expect_val, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + /*-----------------------------------------------*/ void UnityAssertEqualString(const char* expected, const char* actual, @@ -1025,7 +1429,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, { UNITY_UINT32 i = 0; UNITY_UINT32 j = 0; - const char* exp = NULL; + const char* expd = NULL; const char* act = NULL; RETURN_IF_FAIL_OR_IGNORE; @@ -1048,7 +1452,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, if (flags != UNITY_ARRAY_TO_ARRAY) { - exp = (const char*)expected; + expd = (const char*)expected; } do @@ -1056,15 +1460,15 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, act = actual[j]; if (flags == UNITY_ARRAY_TO_ARRAY) { - exp = ((const char* const*)expected)[j]; + expd = ((const char* const*)expected)[j]; } /* if both pointers not null compare the strings */ - if (exp && act) + if (expd && act) { - for (i = 0; exp[i] || act[i]; i++) + for (i = 0; expd[i] || act[i]; i++) { - if (exp[i] != act[i]) + if (expd[i] != act[i]) { Unity.CurrentTestFailed = 1; break; @@ -1073,7 +1477,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, } else { /* handle case of one pointers being null (if both null, test should pass) */ - if (exp != act) + if (expd != act) { Unity.CurrentTestFailed = 1; } @@ -1087,7 +1491,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, UnityPrint(UnityStrElement); UnityPrintNumberUnsigned(j); } - UnityPrintExpectedAndActualStrings(exp, act); + UnityPrintExpectedAndActualStrings(expd, act); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } @@ -1115,9 +1519,15 @@ void UnityAssertEqualMemory(UNITY_INTERNAL_PTR expected, UnityPrintPointlessAndBail(); } - if (expected == actual) return; /* Both are NULL or same pointer */ + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { UNITY_FAIL_AND_BAIL; + } while (elements--) { @@ -1175,25 +1585,27 @@ UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size) switch(size) { case 1: - UnityQuickCompare.i8 = (UNITY_INT8)num; - return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i8); + UnityQuickCompare.i8 = (UNITY_INT8)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i8); case 2: - UnityQuickCompare.i16 = (UNITY_INT16)num; - return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i16); + UnityQuickCompare.i16 = (UNITY_INT16)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i16); #ifdef UNITY_SUPPORT_64 case 8: - UnityQuickCompare.i64 = (UNITY_INT64)num; - return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i64); + UnityQuickCompare.i64 = (UNITY_INT64)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i64); #endif + default: /* 4 bytes */ - UnityQuickCompare.i32 = (UNITY_INT32)num; - return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i32); + UnityQuickCompare.i32 = (UNITY_INT32)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i32); } } #ifndef UNITY_EXCLUDE_FLOAT +/*-----------------------------------------------*/ UNITY_INTERNAL_PTR UnityFloatToPtr(const float num) { UnityQuickCompare.f = num; @@ -1202,6 +1614,7 @@ UNITY_INTERNAL_PTR UnityFloatToPtr(const float num) #endif #ifndef UNITY_EXCLUDE_DOUBLE +/*-----------------------------------------------*/ UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num) { UnityQuickCompare.d = num; @@ -1209,10 +1622,138 @@ UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num) } #endif +/*----------------------------------------------- + * printf helper function + *-----------------------------------------------*/ +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +static void UnityPrintFVA(const char* format, va_list va) +{ + const char* pch = format; + if (pch != NULL) + { + while (*pch) + { + /* format identification character */ + if (*pch == '%') + { + pch++; + + if (pch != NULL) + { + switch (*pch) + { + case 'd': + case 'i': + { + const int number = va_arg(va, int); + UnityPrintNumber((UNITY_INT)number); + break; + } +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + case 'f': + case 'g': + { + const double number = va_arg(va, double); + UnityPrintFloat((UNITY_DOUBLE)number); + break; + } +#endif + case 'u': + { + const unsigned int number = va_arg(va, unsigned int); + UnityPrintNumberUnsigned((UNITY_UINT)number); + break; + } + case 'b': + { + const unsigned int number = va_arg(va, unsigned int); + const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1; + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('b'); + UnityPrintMask(mask, (UNITY_UINT)number); + break; + } + case 'x': + case 'X': + case 'p': + { + const unsigned int number = va_arg(va, unsigned int); + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, 8); + break; + } + case 'c': + { + const int ch = va_arg(va, int); + UnityPrintChar((const char *)&ch); + break; + } + case 's': + { + const char * string = va_arg(va, const char *); + UnityPrint(string); + break; + } + case '%': + { + UnityPrintChar(pch); + break; + } + default: + { + /* print the unknown format character */ + UNITY_OUTPUT_CHAR('%'); + UnityPrintChar(pch); + break; + } + } + } + } +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + else if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + else if (*pch == '\n') + { + UNITY_PRINT_EOL(); + } + else + { + UnityPrintChar(pch); + } + + pch++; + } + } +} + +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if(format != NULL) + { + UnityPrint(": "); + va_list va; + va_start(va, format); + UnityPrintFVA(format, va); + va_end(va); + } + UNITY_PRINT_EOL(); +} +#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */ + + /*----------------------------------------------- * Control Functions *-----------------------------------------------*/ +/*-----------------------------------------------*/ void UnityFail(const char* msg, const UNITY_LINE_TYPE line) { RETURN_IF_FAIL_OR_IGNORE; @@ -1223,6 +1764,9 @@ void UnityFail(const char* msg, const UNITY_LINE_TYPE line) { UNITY_OUTPUT_CHAR(':'); +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif #ifndef UNITY_EXCLUDE_DETAILS if (Unity.CurrentDetail1) { @@ -1263,23 +1807,29 @@ void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) } /*-----------------------------------------------*/ -#if defined(UNITY_WEAK_ATTRIBUTE) - UNITY_WEAK_ATTRIBUTE void setUp(void) { } - UNITY_WEAK_ATTRIBUTE void tearDown(void) { } -#elif defined(UNITY_WEAK_PRAGMA) - #pragma weak setUp - void setUp(void) { } - #pragma weak tearDown - void tearDown(void) { } -#endif +void UnityMessage(const char* msg, const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_PRINT_EOL(); +} /*-----------------------------------------------*/ +/* If we have not defined our own test runner, then include our default test runner to make life easier */ +#ifndef UNITY_SKIP_DEFAULT_RUNNER void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) { Unity.CurrentTestName = FuncName; Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; Unity.NumberOfTests++; UNITY_CLR_DETAILS(); + UNITY_EXEC_TIME_START(); if (TEST_PROTECT()) { setUp(); @@ -1289,8 +1839,16 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int { tearDown(); } + UNITY_EXEC_TIME_STOP(); UnityConcludeTest(); } +#endif + +/*-----------------------------------------------*/ +void UnitySetTestFile(const char* filename) +{ + Unity.TestFile = filename; +} /*-----------------------------------------------*/ void UnityBegin(const char* filename) @@ -1347,12 +1905,14 @@ char* UnityOptionIncludeNamed = NULL; char* UnityOptionExcludeNamed = NULL; int UnityVerbosity = 1; +/*-----------------------------------------------*/ int UnityParseOptions(int argc, char** argv) { + int i; UnityOptionIncludeNamed = NULL; UnityOptionExcludeNamed = NULL; - for (int i = 1; i < argc; i++) + for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { @@ -1363,9 +1923,13 @@ int UnityParseOptions(int argc, char** argv) case 'n': /* include tests with name including this string */ case 'f': /* an alias for -n */ if (argv[i][2] == '=') + { UnityOptionIncludeNamed = &argv[i][3]; + } else if (++i < argc) + { UnityOptionIncludeNamed = argv[i]; + } else { UnityPrint("ERROR: No Test String to Include Matches For"); @@ -1381,9 +1945,13 @@ int UnityParseOptions(int argc, char** argv) break; case 'x': /* exclude tests with name including this string */ if (argv[i][2] == '=') + { UnityOptionExcludeNamed = &argv[i][3]; + } else if (++i < argc) + { UnityOptionExcludeNamed = argv[i]; + } else { UnityPrint("ERROR: No Test String to Exclude Matches For"); @@ -1403,6 +1971,7 @@ int UnityParseOptions(int argc, char** argv) return 0; } +/*-----------------------------------------------*/ int IsStringInBiggerString(const char* longstring, const char* shortstring) { const char* lptr = longstring; @@ -1410,7 +1979,9 @@ int IsStringInBiggerString(const char* longstring, const char* shortstring) const char* lnext = lptr; if (*sptr == '*') + { return 1; + } while (*lptr) { @@ -1441,9 +2012,11 @@ int IsStringInBiggerString(const char* longstring, const char* shortstring) lptr = lnext; sptr = shortstring; } + return 0; } +/*-----------------------------------------------*/ int UnityStringArgumentMatches(const char* str) { int retval; @@ -1456,7 +2029,9 @@ int UnityStringArgumentMatches(const char* str) while (ptr1[0] != 0) { if ((ptr1[0] == '"') || (ptr1[0] == '\'')) + { ptr1++; + } /* look for the start of the next partial */ ptr2 = ptr1; @@ -1465,26 +2040,37 @@ int UnityStringArgumentMatches(const char* str) { ptr2++; if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')) + { ptrf = &ptr2[1]; + } } while ((ptr2[0] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')); + while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\'') || (ptr2[0] == '"') || (ptr2[0] == ','))) + { ptr2++; + } /* done if complete filename match */ retval = IsStringInBiggerString(Unity.TestFile, ptr1); if (retval == 1) + { return retval; + } /* done if testname match after filename partial match */ if ((retval == 2) && (ptrf != 0)) { if (IsStringInBiggerString(Unity.CurrentTestName, ptrf)) + { return 1; + } } /* done if complete testname match */ if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1) + { return 1; + } ptr1 = ptr2; } @@ -1493,6 +2079,7 @@ int UnityStringArgumentMatches(const char* str) return 0; } +/*-----------------------------------------------*/ int UnityTestMatches(void) { /* Check if this test name matches the included test pattern */ @@ -1502,14 +2089,19 @@ int UnityTestMatches(void) retval = UnityStringArgumentMatches(UnityOptionIncludeNamed); } else + { retval = 1; + } /* Check if this test name matches the excluded test pattern */ if (UnityOptionExcludeNamed) { if (UnityStringArgumentMatches(UnityOptionExcludeNamed)) + { retval = 0; + } } + return retval; } diff --git a/src/lib/unity/unit.mk b/src/lib/unity/unit.mk index 22ae9910..9e541de5 100644 --- a/src/lib/unity/unit.mk +++ b/src/lib/unity/unit.mk @@ -11,6 +11,8 @@ UNIT_SRC := src/unity.c UNIT_CFLAGS := -I$(UNIT_PATH)/inc UNIT_CFLAGS += -fasynchronous-unwind-tables +UNIT_CFLAGS += -D UNITY_INCLUDE_EXEC_TIME +UNIT_CFLAGS += -D UNITY_INCLUDE_PRINT_FORMATTED UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS) UNIT_EXPORT_LDFLAGS := -lm diff --git a/src/lib/wc_null_plugin/tests/fut/create_wc_null_plugin.sh b/src/lib/wc_null_plugin/tests/fut/create_wc_null_plugin.sh index b920bbf5..e91be130 100755 --- a/src/lib/wc_null_plugin/tests/fut/create_wc_null_plugin.sh +++ b/src/lib/wc_null_plugin/tests/fut/create_wc_null_plugin.sh @@ -74,30 +74,6 @@ gen_fsmc_wc_null_cmd() { EOF } -# Create a dev wc_null policy entry -gen_dev_wc_null_policy() { - cat <mon_type == OVSDB_UPDATE_MODIFY) + if (mon->mon_type == OVSDB_UPDATE_MODIFY || + mon->mon_type == OVSDB_UPDATE_NEW) { // Update new upload location and token STRSCPY(g_state.config.upload_token, config->upload_token); diff --git a/src/nfm/src/nfm_trule.c b/src/nfm/src/nfm_trule.c index 2adc10db..8e4a3c29 100644 --- a/src/nfm/src/nfm_trule.c +++ b/src/nfm/src/nfm_trule.c @@ -130,6 +130,9 @@ static bool nfm_trule_detect_vars(struct nfm_trule *self, char *what, char var_c } else if (*s == TEMPLATE_CLOUD_CHAR) { s++; flag |= OM_TLE_FLAG_CLOUD; + } else if (*s == TEMPLATE_LOCAL_CHAR) { + s++; + flag |= OM_TLE_FLAG_LOCAL; } if (!(p = strchr(s, end))) { LOGW("[%s] Netfilter template rule has malformed %s (no ending '%c')", @@ -139,8 +142,7 @@ static bool nfm_trule_detect_vars(struct nfm_trule *self, char *what, char var_c *p++ = '\0'; LOGT("[%s] Netfilter template rule detected %s %s'%s'", - self->conf.name, what, (flag == OM_TLE_FLAG_DEVICE) ? "device " : - (flag == OM_TLE_FLAG_CLOUD) ? "cloud " : "", s); + self->conf.name, what, om_tag_get_tle_flag(flag), s); if (!om_tag_list_entry_find_by_val_flags(&self->tags, s, base_flags)) { if (!om_tag_list_entry_add(&self->tags, s, flag)) { errcode = false; @@ -241,7 +243,7 @@ static char *nfm_trule_expand(struct nfm_trule *self, struct nfm_tdata *tdata) strcat(erule, p); s += 2; - if (*s == TEMPLATE_DEVICE_CHAR || *s == TEMPLATE_CLOUD_CHAR) { + if (*s == TEMPLATE_DEVICE_CHAR || *s == TEMPLATE_CLOUD_CHAR || *s == TEMPLATE_LOCAL_CHAR) { s++; } if (!(e = strchr(s, end))) { diff --git a/src/nm2/fut/nm2_configure_nonexistent_iface.sh b/src/nm2/fut/nm2_configure_nonexistent_iface.sh new file mode 100755 index 00000000..7669cfda --- /dev/null +++ b/src/nm2/fut/nm2_configure_nonexistent_iface.sh @@ -0,0 +1,137 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +# TEST DEFINITION DESCRIPTION +# Try to configure non existing interface. +# Non existing interface should not be created/configured. +# Also NM should not crash if non existing interface tries to be created/configured. +# +# TEST PROCEDURE +# Test inserts interface to Wifi_Inet_Config by calling insert_ovsdb_entry. +# It checks Wifi_Inet_State table for interface with wait_ovsdb_entry. +# Checks if interface is created in system. +# Checks if NM is running. +# If it cannot find NM PID, it crashed. Test fails. +# +# EXPECTED RESULTS +# Test is passed: +# - if interface is not created +# - NM survived, did not crash +# Test fails: +# - if nonexisting interface was created but it shouldn't be +# - NM crashed (PID is no longer available) + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/nm2_lib.sh +source ${LIB_OVERRIDE_FILE} + +# Execute on EXIT signal. +trap 'run_setup_if_crashed nm || true' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - (string)(required) + inet_addr=\$3 -- used as inet_addr in Wifi_Inet_Config table - (string)(required) + +this script is dependent on following: + - running NM manager + +example of usage: + /tmp/fut-base/shell/ob/$(basename "$0") test1 eth 10.10.10.15 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide at least 3 argument(s). +if [ $# -lt 3 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +# Fill variables with provided arguments or defaults. +if_name=$1 +if_type=$2 +ip_address=$3 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating NONEXISTENT interface $if_name of type $if_type" + +insert_ovsdb_entry Wifi_Inet_Config \ + -i if_name "$if_name" \ + -i if_type "$if_type" \ + -i enabled true \ + -i network true \ + -i NAT false \ + -i inet_addr "$ip_address" \ + -i netmask "255.255.255.0" \ + -i broadcast "10.10.10.255" \ + -i ip_assign_scheme static \ + -i parent_ifname eth1 \ + -i mtu 1500 && + log "$tc_name: Creating NONEXISTENT interface - Failed to insert_ovsdb_entry" || + raise "Failed to insert_ovsdb_entry" -l "$tc_name" -oe + +log "$tc_name: Checking if NONEXISTENT interface $if_name was CREATED" +# Interface must be present in Wifi_Inet_State table... +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is if_type "$if_type" && + log "$tc_name: NONEXISTENT interface present in Wifi_Inet_State table - if_name $if_name" || + raise "Wifi_Inet_State - {if_name:=$if_name}" -l "$tc_name" -ow + +# ...but not in system. +wait_for_function_response 1 "check_interface_exists $if_name" && + log "$tc_name: SUCCESS: Interface $if_name of type $if_type does NOT exist on system" || + raise "FAIL: Interface $if_name of type $if_type exists on system, but should NOT" -l "$tc_name" -tc + +# Check if manager survived. +manager_pid_file="${OPENSYNC_ROOTDIR}/bin/nm" +wait_for_function_response 0 "check_manager_alive $manager_pid_file" && + log "$tc_name: SUCCESS: NETWORK MANAGER is running" || + raise "FAILED: NETWORK MANAGER not running/crashed" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_enable_disable_iface_network.sh b/src/nm2/fut/nm2_enable_disable_iface_network.sh new file mode 100755 index 00000000..e1643b8a --- /dev/null +++ b/src/nm2/fut/nm2_enable_disable_iface_network.sh @@ -0,0 +1,146 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# TEST DESCRIPTION +# Try to enable and disable existing interface. +# +# TEST PROCEDURE +# - Configure interface with selected parameters +# - interface IP address is 10.10.10.30, used to check test fail/pass criteria +# +# EXPECTED RESULTS +# Test is passed: +# - if interface is properly configured AND +# - if interface is disabled and if its table is empty (interface_ip_address is checked) AND +# - if interface is re-enabled and if its table is populated (interface_ip_address is checked) +# Test fails: +# - if inteface cannot be disabled OR +# - if disabled interface table is not empty (interface_ip_address is checked) + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +# Fill variables with provided arguments or defaults. +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vif'- (string)(optional) + +this script is dependent on following: + - running NM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_enable_disable_iface_network.sh eth0 eth +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide at least 1 argument(s). +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +if_type=$2 +inet_addr=10.10.10.30 + +tc_name="nm2/$(basename "$0")" + + +log "$tc_name: Creating Wifi_Inet_Config entries for: $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -if_type "$if_type" \ + -ip_assign_scheme static \ + -netmask "255.255.255.0" \ + -inet_addr "$inet_addr" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS $inet_addr was properly applied to $if_name" +wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Setting applied to ifconfig - IP: $inet_addr" || + raise "Failed to apply settings to ifconfig - IP: $inet_addr" -l "$tc_name" -tc + +log "$tc_name: Disabling network, Wifi_Inet_Config network=false" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u network false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - network=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - network=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is network false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - network=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - network=false" -l "$tc_name" -tc + +log "$tc_name: Checking if all network settings on interface are empty" +wait_for_function_response 1 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Setting removed from ifconfig" || + raise "Failed to remove settings to ifconfig" -l "$tc_name" -tc + +log "$tc_name: Re-enabling network, Wifi_Inet_Config network=true" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u network true && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - network=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - network=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is network true && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - network=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - network=false" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS $inet_addr was properly applied to $if_name" +wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Setting applied to ifconfig - IP: $inet_addr" || + raise "Failed to apply settings to ifconfig - IP: $inet_addr" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_ovsdb_configure_interface_dhcpd.sh b/src/nm2/fut/nm2_ovsdb_configure_interface_dhcpd.sh new file mode 100755 index 00000000..9a122ac5 --- /dev/null +++ b/src/nm2/fut/nm2_ovsdb_configure_interface_dhcpd.sh @@ -0,0 +1,175 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + [ "$if_type" == "vif" ] && vif_clean + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +tc_name="nm2/$(basename "$0")" +usage() +{ +cat << EOF +${tc_name} [-h] if_name [if_type] [start_pool] [end_pool] +Options: + -h show this help message +Arguments: + if_name=$1 -- field if_name in Wifi_Inet_Config table - (string)(required) + if_type=$2 -- field if_type in Wifi_Inet_Config table - (string)(optional, default: vif) + start_pool=$3 -- value start_pool in field dhcpd in Wifi_Inet_Config - (string)(optional, default: 10.10.10.20) + end_pool=$4 -- value end_pool in field dhcpd in Wifi_Inet_Config - (string)(optional, default: 10.10.10.50) +Dependencies: + NM manager, WM manager +Example: + ${tc_name} wifi0 vif 10.10.10.16 10.10.10.32 +EOF +exit 1 +} + +while getopts h option; do + case "$option" in + h) + usage + ;; + esac +done + +NARGS=1 +[ $# -lt ${NARGS} ] && raise "Requires at least '${NARGS}' input argument(s)" -l "${tc_name}" -arg +if_name=$1 +if_type=${2:-"vif"} +start_pool=${3:-"10.10.10.20"} +end_pool=${4:-"10.10.10.50"} + +log_title "${tc_name}: Testing table Wifi_Inet_Config field dhcpd" + +log "${tc_name}: Creating Wifi_Inet_Config entries for $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -if_type "$if_type" \ + -inet_addr 10.10.10.10 \ + -netmask 255.255.255.0 \ + -dns "[\"map\",[]]" \ + -gateway 10.10.10.254 && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Check if interface is UP - $if_name" +wait_for_function_response 0 "interface_is_up $if_name " && + log "$tc_name: Interface is UP - $if_name" || + raise "FAILED: Interface is DOWN, should be UP - $if_name" -l "$tc_name" -tc + +log "$tc_name: Setting DHCP range on $if_name" +enable_disable_dhcp_server "$if_name" "$start_pool" "$end_pool" || + raise "Cannot update DHCP settings inside CONFIG $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking if settings were applied to the DHCP server #1" +wait_for_function_response 0 "wait_for_dnsmasq $if_name $start_pool $end_pool" && + log "$tc_name: DNSMASQ DHCP configuration VALID (present) - $if_name" || + raise "DNSMASQ DHCP configuration NOT VALID (not present) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Checking if DHCP server configuration is removed when the interface is DOWN - $if_name" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u enabled false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - $if_name" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - $if_name" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is enabled false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - $if_name" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking DHCP configuration" +wait_for_function_response 1 "wait_for_dnsmasq $if_name $start_pool $end_pool" && + log "$tc_name: DNSMASQ DHCP configuration VALID (not present) - $if_name" || + raise "DNSMASQ DHCP configuration NOT VALID (still present) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Checking if DHCP server configuration is re-applied when the interface is UP - $if_name" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u enabled true && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - $if_name" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - $if_name" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is enabled true && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - $if_name" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking DHCP configuration" +wait_for_function_response 0 "wait_for_dnsmasq $if_name $start_pool $end_pool" && + log "$tc_name: DNSMASQ DHCP configuration VALID (present) - $if_name" || + raise "DNSMASQ DHCP configuration NOT VALID (not present) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Switching interface to DHCP client" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u "ip_assign_scheme" "dhcp" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - $if_name" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - $if_name" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is "ip_assign_scheme" "dhcp" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - $if_name" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking if DHCP client is alive - $if_name" +wait_for_function_response 0 "check_pid_file alive \"/var/run/udhcpc-$if_name.pid\"" && + log "$tc_name: DHCP client process ACTIVE - $if_name" || + raise "DHCP client process NOT ACTIVE - $if_name" -l "$tc_name" -tc + +log "$tc_name: Disabling DHCP client - $if_name" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" \ + -u "dhcpd" "[\"map\",[]]" \ + -u "ip_assign_scheme" "static" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - $if_name" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - $if_name" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" \ + -is "dhcpd" "[\"map\",[]]" \ + -is "ip_assign_scheme" "static" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - $if_name" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking if settings were removed from the DHCP server - $if_name" +wait_for_function_response 1 "wait_for_dnsmasq $if_name $start_pool $end_pool" && + log "$tc_name: DNSMASQ DHCP configuration VALID (not present) #2 - $if_name" || + raise "DNSMASQ DHCP configuration NOT VALID (still present) #2 - $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if DHCP client is dead - $if_name" +wait_for_function_response 0 "check_pid_file dead \"/var/run/udhcpc-$if_name.pid\"" && + log "$tc_name: DHCP client process NOT ACTIVE - $if_name" || + raise "DHCP client process ACTIVE - $if_name" -l "$tc_name" -tc + +pass + diff --git a/src/nm2/fut/nm2_ovsdb_ip_port_forward.sh b/src/nm2/fut/nm2_ovsdb_ip_port_forward.sh new file mode 100755 index 00000000..edb2bb8b --- /dev/null +++ b/src/nm2/fut/nm2_ovsdb_ip_port_forward.sh @@ -0,0 +1,126 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# TEST DESCRIPTION +# Redirect source interface, port 8080 (Web Services) to destination IP, port 80 (Web Services), protocol TCP. +# +# TEST PROCEDURE +# Set port forwarding. +# Delete port forwarding. +# +# EXPECTED RESULTS +# Test is passed: +# - if port forwarding can be configured +# - if port forwarding can be deleted +# +# Test is failed: +# - otherwise + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 \$5 + +where options are: + -h show this help message + +where arguments are: + src_ifname=\$1 -- used as src_ifname in IP_Port_Forward table - (string)(required) + src_port=\$2 -- used as src_port in IP_Port_Forward table - (string)(required) + dst_ipaddr=\$3 -- used as dst_ipaddr in IP_Port_Forward table - (string)(required) + dst_port=\$4 -- used as dst_port in IP_Port_Forward table - (string)(required) + protocol=\$5 -- used as protocol in IP_Port_Forward table - (string)(required) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_ovsdb_ip_port_forward.sh wifi0 8080 10.10.10.200 80 tcp +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide all 5 arguments. +if [ $# -lt 5 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +trap 'run_setup_if_crashed nm || true' EXIT SIGINT SIGTERM + +# No default values. +src_ifname=$1 +src_port=$2 +dst_ipaddr=$3 +dst_port=$4 +protocol=$5 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Set IP FORWARD in OVSDB" +set_ip_forward "$src_ifname" "$src_port" "$dst_ipaddr" "$dst_port" "$protocol" && + log "$tc_name: Failed to set ip port forward - $src_ifname" || + raise "Failed to set ip port forward - $src_ifname" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check for IP FORWARD record in iptables" + +wait_for_function_response 0 "ip_port_forward $dst_ipaddr:$dst_port" && + log "$tc_name: LEVEL2: Ip port forward propagated to iptables" || + raise "LEVEL2: Failed to propagate record into iptables" -l "$tc_name" -tc + +log "$tc_name: Delete IP FORWARD from OVSDB" +${OVSH} d IP_Port_Forward -w dst_ipaddr=="$dst_ipaddr" -w src_ifname=="$src_ifname" && + log "$tc_name: Success to delete IP Port forward - $src_ifname" || + raise "Failed to delete IP Port forward - $src_ifname" -l "$tc_name" -tc + +wait_ovsdb_entry_remove IP_Port_Forward -w dst_ipaddr "$dst_ipaddr" -w src_ifname "$src_ifname" && + log "$tc_name: Success to remove entry - $src_ifname" || + raise "Failed to remove entry - $src_ifname" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check is IP FORWARD record deleted from iptables" +wait_for_function_response 1 "ip_port_forward $dst_ipaddr:$dst_port" && + log "$tc_name: LEVEL2: Ip port forward deleted from iptables" || + force_delete_ip_port_forward_die "$src_ifname" "NM_PORT_FORWARD" "$dst_ipaddr:$dst_port" + +pass diff --git a/src/nm2/fut/nm2_ovsdb_remove_reinsert_iface.sh b/src/nm2/fut/nm2_ovsdb_remove_reinsert_iface.sh new file mode 100755 index 00000000..596d5aeb --- /dev/null +++ b/src/nm2/fut/nm2_ovsdb_remove_reinsert_iface.sh @@ -0,0 +1,154 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vlan'- (string)(optional) + +this script is dependent on following: + - running NM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_ovsdb_remove_reinsert_iface.sh eth0.100 vlan +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +if_type=$2 +inet_addr=${3:-10.10.10.30} + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating $if_type interface" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -if_type "$if_type" \ + -netmask "255.255.255.0" \ + -inet_addr "$inet_addr" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $inet_addr was properly applied to $if_name (ENABLED #1)" +wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Settings applied to ifconfig (ENABLED #1) - $if_name" || + raise "Failed to apply settings to ifconfig (ENABLED #1) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Setting ENABLED to false" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u enabled false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - enabled=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - enabled=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is enabled false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - enabled=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - enabled=false" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $inet_addr was properly removed from $if_name (DISABLED #1)" +wait_for_function_response 1 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Settings removed from ifconfig (DISABLE #1) - $if_name" || + raise "Failed to remove settings from ifconfig (DISABLE #1) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Setting ENABLED to true" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u enabled true && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - enabled=true" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - enabled=true" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is enabled true && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - enabled=true" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - enabled=true" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $inet_addr was properly applied to $if_name (ENABLED #1)" +wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Settings applied to ifconfig (ENABLED #2) - $if_name" || + raise "Failed to apply settings to ifconfig (ENABLED #2) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Setting ENABLED to false" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u enabled false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - enabled=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - enabled=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is enabled false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - enabled=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - enabled=false" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $inet_addr was properly removed from $if_name (DISABLED #1)" +wait_for_function_response 1 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Settings removed from ifconfig (DISABLE #2) - $if_name" || + raise "Failed to remove settings from ifconfig (DISABLE #2) - $if_name" -l "$tc_name" -tc + +log "$tc_name: Setting ENABLED to true" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u enabled true && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - enabled=true" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - enabled=true" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is enabled true && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - enabled=true" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - enabled=true" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS was properly applied to $if_name (ENABLED #1)" +wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Settings applied to ifconfig (ENABLED #3) - enabled=true" || + raise "Failed to apply settings to ifconfig (ENABLED #3) - enabled=true" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_rapid_multiple_insert_delete_iface.sh b/src/nm2/fut/nm2_rapid_multiple_insert_delete_iface.sh new file mode 100755 index 00000000..09be9532 --- /dev/null +++ b/src/nm2/fut/nm2_rapid_multiple_insert_delete_iface.sh @@ -0,0 +1,112 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + delete_inet_interface "$vif_name" + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + vlan_no=\$2 -- used as vlan identifier - example, vlan_no 100 will result in vif_name eth0.100 - (int)(required) + if_type=\$3 -- used as if_type in Wifi_Inet_Config table - default 'vlan'- (string)(optional) + +this script is dependent on following: + - running NM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_rapid_multiple_insert_delete_iface.sh eth0 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +vlan_id=$2 +if_type=${3:-vlan} +vif_name="$if_name.$vlan_id" +ip_address="10.10.10.$vlan_id" + +tc_name="nm2/$(basename "$0")" + +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -netmask "255.255.255.0" \ + -inet_addr "10.10.10.$vlan_id" \ + -if_type "$if_type" \ + -dns "[\"map\",[]]" \ + -vlan_id "$vlan_id" && + log "$tc_name: create_vlan_inet_entry - Success" || + raise "create_vlan_inet_entry - Failed" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $ip_address was properly applied to $vif_name" + +wait_for_function_response 0 "interface_ip_address $vif_name | grep \"$ip_address\"" && + log "$tc_name: Ip address $ip_address applied to ifconfig for interface $vif_name" || + raise "Failed to apply settings to ifconfig (ENABLED) - vif_if_name $vif_name" -l "$tc_name" -tc + +delete_inet_interface "$vif_name" && + log "$tc_name: Interface $vif_name deleted" || + raise "Fail to delete created interface $vif_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $ip_address was properly removed from ifconfig $vif_name" +wait_for_function_response 1 "interface_ip_address $if_name | grep -q \"$ip_address\"" && + log "$tc_name: Settings removed from ifconfig (DISABLE #2) - interface $if_name" || + raise "Failed to remove settings from ifconfig (DISABLE #2) - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_rapid_multiple_insert_delete_ovsdb_row.sh b/src/nm2/fut/nm2_rapid_multiple_insert_delete_ovsdb_row.sh new file mode 100755 index 00000000..b43252a0 --- /dev/null +++ b/src/nm2/fut/nm2_rapid_multiple_insert_delete_ovsdb_row.sh @@ -0,0 +1,117 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + delete_inet_interface $vif_name + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + vlan_no=\$2 -- used as vlan identifier - example, vlan_no 100 will result in vif_name eth0.100 - (int)(required) + if_type=\$3 -- used as if_type in Wifi_Inet_Config table - default 'vlan'- (string)(optional) + +this script is dependent on following: + - running NM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_rapid_multiple_insert_delete_iface.sh eth0 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +vlan_id=$2 +if_type=${3:-vlan} +vif_name="$if_name.$vlan_id" +v_ip_address="10.10.10.$vlan_id" + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating interface $vif_name" +create_inet_entry \ + -if_name "$vif_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -inet_addr "$v_ip_address" \ + -netmask "255.255.255.0" \ + -if_type "$if_type" \ + -vlan_id "$vlan_id" \ + -parent_ifname "$if_name" && + log "$tc_name: create_vlan_inet_entry - Success" || + raise "create_vlan_inet_entry - Failed" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $v_ip_address was properly applied to $vif_name" +wait_for_function_response 0 "interface_ip_address $vif_name | grep -q \"$v_ip_address\"" && + log "$tc_name: LEVEL2: Ip address applied to $vif_name" || + raise "Failed to apply settings to ifconfig (ENABLED) - interface $vif_name" -l "$tc_name" -tc + +log "$tc_name: Setting ENABLED to false - interface $vif_name" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$vif_name" -u enabled false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - enabled=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - enabled=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$vif_name" -is enabled false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - enabled=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - enabled=false" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if IP ADDRESS: $v_ip_address was properly removed from ifconfig $vif_name" +wait_for_function_response 1 "interface_ip_address $if_name | grep -q \"$v_ip_address\"" && + log "$tc_name: Settings removed from ifconfig (DISABLE #2) - interface $if_name" || + raise "Failed to remove settings from ifconfig (DISABLE #2) - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_broadcast.sh b/src/nm2/fut/nm2_set_broadcast.sh new file mode 100755 index 00000000..46a69683 --- /dev/null +++ b/src/nm2/fut/nm2_set_broadcast.sh @@ -0,0 +1,127 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vif'- (string)(optional) + broadcast=\$3 -- used as broadcast in Wifi_Inet_Config table - default '10.10.10.255' - (string)(optional) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_broadcast.sh wifi0 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +if_type=$2 +broadcast=$3 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -inet_addr 10.10.10.30 \ + -netmask "255.255.255.0" \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting BROADCAST for $if_name to $broadcast" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u broadcast "$broadcast" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - broadcast $broadcast" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - broadcast $broadcast" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is broadcast "$broadcast" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - broadcast $broadcast" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - broadcast $broadcast" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if BROADCAST was properly applied to $if_name" +wait_for_function_response 0 "interface_broadcast $if_name | grep -q \"$broadcast\"" && + log "$tc_name: LEVEL2: BROADCAST applied to ifconfig - broadcast $broadcast" || + raise "LEVEL2: Failed to apply BROADCAST to ifconfig - broadcast $broadcast" -l "$tc_name" -tc + +log "$tc_name: Removing broadcast from Wifi_Inet_Config" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" \ + -u broadcast 0.0.0.0 \ + -u ip_assign_scheme none && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - broadcast 0.0.0.0" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - broadcast 0.0.0.0" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" \ + -is broadcast 0.0.0.0 \ + -is ip_assign_scheme none && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - broadcast 0.0.0.0" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - broadcast 0.0.0.0" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if BROADCAST was properly removed from $if_name" +wait_for_function_response 1 "interface_broadcast $if_name | grep -q \"$broadcast\"" && + log "$tc_name: LEVEL2: BROADCAST removed from ifconfig - interface $if_name" || + raise "LEVEL2: Failed to remove BROADCAST to ifconfig - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_dns.sh b/src/nm2/fut/nm2_set_dns.sh new file mode 100755 index 00000000..a81febac --- /dev/null +++ b/src/nm2/fut/nm2_set_dns.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +tc_name="nm2/$(basename "$0")" +usage() +{ +cat << EOF +${tc_name} [-h] if_name if_type primary_dns secondary_dns +Options: + -h show this help message +Arguments: + if_name=$1 -- field if_name in Wifi_Inet_Config table - (string)(required) + if_type=$2 -- field if_type in Wifi_Inet_Config table - (string)(required) + primary_dns=$2 -- primary entry for field dns in Wifi_Inet_Config table - (string)(required) + secondary_dns=$3 -- secondary entry for field dns in Wifi_Inet_Config table - (string)(required) +Dependencies: + NM manager, WM manager +Example: + ${tc_name} wifi0 vif 8.8.4.4 1.1.1.1 +EOF +exit 1 +} + +while getopts h option; do + case "$option" in + h) + usage + ;; + esac +done + +NARGS=4 +[ $# -ne ${NARGS} ] && raise "Requires exactly '${NARGS}' input argument(s)" -l "${tc_name}" -arg +if_name=$1 +if_type=$2 +primary_dns=$3 +secondary_dns=$4 + +log_title "${tc_name}: Testing table Wifi_Inet_Config field dns" + +log "${tc_name}: Creating Wifi_Inet_Config entries for $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -inet_addr 10.10.10.30 \ + -netmask "255.255.255.0" \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting DNS for $if_name to $primary_dns, $secondary_dns" +enable_disable_custom_dns "$if_name" "$primary_dns" "$secondary_dns" || + raise "Failed to set custom DNS - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if Primary DNS was properly applied to $if_name" +wait_for_function_response 0 "check_resolv_conf $primary_dns" && + log "$tc_name: LEVEL2: Primary dns set on /etc/resolv.conf - interface $if_name" || + raise "Primary DNS configuration NOT VALID - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if Secondary DNS was properly applied to $if_name" +wait_for_function_response 0 "check_resolv_conf $secondary_dns" && + log "$tc_name: LEVEL2: Secondary dns set on /etc/resolv.conf - interface $if_name" || + raise "Secondary DNS configuration NOT VALID - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_gateway.sh b/src/nm2/fut/nm2_set_gateway.sh new file mode 100755 index 00000000..b17c95e6 --- /dev/null +++ b/src/nm2/fut/nm2_set_gateway.sh @@ -0,0 +1,131 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +tc_name="nm2/$(basename "$0")" +usage() +{ +cat << EOF +${tc_name} [-h] if_name [if_type] [gateway] +Options: + -h show this help message +Arguments: + if_name=$1 -- if_name field in Wifi_Inet_Config - (string)(required) + if_type=$2 -- if_type field in Wifi_Inet_Config - (string)(optional, default: vif) + gateway=$3 -- gateway field in Wifi_Inet_Config - (string)(optional, default: 10.10.10.200) +Dependencies: + NM manager, WM manager +Example: + ${tc_name} eth0 eth 10.10.10.50 + ${tc_name} wifi0 vif +EOF +exit 1 +} + +while getopts h option; do + case "$option" in + h) + usage + ;; + esac +done + +NARGS=1 +[ $# -lt ${NARGS} ] && raise "Requires at least '${NARGS}' input argument(s)" -l "${tc_name}" -arg +if_name=$1 +if_type=${2:-"vif"} +gateway=${3:-"10.10.10.200"} + +log_title "${tc_name}: Testing table Wifi_Inet_Config field gateway" + +log "${tc_name}: Creating Wifi_Inet_Config entries for $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -inet_addr 10.10.10.30 \ + -netmask "255.255.255.0" \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting GATEWAY for $if_name to $gateway" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u gateway "$gateway" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - gateway $gateway" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - gateway $gateway" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is gateway "$gateway" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - gateway $gateway" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - gateway $gateway" -l "$tc_name" -tc + +gateway_check_cmd="ip route show default | grep -q $gateway' .* '$if_name" +log "$tc_name: LEVEL 2: Checking ifconfig for applied gateway - interface $if_name" +wait_for_function_response 0 "$gateway_check_cmd" && + log "$tc_name: LEVEL 2: Gateway $gateway applied to OS - interface $if_name" || + raise "LEVEL 2: Failed to apply gateway $gateway to OS - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: Removing GATEWAY $gateway for $if_name" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u gateway "[\"set\",[]]" -u ip_assign_scheme none && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - gateway [\"set\",[]]" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - gateway [\"set\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is ip_assign_scheme none && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme none" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme none" -l "$tc_name" -tc + +# gateway field can either be empty or "0.0.0.0" +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is gateway "0.0.0.0" +if [ $? -eq 0 ]; then + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - gateway 0.0.0.0" +else + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_State::gateway is not 0.0.0.0" + wait_for_function_response 'empty' "get_ovsdb_entry_value Wifi_Inet_State gateway -w if_name $if_name" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - gateway empty" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - gateway empty" -l "$tc_name" -tc +fi + +log "$tc_name: LEVEL 2: Checking ifconfig for removed gateway" +wait_for_function_response 1 "$gateway_check_cmd" && + log "$tc_name: LEVEL 2: Gateway $gateway removed from OS - interface $if_name" || + raise "LEVEL 2: Failed to remove gateway $gateway from OS - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_inet_addr.sh b/src/nm2/fut/nm2_set_inet_addr.sh new file mode 100755 index 00000000..107f5bc6 --- /dev/null +++ b/src/nm2/fut/nm2_set_inet_addr.sh @@ -0,0 +1,123 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vi' - (string)(optional) + inet_addr=\$3 -- used as inet_addr in Wifi_Inet_Config table - default '10.10.10.20' - (integer)(optional) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_inet_addr.sh eth0 eth 10.10.10.15 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +if_type=$2 +inet_addr=$3 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name (enabled=true, network=true, ip_assign_scheme=static)" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -netmask "255.255.255.0" \ + -ip_assign_scheme static \ + -if_type "$if_type" \ + -inet_addr "$inet_addr" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting INET_ADDR to $inet_addr" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u inet_addr "$inet_addr" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - inet_addr $inet_addr" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - inet_addr $inet_addr" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is inet_addr "$inet_addr" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - inet_addr $inet_addr" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - inet_addr $inet_addr" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking if INET_ADDR was properly applied to $if_name" +wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: INET_ADDR applied to ifconfig - interface $if_name" || + raise "Failed to apply INET_ADDR to ifconfig - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: Removing INET_ADDR to $inet_addr" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u inet_addr "[\"set\",[]]" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - inet_addr [\"set\",[]]" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - inet_addr [\"set\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is inet_addr "0.0.0.0" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - inet_addr 0.0.0.0" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - inet_addr 0.0.0.0" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking if INET_ADDR was properly removed from $if_name" +wait_for_function_response 1 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: INET_ADDR removed from ifconfig - interface $if_name" || + raise "Failed to removed INET_ADDR from ifconfig - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_ip_assign_scheme.sh b/src/nm2/fut/nm2_set_ip_assign_scheme.sh new file mode 100755 index 00000000..6937b48a --- /dev/null +++ b/src/nm2/fut/nm2_set_ip_assign_scheme.sh @@ -0,0 +1,157 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vif'- (string)(optional) + ip_assign_scheme=\$3 -- used as ip_assign_scheme in Wifi_Inet_Config table - default 'static' - (string)(optional) + inet_addr=\$3 -- used as inet_addr column in Wifi_Inet_Config/State table - (string IP address)(optional) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_ip_assign_scheme.sh wifi0 vif static 10.10.10.100 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +if_type=$2 +ip_assign_scheme=$3 +inet_addr=${4:-10.10.10.30} + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Remove running clients first" +rm "/var/run/udhcpc-$if_name.pid" || log "Nothing to remove" +rm "/var/run/udhcpc_$if_name.opts" || log "Nothing to remove" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -netmask "255.255.255.0" \ + -inet_addr "$inet_addr" \ + -ip_assign_scheme static \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +if [ "$ip_assign_scheme" = "dhcp" ]; then + log "$tc_name: Setting dhcp for $if_name to dhcp" + update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u ip_assign_scheme dhcp && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - ip_assign_scheme=dhcp" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - ip_assign_scheme=dhcp" -l "$tc_name" -tc + + wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is ip_assign_scheme dhcp && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=dhcp" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=dhcp" -l "$tc_name" -tc + + log "$tc_name: LEVEL 2 - Checking if DHCP client is alive" + wait_for_function_response 0 "check_pid_file alive \"/var/run/udhcpc-$if_name.pid\"" && + log "$tc_name: DHCP client process ACTIVE - interface $if_name" || + raise "DHCP client process NOT ACTIVE - interface $if_name" -l "$tc_name" -tc + + log "$tc_name: Setting dhcp for $if_name to none" + update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u ip_assign_scheme none && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - ip_assign_scheme=none" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - ip_assign_scheme=none" -l "$tc_name" -tc + + wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is ip_assign_scheme none && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State" -l "$tc_name" -tc + + log "$tc_name: LEVEL 2 - Checking if DHCP client is dead" + wait_for_function_response 0 "check_pid_file dead \"/var/run/udhcpc-$if_name.pid\"" && + log "$tc_name: DHCP client process NOT ACTIVE" || + raise "DHCP client process ACTIVE" -l "$tc_name" -tc + +elif [ "$ip_assign_scheme" = "static" ]; then + log "$tc_name: Setting ip_assign_scheme for $if_name to static" + update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" \ + -u ip_assign_scheme static \ + -u inet_addr "$inet_addr" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - ip_assign_scheme=static" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - ip_assign_scheme=static" -l "$tc_name" -tc + + wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" \ + -is ip_assign_scheme static \ + -is inet_addr "$inet_addr" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - ip_assign_scheme=static" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - ip_assign_scheme=static" -l "$tc_name" -tc + + log "$tc_name: LEVEL 2: Checking if settings are applied to ifconfig" + wait_for_function_response 0 "interface_ip_address $if_name | grep -q \"$inet_addr\"" && + log "$tc_name: Settings applied to ifconfig - interface $if_name" || + raise "Failed to apply settings to ifconfig - interface $if_name" -l "$tc_name" -tc + + log "$tc_name: LEVEL 2 - Checking if DHCP client is DEAD" + wait_for_function_response 0 "check_pid_file dead \"/var/run/udhcpc-$if_name.pid\"" && + log "$tc_name: DHCP client process is DEAD - interface $if_name" || + raise "DHCP client process is NOT DEAD - interface $if_name" -l "$tc_name" -tc +else + raise "Wrong IP_ASSIGN_SCHEME parameter - $ip_assign_scheme" -l "$tc_name" -tc +fi + +pass diff --git a/src/nm2/fut/nm2_set_mtu.sh b/src/nm2/fut/nm2_set_mtu.sh new file mode 100755 index 00000000..abcd9175 --- /dev/null +++ b/src/nm2/fut/nm2_set_mtu.sh @@ -0,0 +1,124 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# TEST DESCRIPTION +# Try to configure MTU to existing interface. +# +# TEST PROCEDURE +# - Configure interface with selected parameters +# +# EXPECTED RESULTS +# Test is passed: +# - if interface is properly configured AND +# - if mtu is applied to State table +# Test fails: +# - if inteface cannot be configured OR +# - if mtu is not applied to State table + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vif' - (string)(optional) + mtu=\$3 -- used as mtu in Wifi_Inet_Config table - default '1600' - (integer)(optional) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_mtu.sh eth0 eth 1500 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide at least 2 argument(s). +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +# Fill variables with provided arguments or defaults. +if_name=$1 +if_type=$2 +mtu=$3 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name (enabled=true, network=true, ip_assign_scheme=static)" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting MTU to $mtu" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u mtu "$mtu" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - mtu $mtu" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - mtu $mtu" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is mtu "$mtu" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - mtu $mtu" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - mtu $mtu" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking if MTU was properly applied to $if_name" +wait_for_function_response 0 "interface_mtu $if_name | grep -q \"$mtu\"" && + log "$tc_name: MTU applied to ifconfig - interface $if_name" || + raise "Failed to apply MTU to ifconfig - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_nat.sh b/src/nm2/fut/nm2_set_nat.sh new file mode 100755 index 00000000..83e5bc00 --- /dev/null +++ b/src/nm2/fut/nm2_set_nat.sh @@ -0,0 +1,138 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# TEST DESCRIPTION +# Try to configure NAT on existing interface. +# +# TEST PROCEDURE +# Set NAT to true, check table. +# Set NAT to false, check table. +# +# EXPECTED RESULTS +# Test is passed: +# - if NAT can be enabled and disabled on existing interface +# Test fails: +# - if inteface cannot be created +# - if NAT cannot be enabled or disabled on existing interface + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vif' - (string)(optional) + NAT=\$3 -- used as NAT in Wifi_Inet_Config table - default 'true' - (boolean)(optional) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_nat.sh eth0 eth true +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide at least 1 argument(s). +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +# Fill variables with provided arguments or defaults. +if_name=$1 +if_type=$2 +NAT=$3 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name (enabled=true, network=true, ip_assign_scheme=static)" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting NAT to $NAT" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u NAT "$NAT" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - NAT $NAT" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - - NAT $NAT" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is NAT "$NAT" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - - NAT $NAT" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - - NAT $NAT" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking state of NAT on $if_name (must be ON)" +wait_for_function_response 0 "interface_nat_enabled $if_name" && + log "$tc_name: NAT applied to iptables - interface $if_name" || + raise "Failed to apply NAT to iptables - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: Disabling NAT" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u NAT false && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - NAT=false" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - NAT=false" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is NAT false && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - NAT=false" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - NAT=false" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Checking state of NAT on $if_name (must be OFF)" +wait_for_function_response 1 "interface_nat_enabled $if_name" && + log "$tc_name: NAT removed from iptables - interface $if_name" || + raise "Failed to remove NAT from iptables - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_netmask.sh b/src/nm2/fut/nm2_set_netmask.sh new file mode 100755 index 00000000..c1d0b710 --- /dev/null +++ b/src/nm2/fut/nm2_set_netmask.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + + +trap ' + reset_inet_entry $if_name || true + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Inet_Config table - (string)(required) + if_type=\$2 -- used as if_type in Wifi_Inet_Config table - default 'vif'- (string)(optional) + netmask=\$3 -- used as netmask in Wifi_Inet_Config table - default '255.255.255.0' - (string)(optional) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_netmask.sh eth0 eth 255.255.0.0 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 1 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=$1 +if_type=$2 +netmask=$3 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -netmask 255.255.255.0 \ + -inet_addr 10.10.10.30 \ + -if_type "$if_type" && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting NETMASK for $if_name to $netmask" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$if_name" -u netmask "$netmask" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - netmask $netmask" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - netmask $netmask" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$if_name" -is netmask "$netmask" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - netmask $netmask" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - netmask $netmask" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check if NETMASK was properly applied to $if_name" +wait_for_function_response 0 "interface_netmask $if_name | grep -q \"$netmask\"" && + log "$tc_name: NETMASK applied to ifconfig - interface $if_name" || + raise "Failed to apply NETMASK to ifconfig - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_parent_ifname.sh b/src/nm2/fut/nm2_set_parent_ifname.sh new file mode 100755 index 00000000..7e01aaa0 --- /dev/null +++ b/src/nm2/fut/nm2_set_parent_ifname.sh @@ -0,0 +1,133 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# TEST DESCRIPTION +# Try to set parent ifname to wireless interface. +# +# TEST PROCEDURE +# - Configure parent interface +# - Wake UP parent interface +# - Configure wireless interface with parent iface name +# +# EXPECTED RESULTS +# Test is passed: +# - if wireless interface is properly configured AND +# - parent iface is UP AND +# - VLAN config is valid +# Test fails: +# - parent iface is NOT UP OR +# - VLAN config is not valid + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + delete_inet_interface "$if_name" + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + parent_ifname=\$1 -- used as parent_ifname in Wifi_Inet_Config table - (string)(required) + virtual_interface_id=\$2 -- used as vlan_id for virtual interface '100' in 'eth0.100'- (integer)(required) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_parent_ifname.sh eth0 100 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide at least 2 argument(s). +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +# Fill variables with provided arguments or defaults. +parent_ifname=$1 +vlan_id=$2 +# Construct if_name from parent_ifname and vlan_id +if_name="$parent_ifname.$vlan_id" + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name (enabled=true, network=true, ip_assign_scheme=static)" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -inet_addr "10.10.10.$vlan_id" \ + -netmask "255.255.255.0" \ + -if_type vlan \ + -parent_ifname "$parent_ifname" \ + -dns "[\"map\",[]]" \ + -vlan_id "$vlan_id" && + log "$tc_name: create_vlan_inet_entry - Success" || + raise "create_vlan_inet_entry - Failed" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check is interface up" +wait_for_function_response 0 "interface_is_up $if_name" && + log "$tc_name: Interface is UP - interface $if_name" || + raise "Interface is NOT UP - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check vlan config - VLAN exists" +wait_for_function_response 0 "grep -q \"$if_name\" /proc/net/vlan/$if_name" && + log "$tc_name: VLAN configuration IS VALID at OS level - interface $if_name" || + raise "VLAN configuration NOT VALID at OS level - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check vlan config - PARENT ifname $parent_ifname" +wait_for_function_response 0 "grep -q \"Device: $parent_ifname\" /proc/net/vlan/$if_name" && + log "$tc_name: Parent device IS VALID at OS level - parent interface $parent_ifname" || + raise "Parent device NOT VALID at OS level - parent interface $parent_ifname" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_upnp_mode.sh b/src/nm2/fut/nm2_set_upnp_mode.sh new file mode 100755 index 00000000..cc8a9799 --- /dev/null +++ b/src/nm2/fut/nm2_set_upnp_mode.sh @@ -0,0 +1,140 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + reset_inet_entry $internal_if + reset_inet_entry $external_if + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + internal_if=\$1 -- used to set internal_if in Wifi_Inet_Config table as internal UPnP interface - (string)(required) + external_if=\$2 -- used to set external_if in Wifi_Inet_Config table as external UPnP interface - (string)(required) + + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_upnp_mode.sh eth0 br-wan +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +internal_if=$1 +external_if=$2 + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $internal_if" +create_inet_entry \ + -if_name "$internal_if" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -netmask 255.255.255.0 \ + -inet_addr 10.10.10.30 && + log "$tc_name: Interface successfully created" || + raise "Failed to create interface" -l "$tc_name" -tc + +log "$tc_name: Setting UPNP_MODE internal on $internal_if" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$internal_if" -u upnp_mode internal && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - upnp_mode=internal" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - upnp_mode=internal" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$internal_if" -is upnp_mode internal && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - upnp_mode=internal" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - upnp_mode=internal" -l "$tc_name" -tc + +log "$tc_name: Setting UPNP_MODE external on $external_if" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$external_if" -u upnp_mode external && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - upnp_mode=external" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - upnp_mode=external" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$external_if" -is upnp_mode external && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - upnp_mode=external" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - upnp_mode=external" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 checks" +wait_for_function_response 0 "check_upnp_conf $internal_if $external_if" && + log "$tc_name: LEVEL 2: UPNP applied to OS" || + raise "LEVEL 2: Failed to apply UPNP to OS" -l "$tc_name" -tc + +log "$tc_name: Disabling UPNP_MODE on $internal_if" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$internal_if" -u upnp_mode "[\"set\",[]]" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - upnp_mode=[\"set\",[]]" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - upnp_mode=[\"set\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$internal_if" -is upnp_mode "disabled" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - upnp_mode=disabled" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - upnp_mode=disabled" -l "$tc_name" -tc + +log "$tc_name: Disabling UPNP_MODE on $external_if" +update_ovsdb_entry Wifi_Inet_Config -w if_name "$external_if" -u upnp_mode "[\"set\",[]]" && + log "$tc_name: update_ovsdb_entry - Wifi_Inet_Config table updated - upnp_mode=[\"set\",[]]" || + raise "update_ovsdb_entry - Failed to update Wifi_Inet_Config - upnp_mode=[\"set\",[]]" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Inet_State -w if_name "$external_if" -is upnp_mode "disabled" && + log "$tc_name: wait_ovsdb_entry - Wifi_Inet_Config reflected to Wifi_Inet_State - upnp_mode=disabled" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Inet_Config to Wifi_Inet_State - upnp_mode=disabled" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 checks" +wait_for_function_response 1 "check_upnp_conf $internal_if $external_if" && + log "$tc_name: LEVEL 2: UPNP removed from OS" || + raise "LEVEL 2: Failed to remove UPNP remove OS" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_set_vlan_id.sh b/src/nm2/fut/nm2_set_vlan_id.sh new file mode 100755 index 00000000..05bfb166 --- /dev/null +++ b/src/nm2/fut/nm2_set_vlan_id.sh @@ -0,0 +1,133 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# TEST DESCRIPTION +# Try to set vlan_id to wireless interface. +# +# TEST PROCEDURE +# - Configure parent interface. +# - Wake UP parent interface. +# - Configure wireless interface with vlan_id. +# +# EXPECTED RESULTS +# Test is passed: +# - if wireless interface is properly configured AND +# - parent iface is UP AND +# - VLAN exists +# - VLAN config is valid +# Test fails: +# - parent iface is NOT UP OR +# - VLAN config is not valid + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap ' + delete_inet_interface "$if_name" + run_setup_if_crashed nm || true + check_restore_management_access || true +' EXIT SIGINT SIGTERM + +usage=" +$(basename "$0") [-h] \$1 \$2 + +where options are: + -h show this help message + +where arguments are: + parent_ifname=\$1 -- used as parent_ifname in Wifi_Inet_Config table - (string)(required) + virtual_interface_id=\$2 -- used as vlan_id for virtual interface '100' in 'eth0.100'- (integer)(required) + +this script is dependent on following: + - running NM manager + - running WM manager + +example of usage: + /tmp/fut-base/shell/nm2/nm2_set_vlan_id.sh eth0 100 +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +# Provide at least 2 argument(s). +if [ $# -lt 2 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +# Fill variables with provided arguments or defaults. +parent_ifname=$1 +vlan_id=$2 +# Construct if_name from parent_ifname and vlan_id. +if_name="$parent_ifname.$vlan_id" + +tc_name="nm2/$(basename "$0")" + +log "$tc_name: Creating Wifi_Inet_Config entries for $if_name (enabled=true, network=true, ip_assign_scheme=static)" +create_inet_entry \ + -if_name "$if_name" \ + -enabled true \ + -network true \ + -ip_assign_scheme static \ + -inet_addr "10.10.10.$vlan_id" \ + -netmask "255.255.255.0" \ + -if_type vlan \ + -parent_ifname "$parent_ifname" \ + -vlan_id "$vlan_id" && + log "$tc_name: create_vlan_inet_entry - Success" || + raise "create_vlan_inet_entry - Failed" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check is interface up - $if_name" +wait_for_function_response 0 "interface_is_up $if_name" && + log "$tc_name: wait_for_function_response - Interface is UP - $if_name" || + raise "wait_for_function_response - Interface is DOWN - $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check vlan config - VLAN exists - $if_name" +wait_for_function_response 0 "grep -q \"$if_name\" /proc/net/vlan/$if_name" && + log "$tc_name: wait_for_function_response - VLAN configuration IS VALID at OS level - interface $if_name" || + raise "wait_for_function_response - VLAN configuration NOT VALID at OS level - interface $if_name" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - Check vlan config - PARENT ifname" +wait_for_function_response 0 "grep -q \"VID: $vlan_id\" /proc/net/vlan/$if_name" && + log "$tc_name: wait_for_function_response - Parent device IS VALID at OS level - interface $if_name" || + raise "wait_for_function_response - Parent device NOT VALID at OS level - interface $if_name" -l "$tc_name" -tc + +pass diff --git a/src/nm2/fut/nm2_setup.sh b/src/nm2/fut/nm2_setup.sh new file mode 100755 index 00000000..2ed81795 --- /dev/null +++ b/src/nm2/fut/nm2_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for NM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="nm2/$(basename "$0")" + +nm_setup_test_environment "$@" && + log "$tc_name: nm_setup_test_environment - Success " || + raise "nm_setup_test_environment - Failed" -l "$tc_name" -tc + +exit 0 diff --git a/src/nm2/fut/unit.mk b/src/nm2/fut/unit.mk new file mode 100644 index 00000000..100f297a --- /dev/null +++ b/src/nm2/fut/unit.mk @@ -0,0 +1,52 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_nm + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_NM),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/nm + +UNIT_FILE := nm2_setup.sh +UNIT_FILE += nm2_configure_nonexistent_iface.sh +UNIT_FILE += nm2_enable_disable_iface_network.sh +UNIT_FILE += nm2_ovsdb_configure_interface_dhcpd.sh +UNIT_FILE += nm2_ovsdb_ip_port_forward.sh +UNIT_FILE += nm2_ovsdb_remove_reinsert_iface.sh +UNIT_FILE += nm2_rapid_multiple_insert_delete_iface.sh +UNIT_FILE += nm2_rapid_multiple_insert_delete_ovsdb_row.sh +UNIT_FILE += nm2_set_broadcast.sh +UNIT_FILE += nm2_set_dns.sh +UNIT_FILE += nm2_set_gateway.sh +UNIT_FILE += nm2_set_inet_addr.sh +UNIT_FILE += nm2_set_ip_assign_scheme.sh +UNIT_FILE += nm2_set_mtu.sh +UNIT_FILE += nm2_set_nat.sh +UNIT_FILE += nm2_set_netmask.sh +UNIT_FILE += nm2_set_parent_ifname.sh +UNIT_FILE += nm2_set_upnp_mode.sh +UNIT_FILE += nm2_set_vlan_id.sh diff --git a/src/nm2/inc/nm2_iface.h b/src/nm2/inc/nm2_iface.h index bafe1b60..ac1246f8 100644 --- a/src/nm2/inc/nm2_iface.h +++ b/src/nm2/inc/nm2_iface.h @@ -38,7 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "ds_list.h" +#include "ds_dlist.h" #include "ds_tree.h" #include "schema.h" @@ -48,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "inet_vif.h" #include "inet_gre.h" #include "inet_vlan.h" +#include "inet_pppoe.h" /* Debounce timer for interface configuration commit */ #define NM2_IFACE_APPLY_TIMER 0.3 @@ -88,6 +89,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. M(NM2_IFTYPE_BRIDGE, "bridge") \ M(NM2_IFTYPE_GRE, "gre") \ M(NM2_IFTYPE_TAP, "tap") \ + M(NM2_IFTYPE_PPPOE, "pppoe") \ M(NM2_IFTYPE_MAX, NULL) @@ -127,6 +129,7 @@ struct nm2_iface bool if_commit; /* Commit pending */ inet_t* if_inet; /* Inet structure */ ds_tree_node_t if_tnode; /* ds_tree node -- for device lookup by name */ + ds_dlist_node_t if_commit_dnode; /* Node nm2_iface_commit_list */ inet_state_t if_inet_state; /* Remembered last interface status */ ds_tree_t if_dhcpc_options; /* Options received from the DHCP client */ struct nm2_ip_interface *if_ipi; /* Non-NULL if there's a nm2_ip_interface structure associated */ diff --git a/src/nm2/src/nm2_iface.c b/src/nm2/src/nm2_iface.c index 62182a69..b599f7ca 100644 --- a/src/nm2/src/nm2_iface.c +++ b/src/nm2/src/nm2_iface.c @@ -26,11 +26,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "osa_assert.h" #include "log.h" +#include "util.h" #include "build_version.h" #include "inet.h" #include "evx.h" #include "schema.h" -#include "target.h" +#include "osp_unit.h" #include "nm2.h" #include "nm2_iface.h" @@ -43,6 +44,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static ds_key_cmp_t nm2_iface_cmp; ds_tree_t nm2_iface_list = DS_TREE_INIT(nm2_iface_cmp, struct nm2_iface, if_tnode); +/* Ordered list of pending commits */ +ds_dlist_t nm2_iface_commit_list = DS_DLIST_INIT(struct nm2_iface, if_commit_dnode); static void nm2_iface_dhcpc_notify(inet_t *self, enum osn_notify hint, const char *name, const char *value); static inet_t *nm2_iface_new_inet(const char *ifname, enum nm2_iftype type); @@ -197,6 +200,11 @@ bool nm2_iface_del(struct nm2_iface *piface) bool retval = true; + /* Remove the interface from the "pending commits" list */ + if (piface->if_commit) + { + ds_dlist_remove(&nm2_iface_commit_list, piface); + } /* Destroy the inet object */ if (!inet_del(piface->if_inet)) @@ -284,11 +292,10 @@ void __nm2_iface_apply(EV_P_ ev_debounce *w, int revent) TRACE(); struct nm2_iface *piface; + ds_dlist_iter_t iter; - ds_tree_foreach(&nm2_iface_list, piface) + ds_dlist_foreach_iter(&nm2_iface_commit_list, piface, iter) { - /* If not commit bit is set, continue */ - if (!piface->if_commit) continue; piface->if_commit = false; /* Apply the configuration */ @@ -298,6 +305,8 @@ void __nm2_iface_apply(EV_P_ ev_debounce *w, int revent) piface->if_name, nm2_iftype_tostr(piface->if_type)); } + + ds_dlist_iremove(&iter); } } @@ -310,8 +319,12 @@ bool nm2_iface_apply(struct nm2_iface *piface) static bool apply_init = false; + /* If already flagged, do not add to the list */ + if (piface->if_commit) return true; + /* Flag the interface as pending for commit */ piface->if_commit = true; + ds_dlist_insert_tail(&nm2_iface_commit_list, piface); /* If it's not already initialized, initialize the commit timer */ if (!apply_init) @@ -333,7 +346,7 @@ bool nm2_iface_apply(struct nm2_iface *piface) * Additionally, it initializes some of the DHCP client options -- this is * true also for interfaces that do not actually use DHCP. * - * TODO: Get rid of the target dependency (target_sku_get(), target_model_get() etc). + * TODO: Get rid of the target dependency (osp_unit_sku_get(), osp_unit_model_get() etc). */ inet_t *nm2_iface_new_inet(const char *ifname, enum nm2_iftype type) { @@ -366,6 +379,10 @@ inet_t *nm2_iface_new_inet(const char *ifname, enum nm2_iftype type) nif = inet_vlan_new(ifname); break; + case NM2_IFTYPE_PPPOE: + nif = inet_pppoe_new(ifname); + break; + default: /* Unsupported types */ LOG(ERR, "nm2_iface: %s: Unsupported interface type: %d", ifname, type); @@ -383,20 +400,20 @@ inet_t *nm2_iface_new_inet(const char *ifname, enum nm2_iftype type) */ /* Retrieve vendor class, sku, hostname ... we need these values to populate DHCP options */ - if (vendor_class[0] == '\0' && target_model_get(vendor_class, sizeof(vendor_class)) == false) + if (vendor_class[0] == '\0' && osp_unit_model_get(vendor_class, sizeof(vendor_class)) == false) { STRSCPY(vendor_class, TARGET_NAME); } if (serial_num[0] == '\0') { - target_serial_get(serial_num, sizeof(serial_num)); + osp_unit_serial_get(serial_num, sizeof(serial_num)); } /* read SKU number, if empty, reset buffer */ if (hostname[0] == '\0') { - if (target_sku_get(sku_num, sizeof(sku_num)) == false) + if (osp_unit_sku_get(sku_num, sizeof(sku_num)) == false) { tsnprintf(hostname, sizeof(hostname), "%s_Pod", serial_num); } diff --git a/src/nm2/src/nm2_inet_config.c b/src/nm2/src/nm2_inet_config.c index 9d47d43a..cdb81ded 100644 --- a/src/nm2/src/nm2_inet_config.c +++ b/src/nm2/src/nm2_inet_config.c @@ -126,6 +126,10 @@ static bool nm2_inet_vlan_set( struct nm2_iface *piface, const struct schema_Wifi_Inet_Config *pconfig); +static bool nm2_inet_credential_set( + struct nm2_iface *piface, + const struct schema_Wifi_Inet_Config *iconf); + static void nm2_inet_copy( struct nm2_iface *piface, const struct schema_Wifi_Inet_Config *pconfig); @@ -236,6 +240,7 @@ bool nm2_inet_config_set(struct nm2_iface *piface, struct schema_Wifi_Inet_Confi retval &= nm2_inet_ip4tunnel_set(piface, iconf); retval &= nm2_inet_dhsnif_set(piface, iconf); retval &= nm2_inet_vlan_set(piface, iconf); + retval &= nm2_inet_credential_set(piface, iconf); retval &= nm2_inet_igmp_proxy_set(piface, iconf); retval &= nm2_inet_mld_proxy_set(piface, iconf); @@ -279,6 +284,14 @@ bool nm2_inet_interface_set( retval = false; } + if (!inet_parent_ifname_set(piface->if_inet, iconf->parent_ifname_exists ? iconf->parent_ifname : NULL)) + { + LOG(WARN, "inet_config: %s (%s): Error setting parent interface name.", + piface->if_name, nm2_iftype_tostr(piface->if_type)); + + retval = false; + } + if (!inet_nat_enable(piface->if_inet, iconf->NAT_exists && iconf->NAT)) { LOG(WARN, "inet_config: %s (%s): Error enabling NAT (%d).", @@ -918,7 +931,6 @@ bool nm2_inet_vlan_set( struct nm2_iface *piface, const struct schema_Wifi_Inet_Config *iconf) { - const char *ifparent = NULL; int vlanid = 0; /* Not supported for non-VLAN types */ @@ -929,12 +941,23 @@ bool nm2_inet_vlan_set( vlanid = iconf->vlan_id; } - if (iconf->parent_ifname_exists) - { - ifparent = iconf->parent_ifname; - } + return inet_vlanid_set(piface->if_inet, vlanid); +} + +/* Set interface credentials */ +bool nm2_inet_credential_set( + struct nm2_iface *piface, + const struct schema_Wifi_Inet_Config *iconf) +{ + /* + * Currently only PPPoE is supported + */ + if (piface->if_type != NM2_IFTYPE_PPPOE) return true; + + const char *username = SCHEMA_FIND_KEY(iconf->ppp_options, "username"); + const char *password = SCHEMA_FIND_KEY(iconf->ppp_options, "password"); - return inet_vlan_set(piface->if_inet, ifparent, vlanid); + return inet_credential_set(piface->if_inet, username, password); } /* diff --git a/src/nm2/src/nm2_port.c b/src/nm2/src/nm2_port.c index 7c5960aa..9fb701ac 100644 --- a/src/nm2/src/nm2_port.c +++ b/src/nm2/src/nm2_port.c @@ -24,12 +24,13 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "log.h" +#include "util.h" #include "ovsdb_table.h" #include "os_util.h" #include "reflink.h" #include "synclist.h" #include "ovsdb_sync.h" -#include "target.h" #include "osp_l2switch.h" #include "nm2.h" diff --git a/src/om/src/om_monitor.c b/src/om/src/om_monitor.c index b21a26af..d1bafe05 100644 --- a/src/om/src/om_monitor.c +++ b/src/om/src/om_monitor.c @@ -54,12 +54,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "om.h" #include "util.h" #include "ovsdb_sync.h" +#include "ovsdb_update.h" +#include "ovsdb_sync.h" +#include "ovsdb_table.h" +#include "schema.h" /*****************************************************************************/ #define MODULE_ID LOG_MODULE_ID_MAIN /*****************************************************************************/ +ovsdb_table_t table_Openflow_Local_Tag; static ovsdb_update_monitor_t om_monitor_config; static ovsdb_update_monitor_t om_monitor_tags; static ovsdb_update_monitor_t om_monitor_tag_groups; @@ -187,7 +192,7 @@ om_range_clear_range_rules(void) struct om_rule_node *data; ds_list_iter_t iter; - for (data = ds_list_ifirst(&iter, &range_rules); + for (data = ds_list_ifirst(&iter, &range_rules); data != NULL; data = ds_list_inext(&iter)) { ds_list_iremove(&iter); @@ -267,19 +272,21 @@ om_range_long_to_dot_ip(uint32_t ipnum) static void om_range_rmv_substr(char *s,const char *toremove) { - while( (s=strstr(s,toremove)) ) { + while( (s=strstr(s,toremove)) ) { memmove(s,s+strlen(toremove),1+strlen(s+strlen(toremove))); } } -// Pull out the start and end values for a string, +// Pull out the start and end values for a string, // Example: tcp,tp_src=$<1-4> turns into (1, 4, tcp) static bool om_range_extract(struct schema_Openflow_Config *sflow, char *pattern, - char *start, char *end, size_t str_size, struct schema_Openflow_Config *out) + char *start, char *end, size_t str_size, struct schema_Openflow_Config *out) { char *token, *str, *iter; char removing[1024]; + char *orig_str; + bool rc = false; memcpy(out, sflow, sizeof(*out)); @@ -288,24 +295,19 @@ om_range_extract(struct schema_Openflow_Config *sflow, char *pattern, iter = iter + 3; str = strdup(iter); // We own str's memory now. + orig_str = str; token = strsep(&str, "-"); if (!token) { - if (str) { - free(str); - } - - return false; + rc = false; + goto err; } strscpy(start, token, str_size); token = strsep(&str, ">"); if (!token) { - if (str) { - free(str); - } - - return false; + rc = false; + goto err; } strscpy(end, token, str_size); @@ -314,11 +316,11 @@ om_range_extract(struct schema_Openflow_Config *sflow, char *pattern, if ( strstr(sflow->rule, removing) != NULL ) { STRSCPY(out->rule, sflow->rule); om_range_rmv_substr(out->rule, removing); - - return true; + rc = true; } - - return false; +err: + if (orig_str) free(orig_str); + return rc; } static bool @@ -710,6 +712,31 @@ om_monitor_update_tags(om_action_t type, json_t *js) return; } +/****************************************************************************** + * Adds/deletes/updates local tags based on Openflow_Local_Tag table + *****************************************************************************/ +void callback_Openflow_Local_Tag( + ovsdb_update_monitor_t *mon, + struct schema_Openflow_Local_Tag *old_rec, + struct schema_Openflow_Local_Tag *conf) +{ + if (mon->mon_type == OVSDB_UPDATE_NEW) + { + om_local_tag_add_from_schema(conf); + } + + if (mon->mon_type == OVSDB_UPDATE_DEL) + { + om_local_tag_remove_from_schema(old_rec); + } + + if (mon->mon_type == OVSDB_UPDATE_MODIFY) + { + om_local_tag_update_from_schema(conf); + } +} + + /****************************************************************************** * Handle Openflow_Tag callbacks ******************************************************************************/ @@ -837,5 +864,8 @@ om_monitor_init(void) return false; } + OVSDB_TABLE_INIT_NO_KEY(Openflow_Local_Tag); + OVSDB_TABLE_MONITOR(Openflow_Local_Tag, false); + return true; } diff --git a/src/om/src/om_template.c b/src/om/src/om_template.c index c65d1608..9b0fa184 100644 --- a/src/om/src/om_template.c +++ b/src/om/src/om_template.c @@ -152,7 +152,7 @@ om_template_rule_expand(om_tflow_t *tflow, om_tdata_t *tdata) strcat(erule, p); s += 2; - if (*s == TEMPLATE_DEVICE_CHAR || *s == TEMPLATE_CLOUD_CHAR) { + if (*s == TEMPLATE_DEVICE_CHAR || *s == TEMPLATE_CLOUD_CHAR || *s == TEMPLATE_LOCAL_CHAR) { s++; } if (!(e = strchr(s, end))) { diff --git a/src/om/src/om_tflows.c b/src/om/src/om_tflows.c index 1cd2fe98..c81c0f7f 100644 --- a/src/om/src/om_tflows.c +++ b/src/om/src/om_tflows.c @@ -121,6 +121,10 @@ om_tflow_detect_vars(const char *token, const char *rule, char *what, char var_c s++; flag |= OM_TLE_FLAG_CLOUD; } + else if (*s == TEMPLATE_LOCAL_CHAR) { + s++; + flag |= OM_TLE_FLAG_LOCAL; + } if (!(p = strchr(s, end))) { LOGW("[%s] Template Flow has malformed %s (no ending '%c')", token, what, end); @@ -130,8 +134,7 @@ om_tflow_detect_vars(const char *token, const char *rule, char *what, char var_c LOGT("[%s] Template Flow detected %s %s'%s'", token, what, - (flag == OM_TLE_FLAG_DEVICE) ? "device " : - (flag == OM_TLE_FLAG_CLOUD) ? "cloud " : "", + om_tag_get_tle_flag(flag), s); if (!om_tag_list_entry_find_by_val_flags(list, s, base_flags)) { diff --git a/src/pm/inc/pm.h b/src/pm/inc/pm.h index 9b5d970b..991ed627 100644 --- a/src/pm/inc/pm.h +++ b/src/pm/inc/pm.h @@ -33,5 +33,6 @@ bool pm_led_init(void); bool pm_tm_init(void); bool pm_tm_deinit(void); bool pm_lm_init(void); +bool pm_objm_init(void); #endif /* PM_H_INCLUDED */ diff --git a/src/pm/inc/pm_objm.h b/src/pm/inc/pm_objm.h new file mode 100644 index 00000000..699b4883 --- /dev/null +++ b/src/pm/inc/pm_objm.h @@ -0,0 +1,62 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PM_OBJM_H_INCLUDED +#define PM_OBJM_H_INCLUDED + +#include "osp_objm.h" + +#define PM_OBJM_STORAGE "pm_obj" +#define PM_OBJM_KEY "store" + +#define PM_OBJM_MQTT "objectStore" + +#define PM_OBJS_INSTALLED "install-done" // Object is installed on the device +#define PM_OBJS_DOWNLOAD_STARTED "download-started" // Download of the object started +#define PM_OBJS_DOWNLOAD_FAILED "download-failed" // Download of the object failed +#define PM_OBJS_DOWNLOAD_DONE "download-done" // Download of the object complete +#define PM_OBJS_INSTALL_FAILED "install-failed" // Install of the object failed +#define PM_OBJS_LOAD_FAILED "load-failed" // Load of object failed +#define PM_OBJS_ACTIVE "active" // Object is activly used by final user +#define PM_OBJS_OBSOLETE "obsolete" // Object is not used by final user and can be removed +#define PM_OBJS_ERROR "error" // General error + +#define FIELD_ARRAY_LEN(TYPE,FIELD) ARRAY_LEN(((TYPE*)0)->FIELD) + +struct pm_objm_ctx_t +{ + struct ev_async install_async; + char url[FIELD_ARRAY_LEN(struct schema_Object_Store_Config, dl_url)]; + char dl_path[PATH_MAX]; + char name[FIELD_ARRAY_LEN(struct schema_Object_Store_Config, name)]; + char version[FIELD_ARRAY_LEN(struct schema_Object_Store_Config, version)]; + int timeout; + bool fw_integrated; + char status[64]; +}; + + +#endif // PM_OBJM_H_INCLUDED diff --git a/src/pm/inc/pm_objm_pjs.h b/src/pm/inc/pm_objm_pjs.h new file mode 100644 index 00000000..bfdb6e00 --- /dev/null +++ b/src/pm/inc/pm_objm_pjs.h @@ -0,0 +1,53 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * =========================================================================== + * Object store management structure/JSON definition. The JSON will be stored + * to persistent storage in compact form. + * =========================================================================== + */ + +/* + * Single object record + */ +#define PJS_PM_OBJM_STORE_RECORD \ + PJS(pm_objm_store_record, \ + PJS_STRING(name, 64) \ + PJS_STRING(version, 16) \ + PJS_BOOL(fw_integrated)) + +/* + * Object database structure, contains up to 64 object records + */ +#define PJS_PM_OBJM_STORE \ + PJS(pm_objm_store, \ + PJS_SUB_A(obj_records, pm_objm_store_record, 64)) + +/* + * Generate the PJS table + */ +#define PJS_GEN_TABLE PJS_PM_OBJM_STORE_RECORD PJS_PM_OBJM_STORE diff --git a/src/pm/inc/pm_tm.h b/src/pm/inc/pm_tm.h index a3991c90..9f6acdbb 100644 --- a/src/pm/inc/pm_tm.h +++ b/src/pm/inc/pm_tm.h @@ -29,7 +29,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include "osp.h" +#include "osp_tm.h" +#include "osp_led.h" struct osp_tm_ctx { diff --git a/src/pm/kconfig/Kconfig.managers b/src/pm/kconfig/Kconfig.managers index d8711d8d..16830dc5 100644 --- a/src/pm/kconfig/Kconfig.managers +++ b/src/pm/kconfig/Kconfig.managers @@ -101,4 +101,32 @@ if MANAGER_PM default n help Select to include log management as part of PM (Platform manager) + + menuconfig PM_ENABLE_OBJM + bool "Enable support for Object Management" + default n + help + Select to include Object management as part of PM (Platform manager) + + if PM_ENABLE_OBJM + config PM_OBJM_DOWNLOAD_DIR + string "Location of tmp download dir" + default "/tmp/obj-dl" + help + Location of temporary folder where all the objects are downloaded before installing + + config PM_OBJM_INTEGRATED_DIR + string "Location of pre integrated dir" + default "$(INSTALL_PREFIX)/storage" + help + Location of preintegrated packages + endif + + config PM_GW_OFFLINE_CFG + bool "Enable support for GW offline config" + default n + help + Ability to recover previously working ethernet connected POD acting as a GW + on reboot with loss of Internet access with local HOME LAN service + from stored subset of Cloud-provisioned OVSDB configuration. endif diff --git a/src/pm/src/pm_client_freeze.c b/src/pm/src/pm_client_freeze.c index 082c4953..324f047a 100644 --- a/src/pm/src/pm_client_freeze.c +++ b/src/pm/src/pm_client_freeze.c @@ -50,9 +50,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "json_util.h" #include "pm.h" -#include "target.h" -// defines +// Defines #define MODULE_ID LOG_MODULE_ID_MAIN // OVSDB constants diff --git a/src/pm/src/pm_client_nickname.c b/src/pm/src/pm_client_nickname.c index 8ce390ee..9caccbb7 100644 --- a/src/pm/src/pm_client_nickname.c +++ b/src/pm/src/pm_client_nickname.c @@ -50,7 +50,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "json_util.h" #include "pm.h" -#include "target.h" // Defines #define MODULE_ID LOG_MODULE_ID_MAIN diff --git a/src/pm/src/pm_gw_offline_cfg.c b/src/pm/src/pm_gw_offline_cfg.c new file mode 100644 index 00000000..264f2c60 --- /dev/null +++ b/src/pm/src/pm_gw_offline_cfg.c @@ -0,0 +1,1016 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "ovsdb_table.h" +#include "ovsdb_sync.h" +#include "schema.h" +#include "json_util.h" +#include "log.h" +#include "osp_ps.h" + + +#define KEY_OFFLINE_CFG "gw_offline_cfg" +#define KEY_OFFLINE_MON "gw_offline_mon" +#define KEY_OFFLINE "gw_offline" +#define KEY_OFFLINE_STATUS "gw_offline_status" + +#define VAL_OFFLINE_ON "true" +#define VAL_OFFLINE_OFF "false" +#define VAL_STATUS_READY "ready" +#define VAL_STATUS_ACTIVE "active" +#define VAL_STATUS_ENABLED "enabled" +#define VAL_STATUS_DISABLED "disabled" +#define VAL_STATUS_ERROR "error" + +#define PM_MODULE_NAME "PM" + +#define PS_STORE_GW_OFFLINE "pm_gw_offline_store" + +#define PS_KEY_VIF_CONFIG "vif_config" +#define PS_KEY_INET_CONFIG "inet_config" +#define PS_KEY_RADIO_CONFIG "radio_config" +#define PS_KEY_INET_CONFIG_HOME_APS "inet_config_home_aps" +#define PS_KEY_RADIO_IF_NAMES "radio_if_names" +#define PS_KEY_DHCP_RESERVED_IP "dhcp_reserved_ip" + +#define PS_KEY_OFFLINE_CFG KEY_OFFLINE_CFG + +#define TIMEOUT_NO_CFG_CHANGE 30 + +#if defined(CONFIG_TARGET_LAN_BRIDGE_NAME) +#define LAN_BRIDGE CONFIG_TARGET_LAN_BRIDGE_NAME +#else +#define LAN_BRIDGE SCHEMA_CONSTS_BR_NAME_HOME +#endif + +struct gw_offline_cfg +{ + json_t *vif_config; + json_t *inet_config; + json_t *radio_config; + json_t *inet_config_home_aps; + json_t *radio_if_names; + json_t *dhcp_reserved_ip; +}; + +MODULE(pm_gw_offline, pm_gw_offline_init, pm_gw_offline_fini) + +static ovsdb_table_t table_Node_Config; +static ovsdb_table_t table_Node_State; +static ovsdb_table_t table_Wifi_VIF_Config; +static ovsdb_table_t table_Wifi_Inet_Config; +static ovsdb_table_t table_Wifi_Radio_Config; +static ovsdb_table_t table_DHCP_reserved_IP; + +static ev_timer timeout_no_cfg_change; + +static struct gw_offline_cfg cfg_cache; + +static bool gw_offline_cfg; +static bool gw_offline_mon; +static bool gw_offline; + +static bool gw_offline_ps_store(const char *ps_key, const json_t *config); +static bool gw_offline_cfg_ps_store(const struct gw_offline_cfg *cfg); +static bool gw_offline_ps_load(const char *ps_key, json_t **config); +static bool gw_offline_cfg_ps_load(struct gw_offline_cfg *cfg); + +static bool gw_offline_cfg_ovsdb_read(struct gw_offline_cfg *cfg); +static bool gw_offline_cfg_ovsdb_apply(const struct gw_offline_cfg *cfg); + +bool pm_gw_offline_cfg_is_available(); +bool pm_gw_offline_load_and_apply_config(); +bool pm_gw_offline_read_and_store_config(); + +static void delete_special_ovsdb_keys(json_t *rows) +{ + size_t index; + json_t *row; + + json_array_foreach(rows, index, row) + { + json_object_del(row, "_uuid"); + json_object_del(row, "_version"); + } +} + +static void gw_offline_cfg_release(struct gw_offline_cfg *cfg) +{ + json_decref(cfg->vif_config); + json_decref(cfg->inet_config); + json_decref(cfg->radio_config); + json_decref(cfg->inet_config_home_aps); + json_decref(cfg->radio_if_names); + json_decref(cfg->dhcp_reserved_ip); +} + +static void gw_offline_cfg_delete_special_keys(struct gw_offline_cfg *cfg) +{ + delete_special_ovsdb_keys(cfg->vif_config); + delete_special_ovsdb_keys(cfg->inet_config); + delete_special_ovsdb_keys(cfg->radio_config); + delete_special_ovsdb_keys(cfg->inet_config_home_aps); + delete_special_ovsdb_keys(cfg->dhcp_reserved_ip); +} + +static void on_timeout_cfg_no_change(struct ev_loop *loop, ev_timer *watcher, int revent) +{ + if (!(gw_offline_cfg && gw_offline_mon)) + { + LOG(TRACE, "offline_cfg: %s() called, but gw_offline_cfg=%d, gw_offline_mon=%d. Ignoring", + __func__, gw_offline_cfg, gw_offline_mon); + return; + } + + pm_gw_offline_read_and_store_config(); +} + +static bool pm_node_state_set(const char *key, const char *value) +{ + struct schema_Node_State node_state; + json_t *where; + + where = json_array(); + json_array_append_new(where, ovsdb_tran_cond_single("module", OFUNC_EQ, PM_MODULE_NAME)); + json_array_append_new(where, ovsdb_tran_cond_single("key", OFUNC_EQ, (char *)key)); + + MEMZERO(node_state); + SCHEMA_SET_STR(node_state.module, PM_MODULE_NAME); + SCHEMA_SET_STR(node_state.key, key); + + if (value != NULL) + { + SCHEMA_SET_STR(node_state.value, value); + ovsdb_table_upsert_where(&table_Node_State, where, &node_state, false); + } + else + { + ovsdb_table_delete_where(&table_Node_State, where); + } + return true; +} + +static void on_configuration_updated() +{ + if (gw_offline_cfg && gw_offline_mon) + { + LOG(DEBUG, "offline_cfg: Feature and monitoring enabled. " + "Will read && store config after timeout if no additional config change."); + + /* On each OVSDB config change we're interested in, we restart the + * current timer so that we read the whole configuration not at every + * ovsdb monitor callback, but after a "cool down period". */ + ev_timer_stop(EV_DEFAULT, &timeout_no_cfg_change); + ev_timer_set(&timeout_no_cfg_change, TIMEOUT_NO_CFG_CHANGE, 0.0); + ev_timer_start(EV_DEFAULT, &timeout_no_cfg_change); + } + else + { + LOG(DEBUG, "offline_cfg: gw_offline_cfg=%d, gw_offline_mon=%d. Ignore this configuration update.", + gw_offline_cfg, gw_offline_mon); + } +} + +static void callback_Wifi_VIF_Config( + ovsdb_update_monitor_t *mon, + struct schema_Wifi_VIF_Config *old_rec, + struct schema_Wifi_VIF_Config *config) +{ + on_configuration_updated(); +} + +static void callback_Wifi_Inet_Config( + ovsdb_update_monitor_t *mon, + struct schema_Wifi_Inet_Config *old_rec, + struct schema_Wifi_Inet_Config *config) +{ + on_configuration_updated(); +} + +static void callback_Wifi_Radio_Config( + ovsdb_update_monitor_t *mon, + struct schema_Wifi_Radio_Config *old_rec, + struct schema_Wifi_Radio_Config *config) +{ + on_configuration_updated(); +} + +static void callback_DHCP_reserved_IP( + ovsdb_update_monitor_t *mon, + struct schema_DHCP_reserved_IP *old_rec, + struct schema_DHCP_reserved_IP *config) +{ + on_configuration_updated(); +} + +static bool gw_offline_enable_cfg_mon() +{ + static bool inited; + + if (inited) + return true; + + OVSDB_TABLE_MONITOR(Wifi_VIF_Config, true); + OVSDB_TABLE_MONITOR(Wifi_Inet_Config, true); + OVSDB_TABLE_MONITOR(Wifi_Radio_Config, true); + OVSDB_TABLE_MONITOR(DHCP_reserved_IP, true); + + ev_timer_init(&timeout_no_cfg_change, on_timeout_cfg_no_change, TIMEOUT_NO_CFG_CHANGE, 0.0); + + inited = true; + return true; +} + +static void callback_Node_Config( + ovsdb_update_monitor_t *mon, + struct schema_Node_Config *old_rec, + struct schema_Node_Config *config) +{ + pjs_errmsg_t perr; + json_t *row; + + if (mon->mon_type == OVSDB_UPDATE_ERROR) + return; + if (!(config->module_exists && strcmp(config->module, PM_MODULE_NAME) == 0)) + return; + + /* Enabling/Disabling the feature (Cloud): */ + if (strcmp(config->key, KEY_OFFLINE_CFG) == 0) + { + if (mon->mon_type == OVSDB_UPDATE_DEL) + strcpy(config->value, VAL_OFFLINE_OFF); + + // Set enable/disable flag: + if (strcmp(config->value, VAL_OFFLINE_ON) == 0) + { + gw_offline_cfg = true; + LOG(INFO, "offline_cfg: Cloud enabled feature."); + } + else + { + gw_offline_cfg = false; + LOG(INFO, "offline_cfg: Cloud disabled feature."); + } + + // Remember enable/disable flag: + if (config->persist_exists && config->persist) + { + row = schema_Node_Config_to_json(config, perr); + if (row == NULL) + { + LOG(ERR, "offline_cfg: Error converting to json: %s", perr); + return; + } + if (!gw_offline_ps_store(PS_KEY_OFFLINE_CFG, row)) + LOG(ERR, "offline_cfg: Error storing gw_offline_cfg flag to persistent storage"); + json_decref(row); + } + + // Reflect enable/disable flag in Node_State: + pm_node_state_set(KEY_OFFLINE_CFG, config->value); + + // Indicate ready if enabled and config already available: + if (gw_offline_cfg) + { + if (pm_gw_offline_cfg_is_available()) + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_READY); + else + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_ENABLED); + } + else + { + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_DISABLED); + } + } + + /* Enabling/disabling config monitoring and storing (Cloud): */ + if (strcmp(config->key, KEY_OFFLINE_MON) == 0) + { + if (mon->mon_type == OVSDB_UPDATE_DEL) + strcpy(config->value, VAL_OFFLINE_OFF); + + // Set enable/disable config monitoring flag: + if (strcmp(config->value, VAL_OFFLINE_ON) == 0) + { + if (!gw_offline_cfg) + { + LOG(WARN, "offline_cfg: Cloud tried to enable config monitoring but feature is disabled. Ignoring."); + return; + } + gw_offline_mon = true; + + // Do the initial read config and store to persistent storage: + pm_gw_offline_read_and_store_config(); + + // Enable monitoring of ovsdb config subset: + gw_offline_enable_cfg_mon(); + + LOG(INFO, "offline_cfg: Cloud enabled config monitoring"); + } + else + { + gw_offline_mon = false; + LOG(INFO, "offline_cfg: Cloud disabled config monitoring."); + } + } + + /* Triggering restoring of config from persistent storage (CM): */ + if (strcmp(config->key, KEY_OFFLINE) == 0) + { + if (strcmp(config->value, VAL_OFFLINE_ON) == 0 + && (mon->mon_type == OVSDB_UPDATE_NEW || mon->mon_type == OVSDB_UPDATE_MODIFY)) + { + /* Enabled by CM when no Cloud/Internet connectivity and other + * conditions are met for certain amount of time. */ + gw_offline = true; + LOG(INFO, "offline_cfg: Offline config mode enabled. Load && apply persistent config triggered."); + pm_gw_offline_load_and_apply_config(); + } + else + { + /* Disabled by CM when Cloud/Internet connectivity reestablished. + * + * In this case, PM does nothing -- Cloud will push proper ovsdb + * config that should cleanly overwrite the applied persistent config. + * If not, then restart of managers will be required. + */ + gw_offline = false; + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_DISABLED); + LOG(INFO, "offline_cfg: Offline config mode disabled."); + } + } +} + +static const char *find_radio_if_name_for_vif_with_uuid( + const struct gw_offline_cfg *cfg, + const char *vif_str_uuid) +{ + size_t index; + size_t index2; + json_t *radio_row; + json_t *a_vif_config; + const char *radio_if_name = NULL; + + json_array_foreach(cfg->radio_config, index, radio_row) + { + json_t *vif_configs = json_object_get(radio_row, "vif_configs"); + + json_array_foreach(json_array_get(vif_configs, 1), index2, a_vif_config) + { + const char *str_uuid = json_string_value(json_array_get(a_vif_config, 1)); + if (str_uuid != NULL) + { + if (strcmp(str_uuid, vif_str_uuid) == 0) + { + /* For VIF with vif_str_uuid we've found the corresponding + * radio if_name: */ + radio_if_name = json_string_value(json_object_get(radio_row, "if_name")); + return radio_if_name; + } + } + } + } + return NULL; +} + +/* In array 'radio_if_names' at index n set radio if_name for the corresponding + * VIF at index n in array 'vif_config'. */ +static bool gw_offline_cfg_set_radio_if_names(struct gw_offline_cfg *cfg) +{ + size_t index; + json_t *vif_row; + json_t *juuid = NULL; + const char *vif_str_uuid = NULL; + + json_decref(cfg->radio_if_names); + cfg->radio_if_names = json_array(); + + // Traverse VIFs and find out their radio: + json_array_foreach(cfg->vif_config, index, vif_row) + { + juuid = json_object_get(vif_row, "_uuid"); + vif_str_uuid = json_string_value(json_array_get(juuid, 1)); + + const char *radio_if_name = find_radio_if_name_for_vif_with_uuid(cfg, vif_str_uuid); + if (radio_if_name == NULL) + { + /* A valid VIF that is up should have a correspoinding radio that + * is referencing that VIF with uuiid, so issue at least a warning. */ + LOG(WARN, "offline_cfg: NOT FOUND radio if_name for VIF with uuid=%s", vif_str_uuid); + return false; + } + LOG(DEBUG, "offline_cfg: For VIF with uuid=%s found radio if_name=%s", vif_str_uuid, radio_if_name); + json_array_append_new(cfg->radio_if_names, json_string(radio_if_name)); + + } + return true; +} + +static void gw_offline_cfg_cleanup_radio_config(struct gw_offline_cfg *cfg) +{ + json_t *row; + size_t index; + + json_array_foreach(cfg->radio_config, index, row) + { + // channel_mode: cloud --> manual + json_object_set_new(row, "channel_mode", json_string("manual")); + /* + * Cleanup vif_configs (radio --> VIF uuids) references as these are + * valid only for this runtime config and does not make sense storing + * them to persistent storage.. When loading stored config, + * these references will be setup according to state remembered in + * 'radio_if_names'. + */ + json_object_del(row, "vif_configs"); + } +} + +/* Add uuid (of a VIF) to Wifi_Radio_Config's 'vif_configs' for radio 'if_name': */ +static bool ovsdb_add_uuid_to_radio_config(const char *if_name, ovs_uuid_t uuid) +{ + json_t *row = NULL; + int rv; + + LOG(DEBUG, "offline_cfg: Adding uuid=%s to Wifi_Radio_Config -where if_name==%s", uuid.uuid, if_name); + + row = json_pack("{ s : [ s, s ] }", "vif_configs", "uuid", uuid.uuid); + if (row == NULL) + { + LOG(ERR, "offline_cfg: Error packing vif_configs json row"); + return false; + } + + rv = ovsdb_sync_update("Wifi_Radio_Config", "if_name", if_name, row); + if (rv != 1) + { + LOG(ERR, "offline_cfg: Error updating Wifi_Radio_Config: rv=%d", rv); + json_decref(row); + return false; + } + json_decref(row); + return true; +} + +/* Initiate this module. */ +void pm_gw_offline_init(void) +{ + json_t *json_en = NULL; + + LOG(INFO, "offline_cfg: %s()", __func__); + + // Init OVSDB: + OVSDB_TABLE_INIT_NO_KEY(Node_Config); + + OVSDB_TABLE_INIT_NO_KEY(Node_State); + OVSDB_TABLE_INIT(Wifi_VIF_Config, if_name); + OVSDB_TABLE_INIT(Wifi_Inet_Config, if_name); + OVSDB_TABLE_INIT(Wifi_Radio_Config, if_name); + OVSDB_TABLE_INIT(DHCP_reserved_IP, hw_addr); + + // Check feature enable flag (persistent): + if (gw_offline_ps_load(PS_KEY_OFFLINE_CFG, &json_en) && json_en != NULL) + { + const char *en_value; + if ((en_value = json_string_value(json_object_get(json_en, "value"))) != NULL) + { + if (strcmp(en_value, VAL_OFFLINE_ON) == 0) + { + gw_offline_cfg = true; + } + } + json_decref(json_en); + } + + if (gw_offline_cfg) + { + LOG(INFO, "offline_cfg: Feature enabled (flag set in persistent storage)"); + pm_node_state_set(KEY_OFFLINE_CFG, VAL_OFFLINE_ON); + + if (pm_gw_offline_cfg_is_available()) + { + LOG(INFO, "offline_cfg: Config available in persistent storage."); + // Indicate the feature is "ready" (enabled && persistent config available): + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_READY); + } + else + { + LOG(INFO, "offline_cfg: Config NOT available in persistent storage."); + // Indicate the feature is "enabled" (but no persistent config available): + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_ENABLED); + } + } + else + { + LOG(DEBUG, "offline_cfg: Feature disabled (flag not set or not present in persistent storage)"); + } + + // Always install Node_Config monitor, other monitors installed when enabled. + OVSDB_TABLE_MONITOR(Node_Config, true); +} + +void pm_gw_offline_fini(void) +{ + LOG(INFO, "offline_cfg: %s()", __func__); +} + +static bool gw_offline_ps_store(const char *ps_key, const json_t *config) +{ + ssize_t str_size; + bool rv = false; + char *config_str = NULL; + osp_ps_t *ps = NULL; + + if (config == NULL) + return true; + + ps = osp_ps_open(PS_STORE_GW_OFFLINE, OSP_PS_RDWR); + if (ps == NULL) + { + LOG(ERR, "offline_cfg: Error opening %s persistent store.", PS_STORE_GW_OFFLINE); + goto exit; + } + LOG(DEBUG, "offline_cfg: Persisten storage %s opened", PS_STORE_GW_OFFLINE); + + config_str = json_dumps(config, JSON_COMPACT); + if (config_str == NULL) + { + LOG(ERR, "offline_cfg: Error converting %s JSON to string.", ps_key); + goto exit; + } + + str_size = (ssize_t)strlen(config_str) + 1; + if (osp_ps_set(ps, ps_key, config_str, (size_t)str_size) < str_size) + { + LOG(ERR, "offline_cfg: Error storing %s to persistent storage.", ps_key); + goto exit; + } + LOG(DEBUG, "offline_cfg: Stored %s to persistent storage %s.", ps_key, PS_STORE_GW_OFFLINE); + + rv = true; +exit: + if (config_str != NULL) json_free(config_str); + if (ps != NULL) osp_ps_close(ps); + return rv; +} + +/* Store config to persistent storage. */ +static bool gw_offline_cfg_ps_store(const struct gw_offline_cfg *cfg) +{ + bool rv; + + if (!json_equal(cfg->vif_config, cfg_cache.vif_config)) + { + rv = gw_offline_ps_store(PS_KEY_VIF_CONFIG, cfg->vif_config); + if (!rv) goto exit; + json_decref(cfg_cache.vif_config); + cfg_cache.vif_config = json_incref(cfg->vif_config); + } else LOG(DEBUG, "offline_cfg: vif_config: cached==stored. Skipped storing."); + + if (!json_equal(cfg->inet_config, cfg_cache.inet_config)) + { + rv = gw_offline_ps_store(PS_KEY_INET_CONFIG, cfg->inet_config); + if (!rv) goto exit; + json_decref(cfg_cache.inet_config); + cfg_cache.inet_config = json_incref(cfg->inet_config); + } else LOG(DEBUG, "offline_cfg: inet_config: cached==stored. Skipped storing."); + + if (!json_equal(cfg->radio_config, cfg_cache.radio_config)) + { + rv = gw_offline_ps_store(PS_KEY_RADIO_CONFIG, cfg->radio_config); + if (!rv) goto exit; + json_decref(cfg_cache.radio_config); + cfg_cache.radio_config = json_incref(cfg->radio_config); + } else LOG(DEBUG, "offline_cfg: radio_config: cached==stored. Skipped storing."); + + if (!json_equal(cfg->inet_config_home_aps, cfg_cache.inet_config_home_aps)) + { + rv = gw_offline_ps_store(PS_KEY_INET_CONFIG_HOME_APS, cfg->inet_config_home_aps); + if (!rv) goto exit; + json_decref(cfg_cache.inet_config_home_aps); + cfg_cache.inet_config_home_aps = json_incref(cfg->inet_config_home_aps); + } else LOG(DEBUG, "offline_cfg: inet_config_home_aps: cached==stored. Skipped storing."); + + if (!json_equal(cfg->radio_if_names, cfg_cache.radio_if_names)) + { + rv = gw_offline_ps_store(PS_KEY_RADIO_IF_NAMES, cfg->radio_if_names); + if (!rv) goto exit; + json_decref(cfg_cache.radio_if_names); + cfg_cache.radio_if_names = json_incref(cfg->radio_if_names); + } else LOG(DEBUG, "offline_cfg: radio_if_names: cached==stored. Skipped storing."); + + if (!json_equal(cfg->dhcp_reserved_ip, cfg_cache.dhcp_reserved_ip)) + { + rv = gw_offline_ps_store(PS_KEY_DHCP_RESERVED_IP, cfg->dhcp_reserved_ip); + if (!rv) goto exit; + json_decref(cfg_cache.dhcp_reserved_ip); + cfg_cache.dhcp_reserved_ip = json_incref(cfg->dhcp_reserved_ip); + } else LOG(DEBUG, "offline_cfg: dhcp_reserved_ip: cached==stored. Skipped storing."); + +exit: + return rv; +} + +static bool gw_offline_ps_load(const char *ps_key, json_t **config) +{ + ssize_t str_size; + bool rv = false; + char *config_str = NULL; + json_t *config_json = NULL; + osp_ps_t *ps = NULL; + + ps = osp_ps_open(PS_STORE_GW_OFFLINE, OSP_PS_RDWR); + if (ps == NULL) + { + LOG(DEBUG, "offline_cfg: Failed opening %s persistent store. It may not exist yet.", + PS_STORE_GW_OFFLINE); + goto exit; + } + LOG(DEBUG, "offline_cfg: Persisten storage %s opened", PS_STORE_GW_OFFLINE); + + str_size = osp_ps_get(ps, ps_key, NULL, 0); + if (str_size < 0) + { + LOG(ERR, "offline_cfg: Error fetching %s key size.", ps_key); + goto exit; + } + else if (str_size == 0) + { + LOG(DEBUG, "offline_cfg: Read 0 bytes for %s from persistent storage. The record does not exist yet.", ps_key); + rv = true; + goto exit; + } + + /* Fetch the "config" data */ + config_str = malloc((size_t)str_size); + if (osp_ps_get(ps, ps_key, config_str, (size_t)str_size) != str_size) + { + LOG(ERR, "offline_cfg: Error retrieving persistent %s key.", ps_key); + goto exit; + } + LOG(DEBUG, "offline_cfg: Loaded %s string from persistent storage. str=%s", ps_key, config_str); + + /* Convert it to JSON */ + config_json = json_loads(config_str, 0, NULL); + if (config_json == NULL) + { + LOG(ERR, "offline_cfg: Error parsing JSON: %s", config_str); + goto exit; + } + LOG(DEBUG, "offline_cfg: Loaded %s json from persistent storage %s.", ps_key, PS_STORE_GW_OFFLINE); + + *config = config_json; + rv = true; +exit: + if (config_str != NULL) free(config_str); + if (ps != NULL) osp_ps_close(ps); + + return rv; +} + +/* Load config from persistent storage. */ +static bool gw_offline_cfg_ps_load(struct gw_offline_cfg *cfg) +{ + bool rv = false; + + rv = gw_offline_ps_load(PS_KEY_VIF_CONFIG, &cfg->vif_config); + if (!rv) goto exit; + json_decref(cfg_cache.vif_config); + cfg_cache.vif_config = json_incref(cfg->vif_config); + + rv = gw_offline_ps_load(PS_KEY_INET_CONFIG, &cfg->inet_config); + if (!rv) goto exit; + json_decref(cfg_cache.inet_config); + cfg_cache.inet_config = json_incref(cfg->inet_config); + + rv = gw_offline_ps_load(PS_KEY_RADIO_CONFIG, &cfg->radio_config); + if (!rv) goto exit; + json_decref(cfg_cache.radio_config); + cfg_cache.radio_config = json_incref(cfg->radio_config); + + rv = gw_offline_ps_load(PS_KEY_INET_CONFIG_HOME_APS, &cfg->inet_config_home_aps); + if (!rv) goto exit; + json_decref(cfg_cache.inet_config_home_aps); + cfg_cache.inet_config_home_aps = json_incref(cfg->inet_config_home_aps); + + rv = gw_offline_ps_load(PS_KEY_RADIO_IF_NAMES, &cfg->radio_if_names); + if (!rv) goto exit; + json_decref(cfg_cache.radio_if_names); + cfg_cache.radio_if_names = json_incref(cfg->radio_if_names); + + rv = gw_offline_ps_load(PS_KEY_DHCP_RESERVED_IP, &cfg->dhcp_reserved_ip); + if (!rv) goto exit; + json_decref(cfg_cache.dhcp_reserved_ip); + cfg_cache.dhcp_reserved_ip = json_incref(cfg->dhcp_reserved_ip); + +exit: + return rv; +} + +/* Read the current subset of OVSDB config. */ +static bool gw_offline_cfg_ovsdb_read(struct gw_offline_cfg *cfg) +{ + size_t index; + json_t *json_res; + json_t *row; + + memset(cfg, 0, sizeof(*cfg)); + + /* Select home AP VIFs from Wifi_VIF_Config: */ + cfg->vif_config = ovsdb_sync_select("Wifi_VIF_Config", "bridge", LAN_BRIDGE); + if (cfg->vif_config == NULL) + { + LOG(ERR, "offline_cfg: Error selecting from Wifi_VIF_Config"); + goto exit_failure; + } + + /* For each home AP: find a corresponding entry in Wifi_Inet_Config: */ + json_array_foreach(cfg->vif_config, index, row) + { + const char *if_name = json_string_value(json_object_get(row, "if_name")); + + json_res = ovsdb_sync_select("Wifi_Inet_Config", "if_name", if_name); + if (json_res == NULL || json_array_size(json_res) != 1) + { + LOG(ERR, "offline_cfg: Error selecting from Wifi_Inet_Config"); + goto exit_failure; + } + if (cfg->inet_config_home_aps == NULL) + cfg->inet_config_home_aps = json_array(); + + json_array_append(cfg->inet_config_home_aps, json_array_get(json_res, 0)); + json_decref(json_res); + } + + /* lan bridge config from Wifi_Inet_Config: */ + cfg->inet_config = ovsdb_sync_select("Wifi_Inet_Config", "if_name", LAN_BRIDGE); + if (cfg->inet_config == NULL) + { + LOG(ERR, "offline_cfg: Error selecting from Wifi_Inet_Config"); + goto exit_failure; + } + + /* Remember radio config: */ + cfg->radio_config = ovsdb_sync_select_where("Wifi_Radio_Config", NULL); + if (cfg->radio_config == NULL) + { + LOG(ERR, "offline_cfg: Error selecting from Wifi_Radio_Config"); + goto exit_failure; + } + + /* Determine and save radio if_names for VIFs: */ + gw_offline_cfg_set_radio_if_names(cfg); + + /* Cleanup values in Wifi_Radio_Config that should not be stored: */ + gw_offline_cfg_cleanup_radio_config(cfg); + + /* DHCP reservations: */ + cfg->dhcp_reserved_ip = ovsdb_sync_select_where("DHCP_reserved_IP", NULL); + if (cfg->dhcp_reserved_ip == NULL) + { + LOG(DEBUG, "offline_cfg: DHCP_reserved_IP: NO rows in the table or error."); + cfg->dhcp_reserved_ip = json_array(); + } + + /* Delete special ovsdb keys like _uuid, etc, these should not be stored: */ + gw_offline_cfg_delete_special_keys(cfg); + + return true; +exit_failure: + gw_offline_cfg_release(cfg); + return false; +} + +/* Apply the provided subset of config (obtained from persistent storage) to OVSDB. */ +static bool gw_offline_cfg_ovsdb_apply(const struct gw_offline_cfg *cfg) +{ + ovs_uuid_t uuid; + size_t index; + int rc; + json_t *row; + + /* Update inet config: */ + if ((rc = ovsdb_sync_update("Wifi_Inet_Config", "if_name", LAN_BRIDGE, + json_array_get(cfg->inet_config, 0))) != 1) + { + LOG(ERR, "offline_cfg: Error updating Wifi_Inet_Config, rc=%d", rc); + return false; + } + LOG(DEBUG, "offline_cfg: Updated %d row(s) in Wifi_Inet_Config", rc); + + /* Update radio config: */ + json_array_foreach(cfg->radio_config, index, row) + { + const char *if_name = json_string_value(json_object_get(row, "if_name")); + + if (ovsdb_sync_update("Wifi_Radio_Config", "if_name", if_name, row) == -1) + { + LOG(ERR, "offline_cfg: Error updating Wifi_Radio_Config"); + return false; + } + } + + /* Create VIF interfaces... */ + json_array_foreach(cfg->vif_config, index, row) + { + const char *if_name = json_string_value(json_object_get(row, "if_name")); + + /* Insert a row for this VIF: */ + if (ovsdb_sync_insert("Wifi_VIF_Config", row, &uuid)) + { + /* Add created vif uuid to Wifi_Radio_Config... */ + const char *radio_if_name = json_string_value(json_array_get(cfg->radio_if_names, index)); + LOG(DEBUG, "offline_cfg: if_name=%s is at radio_if_name=%s", if_name, radio_if_name); + ovsdb_add_uuid_to_radio_config(radio_if_name, uuid); + + /* Add this home VIF interface to lan bridge: */ + char cmd_buf[1024]; + sprintf(cmd_buf, "ovs-vsctl add-port %s %s", LAN_BRIDGE, if_name); + + LOG(DEBUG, "offline_cfg: :::: Executing shell cmd: %s", cmd_buf); + rc = system(cmd_buf); + if (WIFEXITED(rc) && WEXITSTATUS(rc) == 0) + LOG(INFO, "offline_cfg: ovs-vsctl: added %s to %s", if_name, LAN_BRIDGE); + else + LOG(ERR, "offline_cfg: ovs-vsctl: Error adding %s to %s", if_name, LAN_BRIDGE); + } + else + { + LOG(ERR, "offline_cfg: Error inserting into Wifi_VIF_Config: row=%s", json_dumps_static(row, 0)); + return false; + } + } + + /* Add home-aps entries to Wifi_Inet_Config... */ + json_array_foreach(cfg->inet_config_home_aps, index, row) + { + if (!ovsdb_sync_insert("Wifi_Inet_Config", row, NULL)) + { + LOG(ERR, "offline_cfg: Error inserting into Wifi_Inet_Config: row=%s", json_dumps_static(row, 0)); + return false; + } + } + + /* Configure DHCP reservations: */ + json_array_foreach(cfg->dhcp_reserved_ip, index, row) + { + if (!ovsdb_sync_insert("DHCP_reserved_IP", row, NULL)) + { + LOG(ERR, "offline_cfg: Error inserting into DHCP_reserved_IP: row=%s", json_dumps_static(row, 0)); + return false; + } + } + + return true; +} + +/* Is persistent-storage config available? */ +bool pm_gw_offline_cfg_is_available() +{ + struct gw_offline_cfg gw_cfg = { 0 }; + bool avail = false; + bool rv; + + rv = gw_offline_cfg_ps_load(&gw_cfg); + if (!rv) goto exit; + do + { + // The following have to be present to declare availability: + if (gw_cfg.vif_config == NULL || json_array_size(gw_cfg.vif_config) == 0) + break; + if (gw_cfg.inet_config == NULL || json_array_size(gw_cfg.inet_config) == 0) + break; + if (gw_cfg.radio_config == NULL || json_array_size(gw_cfg.radio_config) == 0) + break; + if (gw_cfg.inet_config_home_aps == NULL || json_array_size(gw_cfg.inet_config_home_aps) == 0) + break; + if (gw_cfg.radio_if_names == NULL || json_array_size(gw_cfg.radio_if_names) == 0) + break; + + avail = true; + } while (0); + +exit: + gw_offline_cfg_release(&gw_cfg); + return avail; +} + +/* Read current subset of OVSDB config and store it to persistent storage. */ +bool pm_gw_offline_read_and_store_config() +{ + struct gw_offline_cfg gw_cfg = { 0 }; + bool rv = false; + + if (!(gw_offline_cfg && gw_offline_mon)) + { + LOG(TRACE, "%s() called, but gw_offline_cfg=%d, gw_offline_mon=%d. Ignoring.", + __func__, gw_offline_cfg, gw_offline_mon); + return false; + } + + /* Read subset of current ovsdb config: */ + if (!gw_offline_cfg_ovsdb_read(&gw_cfg)) + { + LOG(ERR, "offline_cfg: Error reading current config."); + goto exit; + } + LOG(INFO, "offline_cfg: Read config from OVSDB."); + + /* Store the config to persistent storage: */ + if (!gw_offline_cfg_ps_store(&gw_cfg)) + { + LOG(ERR, "offline_cfg: Error storing current config."); + goto exit; + } + LOG(INFO, "offline_cfg: Stored current config to persistent storage."); + + rv = true; +exit: + /* Indicate to CM that peristent storage is "ready": */ + if (rv) + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_READY); + else + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_ERROR); + + gw_offline_cfg_release(&gw_cfg); + return rv; +} + +/* Load persistent storage config and apply config to OVSDB. */ +bool pm_gw_offline_load_and_apply_config() +{ + struct gw_offline_cfg gw_cfg = { 0 }; + bool rv = false; + + if (!(gw_offline_cfg && gw_offline)) + { + LOG(WARN, "offline_cfg: %s() should only be triggered (by CM) via Node_Config " + "(when the feature is enabled). Ignoring.", __func__); + return false; + } + + /* Load config from persistent storage: */ + if (!gw_offline_cfg_ps_load(&gw_cfg)) + { + LOG(ERR, "offline_cfg: Error loading config from persistent storage."); + goto exit; + } + LOG(INFO, "offline_cfg: Loaded stored config from persistent storage."); + + /* Apply the stored config to OVSDB: */ + if (!gw_offline_cfg_ovsdb_apply(&gw_cfg)) + { + LOG(ERR, "offline_cfg: Error applying stored config to OVSDB."); + goto exit; + } + LOG(INFO, "offline_cfg: Applied config to OVSDB."); + + rv = true; +exit: + gw_offline_cfg_release(&gw_cfg); + + if (rv) + { + /* Indicate in Node_State that the feature is "active" + * (enabled && ps config applied): */ + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_ACTIVE); + } + else + { + /* Indicate error in Node_State: */ + pm_node_state_set(KEY_OFFLINE_STATUS, VAL_STATUS_ERROR); + } + + return rv; +} diff --git a/src/pm/src/pm_led.c b/src/pm/src/pm_led.c index 1aecd38b..dc3babb4 100644 --- a/src/pm/src/pm_led.c +++ b/src/pm/src/pm_led.c @@ -31,14 +31,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "log.h" +#include "util.h" #include "ovsdb.h" #include "schema.h" #include "ovsdb_table.h" #include "json_util.h" -#include "osp.h" #include "pm.h" -#include "target.h" #define PM_LED_TS_FILE "/tmp/pm.led.ts" diff --git a/src/pm/src/pm_lm.c b/src/pm/src/pm_lm.c index 47579921..0c7debdf 100644 --- a/src/pm/src/pm_lm.c +++ b/src/pm/src/pm_lm.c @@ -68,7 +68,10 @@ ovsdb_table_t table_AW_LM_Config; ovsdb_table_t table_AW_Debug; -static void pm_lm_do_log_pull(char *upload_token, char *upload_location) +static void pm_lm_do_log_pull( + const char *upload_token, + const char *upload_location, + const char *upload_method) { // check presence of necessary data in order to execute log-pull if (!strlen(upload_token) || !strlen(upload_location)) { @@ -78,7 +81,7 @@ static void pm_lm_do_log_pull(char *upload_token, char *upload_location) LOGN("LM: Run log-pull procedure."); - if (!target_log_pull(upload_location, upload_token)) { + if (!target_log_pull_ext(upload_location, upload_token, upload_method)) { LOGE("LM: Log-pull procedure failed!"); } } @@ -88,8 +91,10 @@ static void callback_AW_LM_Config( struct schema_AW_LM_Config *old_rec, struct schema_AW_LM_Config *config) { - if (mon->mon_type == OVSDB_UPDATE_MODIFY) { - pm_lm_do_log_pull(config->upload_token, config->upload_location); + if (mon->mon_type == OVSDB_UPDATE_MODIFY || + mon->mon_type == OVSDB_UPDATE_NEW) { + /* AW_LM_Config::name is used to define logpull upload method. */ + pm_lm_do_log_pull(config->upload_token, config->upload_location, config->name); } } diff --git a/src/pm/src/pm_main.c b/src/pm/src/pm_main.c index 803eb6aa..5a436548 100644 --- a/src/pm/src/pm_main.c +++ b/src/pm/src/pm_main.c @@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "log.h" #include "ovsdb.h" #include "schema.h" +#include "module.h" #include "ovsdb_table.h" #include "json_util.h" @@ -87,6 +88,13 @@ static bool pm_init(void) } #endif +#if CONFIG_PM_ENABLE_OBJM + if (!pm_objm_init()) + { + return false; + } +#endif + return true; } @@ -146,8 +154,15 @@ int main(int argc, char *argv[]) return -1; } + /* Start all modules */ + LOG(NOTICE, "Initializing modules..."); + module_init(); + ev_run(loop, 0); + /* Stop all modules */ + module_fini(); + pm_deinit(loop); return 0; diff --git a/src/pm/src/pm_objm.c b/src/pm/src/pm_objm.c new file mode 100644 index 00000000..6c5ce94f --- /dev/null +++ b/src/pm/src/pm_objm.c @@ -0,0 +1,849 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "const.h" +#include "log.h" +#include "ovsdb.h" +#include "schema.h" +#include "ovsdb_table.h" +#include "json_util.h" + +#include "oms.h" +#include "oms_report.h" + +#include "osp_ps.h" +#include "osp_objm.h" +#include "osp_dl.h" + +#include "pm.h" +#include "pm_objm.h" + +/* + * Generate the PJS structures + */ +#include "pm_objm_pjs.h" +#include "pjs_gen_h.h" + +#include "pm_objm_pjs.h" +#include "pjs_gen_c.h" + +static ovsdb_table_t table_Object_Store_Config; +static ovsdb_table_t table_AWLAN_Node; +//static struct pm_objm_ctx_t objm_ctx; + +struct ev_async ev_install_async; + +// Global list of installed pm_objects +static struct pm_objm_store db; + + +static void pm_ctx_to_oms_config(struct oms_config_entry *entry, struct pm_objm_ctx_t *ctx); +static void pm_ctx_to_oms_state(struct oms_state_entry *entry, struct pm_objm_ctx_t *ctx); +static void oms_state_to_pm_ctx(struct pm_objm_ctx_t *ctx, struct oms_state_entry *entry); +static void oms_state_to_oms_config(struct oms_state_entry *c_entry, struct oms_config_entry *s_entry); + + +/****************************************************************************** + * Support functions for interacting with persistent storage + *****************************************************************************/ + +// Load object database from presistent storage +static bool pm_objm_ps_load(struct pm_objm_store *st) +{ + pjs_errmsg_t perr; + ssize_t strsz; + + bool retval = false; + osp_ps_t *ps = NULL; + json_t *json = NULL; + char *str = NULL; + + memset(st, 0, sizeof(*st)); + + ps = osp_ps_open(PM_OBJM_STORAGE, OSP_PS_RDWR); + if (ps == NULL) + { + LOG(ERR, "objm: Unable to open \"%s\" store.", + PM_OBJM_STORAGE); + goto exit; + } + + // Load and parse the object structure + strsz = osp_ps_get(ps, PM_OBJM_KEY, NULL, 0); + if (strsz < 0) + { + LOG(ERR, "objm: Error fetching \"%s\" key size.", + PM_OBJM_KEY); + retval = false; + goto exit; + } + else if (strsz == 0) + { + // The record does not exist yet + retval = true; + goto exit; + } + + // Fetch the "store" data + str = malloc((size_t)strsz); + if (osp_ps_get(ps, PM_OBJM_KEY, str, (size_t)strsz) != strsz) + { + LOG(ERR, "objm: Error retrieving persistent \"%s\" key.", + PM_OBJM_KEY); + goto exit; + } + + // Convert it to JSON + json = json_loads(str, 0, NULL); + if (json == NULL) + { + LOG(ERR, "objm: Error parsing JSON: %s", str); + goto exit; + } + + // Convert it to C struct + if (!pm_objm_store_from_json(st, json, false, perr)) + { + memset(st, 0, sizeof(*st)); + LOG(ERR, "objm: Error parsing pm_objm_store record: %s", perr); + goto exit; + } + + retval = true; + +exit: + if (str != NULL) free(str); + if (json != NULL) json_decref(json); + if (ps != NULL) osp_ps_close(ps); + + return retval; +} + +// Store the object database to persistent storage +static bool pm_objm_ps_save(struct pm_objm_store *st) +{ + pjs_errmsg_t perr; + ssize_t strsz; + + bool retval = false; + osp_ps_t *ps = NULL; + json_t *json = NULL; + char *str = NULL; + + // Open persistent storage in read-write mode + ps = osp_ps_open(PM_OBJM_STORAGE, OSP_PS_RDWR); + if (ps == NULL) + { + LOG(ERR, "objm: Error opening \"%s\" persistent store.", + PM_OBJM_STORAGE); + goto exit; + } + + // Convert the structure to JSON + json = pm_objm_store_to_json(st, perr); + if (json == NULL) + { + LOG(ERR, "objm: Error converting pm_objm_store structure to JSON: %s", perr); + goto exit; + } + + LOG(DEBUG, "objm_store records len= %d", st->obj_records_len); + { + int ii; + for (ii = 0; ii < st->obj_records_len; ii++) + { + LOG(DEBUG, "objm: obj[%d].name: %s", ii, st->obj_records[ii].name); + LOG(DEBUG, "objm: obj[%d].version: %s", ii, st->obj_records[ii].version); + } + } + + // Convert the reboot structure to string + str = json_dumps(json, JSON_COMPACT); + if (str == NULL) + { + LOG(ERR, "objm: Error converting JSON to string."); + goto exit; + } + + // Store the string representation to peristent storage + strsz = (ssize_t)strlen(str) + 1; + if (osp_ps_set(ps, PM_OBJM_KEY, str, (size_t)strsz) < strsz) + { + LOG(ERR, "objm: Error storing object records: %s", str); + goto exit; + } + + retval = true; + +exit: + if (str != NULL) json_free(str); + if (json != NULL) json_decref(json); + if (ps != NULL) osp_ps_close(ps); + + return retval; +} + +static bool pm_objm_ps_add(struct pm_objm_store *st, char *name, char *version, bool fw_integrated) +{ + // Append object to database + int dbl = st->obj_records_len; + + if (dbl == ARRAY_LEN(st->obj_records)) + { + LOG(ERR, "objm: Max size of saved objects reached: %d", dbl); + } + + STRSCPY(st->obj_records[dbl].name, name); + STRSCPY(st->obj_records[dbl].version, version); + st->obj_records[dbl].fw_integrated = fw_integrated; + st->obj_records_len = dbl + 1; + + return pm_objm_ps_save(st); +} +/* + * Remove object from object database + * + * Object database is implemented as array. Cleanest way to remove an element and not have + * any free spots in array is to remove mentioned element and move last element to removed + * element position. This is possible since order of element does not matter. + * + * */ +static bool pm_objm_ps_remove(struct pm_objm_store *st, char *name, char *version) +{ + int i; + int last; + bool found = false; + + LOG(DEBUG, "objm: remove %s version %s from db", name, version); + + for (i = 0; i < st->obj_records_len; i++) + { + if (strcmp(st->obj_records[i].name, name) == 0 && + strcmp(st->obj_records[i].version, version) == 0) + { + found = true; + break; + } + } + + if (!found) + { + LOG(ERR, "objm: Object %s:%s not found", name, version); + return false; + } + + // Move last element to removed element position + last = st->obj_records_len - 1; + STRSCPY_WARN(st->obj_records[i].name, st->obj_records[last].name); + STRSCPY_WARN(st->obj_records[i].version, st->obj_records[last].version); + st->obj_records[i].fw_integrated = st->obj_records[last].fw_integrated; + st->obj_records_len -= 1; + + pm_objm_ps_save(st); + return true; +} + +// Check if object name and version is preintegrated in fw or not. +static bool pm_objm_ps_is_fw_integrated(struct pm_objm_store *st, char *name, char *version) +{ + int i; + bool found = false; + + LOG(DEBUG, "objm: Check if %s version %s is preintegrated", name, version); + + for (i = 0; i < st->obj_records_len; i++) + { + if (strcmp(st->obj_records[i].name, name) == 0 && + strcmp(st->obj_records[i].version, version) == 0) + { + found = true; + break; + } + } + + if (!found) + { + LOG(ERR, "objm: Object %s:%s not found", name, version); + return false; + } + + return st->obj_records[i].fw_integrated; +} + +static bool pm_objm_obj_exist(struct pm_objm_store *st, char *name, char *version) +{ + int i; + + for (i = 0; i < st->obj_records_len; i++) + { + if (strcmp(st->obj_records[i].name, name) == 0 && + strcmp(st->obj_records[i].version, version) == 0) + { + return true; + } + } + return false; +} +/****************************************************************************** + * Support functions for interacting with OVSDB tables + *****************************************************************************/ + +static bool pm_objm_ovsdb_insert_objstore_config(struct pm_objm_ctx_t *d_ctx) +{ + struct schema_Object_Store_Config store; + + if (d_ctx->fw_integrated) + { + LOG(DEBUG, "objm: Skip inserting fw integrated object to Object_Store_Config table: %s", d_ctx->name); + return true; + } + + memset(&store, 0, sizeof(store)); + store._partial_update = true; + SCHEMA_SET_STR(store.name, d_ctx->name); + SCHEMA_SET_STR(store.version, d_ctx->version); + + return ovsdb_table_insert(&table_Object_Store_Config, &store); +} + +static bool pm_objm_get_mqtt_topic(char *buf, size_t bufsize) +{ + struct schema_AWLAN_Node *aw_node; + void *aw_node_p; + + int count; + int i; + bool ret = false; + + aw_node_p = ovsdb_table_select_where(&table_AWLAN_Node, + NULL, + &count); + if (count != 1) + { + LOG(ERR, "objm: AWLAN_Node has %d rows - expected 1", count); + ret = false; + goto cleanup; + } + + aw_node = (struct schema_AWLAN_Node*)aw_node_p; + + for (i = 0; i < aw_node->mqtt_topics_len; i++) + { + if (strcmp(aw_node->mqtt_topics_keys[i], PM_OBJM_MQTT) == 0) + { + strncpy(buf, aw_node->mqtt_topics[i], bufsize); + ret = true; + goto cleanup; + } + } +cleanup: + if (aw_node_p) free(aw_node_p); + return ret; +} + +/****************************************************************************** + * Install of package functions + *****************************************************************************/ + +static bool install(struct pm_objm_ctx_t *d_ctx) +{ + struct oms_config_entry c_entry; + struct oms_state_entry s_entry; + + if (!d_ctx->fw_integrated) + { + // If object is fw_integrated don't use osp_objm_install function since + // object is already preinstalled. + if (!osp_objm_install(d_ctx->dl_path, d_ctx->name, d_ctx->version)) + { + LOG(ERR, "objm: Install failed"); + STRSCPY_WARN(d_ctx->status, PM_OBJS_INSTALL_FAILED); + goto install_failed; + } + } + + LOG(INFO, "objm: Successful installation of object: name: %s version: %s preintegrated: %s", + d_ctx->name, + d_ctx->version, + d_ctx->fw_integrated ? "true" : "false"); + + if (!pm_objm_ps_add(&db, d_ctx->name, d_ctx->version, d_ctx->fw_integrated)) + { + LOG(ERR, "objm: Unable to store object info to database"); + STRSCPY_WARN(d_ctx->status, PM_OBJS_INSTALL_FAILED); + goto install_failed; + } + + STRSCPY_WARN(d_ctx->status, PM_OBJS_INSTALLED); + + // Insert to Object_Store_State + pm_ctx_to_oms_state(&s_entry, d_ctx); + oms_add_state_entry(&s_entry); + + // Update OMS_Config table + pm_ctx_to_oms_config(&c_entry, d_ctx); + oms_add_config_entry(&c_entry); + + return true; + +install_failed: + // Insert to Object_Store_State + pm_ctx_to_oms_state(&s_entry, d_ctx); + oms_add_state_entry(&s_entry); + return false; +} + +static void install_async(EV_P_ ev_async *w, int revents) +{ + struct pm_objm_ctx_t *d_ctx = w->data; + + // Clear url and timeout regardless of success or failure of download + STRSCPY_WARN(d_ctx->url, ""); + d_ctx->timeout = 0; + + install(d_ctx); + free(d_ctx); +} + +static int install_integrated_objects(char *path) +{ + DIR *udir; + FILE *fd; + struct pm_objm_ctx_t file_ctx; + struct dirent *next_file; + int obj_count = 0; + char *name_buf; + char info_path[128]; + char *line = NULL; + size_t len = 0; + + LOG(DEBUG, "objm: Checking %s for pre-integrated objects", path); + udir = opendir(path); + + if (udir != NULL) + { + while ((next_file = readdir(udir)) != NULL) + { + if (next_file->d_type == DT_REG) + { + memset(&file_ctx, 0, sizeof(struct pm_objm_ctx_t)); + name_buf = NULL; + + LOG(DEBUG, "objm: About to install %s", next_file->d_name); + if (strstr(next_file->d_name, ".info") == NULL) + { + LOG(DEBUG, "objm: %s not a info file", next_file->d_name); + continue; + } + + name_buf = strdup(next_file->d_name); + + // Open info file of the package + sprintf(info_path, "%s/%s", path, name_buf); + free(name_buf); + LOG(DEBUG, "objm: Reading info file %s", info_path); + fd = fopen(info_path, "r"); + if (fd == NULL) + { + LOG(ERR, "objm: no info file found %s", info_path); + continue; + } + + while (getline(&line, &len, fd) != -1) + { + if (strstr(line, "name") != NULL) + { + sscanf(line, "name:%s", file_ctx.name); + } + + if (strstr(line, "version") != NULL) + { + sscanf(line, "version:%s", file_ctx.version); + } + } + fclose(fd); + + file_ctx.fw_integrated = true; + + if (install(&file_ctx) == false) + { + LOG(ERR, "objm: %s failed to install", next_file->d_name); + continue; + } + LOG(NOTICE, "objm: %s installed %s", file_ctx.name, file_ctx.version); + obj_count++; + } + } + closedir(udir); + } + return obj_count; +} + +/****************************************************************************** + * Removal of package functions + *****************************************************************************/ + +static void object_remove(struct pm_objm_ctx_t *d_ctx) +{ + struct oms_config_entry c_entry; + struct oms_state_entry s_entry; + + // Check if object is preintegrated + if (pm_objm_ps_is_fw_integrated(&db, d_ctx->name, d_ctx->version)) + { + LOG(INFO, "Object is preintegrated - skip removing %s %s", d_ctx->name, d_ctx->version); + return; + } + + // Remove complete "path" folder trough osp_objm_remove api + if (!osp_objm_remove(d_ctx->name, d_ctx->version)) + { + LOG(ERR, "objm: remove from storage failed"); + return; + } + // Remove Object information from persistant storage + pm_objm_ps_remove(&db, d_ctx->name, d_ctx->version); + + // Remove entry from OMS_Config for final user to process + pm_ctx_to_oms_state(&s_entry, d_ctx); + oms_delete_state_entry(&s_entry); + + // Remove entry from OMS_Config for final user to process + pm_ctx_to_oms_config(&c_entry, d_ctx); + oms_delete_config_entry(&c_entry); + LOG(INFO, "objm: Successful removal of object: %s version: %s", + d_ctx->name, + d_ctx->version); +} + + +/****************************************************************************** + * Download of package functions + *****************************************************************************/ + +static void cb_dl(const enum osp_dl_status status, void *ctx) +{ + struct oms_state_entry s_entry; + struct pm_objm_ctx_t *d_ctx = (struct pm_objm_ctx_t*)ctx; + + LOG(DEBUG, "objm: (%s) status: %d", __func__, status); + if (status != OSP_DL_OK) + { + LOG(ERR, "Download failed"); + STRSCPY_WARN(d_ctx->status, PM_OBJS_DOWNLOAD_FAILED); + // Insert to Object_Store_State + pm_ctx_to_oms_state(&s_entry, d_ctx); + oms_add_state_entry(&s_entry); + + free(d_ctx); + return; + } + STRSCPY_WARN(d_ctx->status, PM_OBJS_DOWNLOAD_DONE); + + // Insert to Object_Store_State + pm_ctx_to_oms_state(&s_entry, d_ctx); + oms_add_state_entry(&s_entry); + + // Call ev_async to start install + ev_install_async.data = d_ctx; + ev_async_send(EV_DEFAULT, &ev_install_async); +} + +static void start_download(struct schema_Object_Store_Config *new) +{ + struct oms_state_entry s_entry; + // Fill ctx struct + struct pm_objm_ctx_t *d_ctx; + d_ctx = malloc(sizeof(struct pm_objm_ctx_t)); + + d_ctx->fw_integrated = false; + d_ctx->timeout = new->dl_timeout; + STRSCPY_WARN(d_ctx->url, new->dl_url); + STRSCPY_WARN(d_ctx->name, new->name); + STRSCPY_WARN(d_ctx->version, new->version); + sprintf(d_ctx->dl_path, "%s/%s", CONFIG_PM_OBJM_DOWNLOAD_DIR, basename(d_ctx->url)); + STRSCPY_WARN(d_ctx->status, PM_OBJS_DOWNLOAD_STARTED); + + if (!osp_dl_download(d_ctx->url, CONFIG_PM_OBJM_DOWNLOAD_DIR, d_ctx->timeout, cb_dl, d_ctx)) + { + LOG(ERR, "objm: failed to start osp_dl_download api"); + STRSCPY_WARN(d_ctx->status, PM_OBJS_DOWNLOAD_FAILED); + } + + // Insert to Object_Store_State + pm_ctx_to_oms_state(&s_entry, d_ctx); + oms_add_state_entry(&s_entry); +} + + +/****************************************************************************** + * OVSDB monitor callback functions + *****************************************************************************/ + +// Registered callback for Node_Config events +static void callback_Object_Store_Config(ovsdb_update_monitor_t *mon, + struct schema_Object_Store_Config *old_rec, + struct schema_Object_Store_Config *new) +{ + struct pm_objm_ctx_t rm_ctx; + + switch (mon->mon_type) + { + case OVSDB_UPDATE_NEW: + // If dl_url is empty assume loading object info from + // persistance storage (at boot), no action needed. + if (strcmp(new->dl_url, "") == 0) + { + break; + } + // Check if object already exists + if (pm_objm_obj_exist(&db, new->name, new->version)) + { + LOG(DEBUG, "objm: ignore (%s) object %s,%s already exists", __func__, new->name, new->version); + break; + } + + start_download(new); + break; + + case OVSDB_UPDATE_MODIFY: + // Install new version + if (strcmp(old_rec->version, new->version) == 0) + { + // Ignore update version did not change + LOG(DEBUG, "objm: ignoring (%s) modify - version not changed", __func__); + break; + } + start_download(new); + break; + + case OVSDB_UPDATE_DEL: + // Remove Object information from Object_Store_State table + STRSCPY_WARN(rm_ctx.name, old_rec->name); + STRSCPY_WARN(rm_ctx.version, old_rec->version); + object_remove(&rm_ctx); + break; + + default: + LOG(ERR, "Monitor update error."); + return; + } +} + + +/****************************************************************************** + * OMS lib support functions + *****************************************************************************/ +static void oms_state_cb(struct oms_state_entry *entry, int event) +{ + struct pm_objm_ctx_t d_ctx; + struct oms_config_entry c_entry; + char mqtt_topic[128]; + + LOG(DEBUG, "objm: (%s) event: %d name: %s version: %s state: %s", + __func__, + event, + entry->object, + entry->version, + entry->state); + + switch (event) + { + case OVSDB_UPDATE_NEW: + break; + case OVSDB_UPDATE_MODIFY: + if (strcmp(entry->state, PM_OBJS_OBSOLETE) == 0) + { + oms_state_to_pm_ctx(&d_ctx, entry); + object_remove(&d_ctx); + } + else if (strcmp(entry->state, PM_OBJS_LOAD_FAILED) == 0) + { + // Remove entry from OMS_Config so final user won't try to process it again + LOG(DEBUG, "objm: %s failed to load. Removing from OMS_Config", entry->object); + oms_state_to_oms_config(entry, &c_entry); + oms_delete_config_entry(&c_entry); + oms_free_config_entry(&c_entry); + } + + break; + case OVSDB_UPDATE_DEL: + break; + } + + // Send mqtt report + // Filtering of status to send is done trough oms_report_cb callback + if (!pm_objm_get_mqtt_topic(mqtt_topic, 128)) + { + LOG(ERR, "objm: no mqtt topic '%s' found in AWLAN_Node", PM_OBJM_MQTT); + return; + } + LOG(INFO, "Sending mqtt report to %s", mqtt_topic); + oms_report_send_report(mqtt_topic); + +} + +static bool oms_report_cb(struct oms_state_entry *entry) +{ + bool ret = false; + + if (strcmp(entry->state, PM_OBJS_OBSOLETE) == 0 || + strcmp(entry->state, PM_OBJS_ACTIVE) == 0 || + strcmp(entry->state, PM_OBJS_DOWNLOAD_FAILED) == 0 || + strcmp(entry->state, PM_OBJS_INSTALL_FAILED) == 0 || + strcmp(entry->state, PM_OBJS_LOAD_FAILED) == 0 || + strcmp(entry->state, PM_OBJS_ERROR) == 0 ) + { + ret = true; + } + + LOG(INFO, "objm: object: %s, state: %s, reporting: %s", + entry->object, entry->state, ret ? "true" : "false"); + + return ret; +} + +static void pm_ctx_to_oms_config(struct oms_config_entry *entry, struct pm_objm_ctx_t *ctx) +{ + entry->object = strdup(ctx->name); + entry->version = strdup(ctx->version); +} + +static void oms_state_to_pm_ctx(struct pm_objm_ctx_t *ctx, struct oms_state_entry *entry) +{ + STRSCPY_WARN(ctx->name, entry->object); + STRSCPY_WARN(ctx->version, entry->version); + STRSCPY_WARN(ctx->status, entry->state); +} + +static void pm_ctx_to_oms_state(struct oms_state_entry *entry, struct pm_objm_ctx_t *ctx) +{ + entry->object = strdup(ctx->name); + entry->version = strdup(ctx->version); + entry->state = strdup(ctx->status); + entry->fw_integrated = ctx->fw_integrated; +} + +static void oms_state_to_oms_config(struct oms_state_entry *s_entry, struct oms_config_entry *c_entry) +{ + c_entry->object = strdup(s_entry->object); + c_entry->version = strdup(s_entry->version); +} + + +/****************************************************************************** + * Init functions + *****************************************************************************/ + +static bool pm_objm_ovsdb_init(void) +{ + LOG(DEBUG, "objm: Enable ovsdb monitor of Object_Store_Config"); + OVSDB_TABLE_INIT_NO_KEY(Object_Store_Config); + OVSDB_TABLE_INIT_NO_KEY(AWLAN_Node); + OVSDB_TABLE_MONITOR(Object_Store_Config, false); + return true; +} + +bool pm_objm_init(void) +{ + struct oms_ovsdb_set oms_set; + struct oms_config_entry c_entry; + struct oms_state_entry s_entry; + + static struct pm_objm_ctx_t objm_ctx; + + LOG(NOTICE, "objm: Initializing Object Upgrade"); + + ev_async_init(&ev_install_async, install_async); + ev_install_async.data = &objm_ctx; + ev_async_start(EV_DEFAULT, &ev_install_async); + + if (!pm_objm_ovsdb_init()) { + return false; + } + + oms_init_manager(); + memset(&oms_set, 0, sizeof(oms_set)); + oms_set.monitor_config = false; + oms_set.monitor_state = true; + oms_set.monitor_awlan = true; + oms_set.accept_id = NULL; + oms_set.config_cb = NULL; + oms_set.state_cb = oms_state_cb; + oms_set.report_cb = oms_report_cb; + + oms_ovsdb_init(&oms_set); + + // Load database of installed object from presistent storage + memset(&db, 0, sizeof(struct pm_objm_store)); + if (pm_objm_ps_load(&db) == false) + { + LOG(ERR, "objm: failed to load db from ps"); + return false; + } + + if (db.obj_records_len == 0) + { + LOG(NOTICE, "objm: No objects in persistant database - checking integrated packages"); + if (install_integrated_objects(CONFIG_PM_OBJM_INTEGRATED_DIR) > 0) + { + // Reload database after installing preintegrated packages + if (pm_objm_ps_load(&db) == false) + { + LOG(ERR, "objm: failed to load db from ps"); + return false; + } + } + } + + // Copy database to ovs table (Object_Store_Config) + int ii; + for (ii = 0; ii < db.obj_records_len; ii++) + { + LOG(DEBUG, "objm: pm_obj[%d].name: %s", ii, db.obj_records[ii].name); + LOG(DEBUG, "objm: pm_obj[%d].version: %s", ii, db.obj_records[ii].version); + LOG(DEBUG, "objm: pm_obj[%d].fw_integrated: %d", ii, db.obj_records[ii].fw_integrated); + STRSCPY_WARN(objm_ctx.name, db.obj_records[ii].name); + STRSCPY_WARN(objm_ctx.version, db.obj_records[ii].version); + objm_ctx.fw_integrated = db.obj_records[ii].fw_integrated; + STRSCPY_WARN(objm_ctx.status, PM_OBJS_INSTALLED); + // Insert to Object_Store_Config for cloud + pm_objm_ovsdb_insert_objstore_config(&objm_ctx); + // Insert to Object_Store_State + pm_ctx_to_oms_state(&s_entry, &objm_ctx); + oms_add_state_entry(&s_entry); + // Insert to OMS_Config for final user of object + pm_ctx_to_oms_config(&c_entry, &objm_ctx); + oms_add_config_entry(&c_entry); + } + + LOG(INFO, "objm: %d objects info loaded from persistent storage to ovsdb table Object_Storage", db.obj_records_len); + + return true; +} diff --git a/src/pm/src/pm_tm.c b/src/pm/src/pm_tm.c index 7d876545..79293da6 100644 --- a/src/pm/src/pm_tm.c +++ b/src/pm/src/pm_tm.c @@ -29,11 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "log.h" +#include "util.h" #include "ovsdb.h" -#include "target.h" + #include "pm.h" #include "pm_tm.h" -#include "osp.h" +#include "osp_reboot.h" #define MODULE_ID LOG_MODULE_ID_MAIN diff --git a/src/pm/unit.mk b/src/pm/unit.mk index 62daa350..43680344 100644 --- a/src/pm/unit.mk +++ b/src/pm/unit.mk @@ -37,16 +37,26 @@ $(eval $(if $(CONFIG_PM_ENABLE_CLIENT_FREEZE), UNIT_SRC += src/pm_client_fr $(eval $(if $(CONFIG_PM_ENABLE_CLIENT_NICKNAME), UNIT_SRC += src/pm_client_nickname.c)) $(eval $(if $(CONFIG_PM_ENABLE_LED), UNIT_SRC += src/pm_led.c)) $(eval $(if $(CONFIG_PM_ENABLE_LM), UNIT_SRC += src/pm_lm.c)) + ifeq ($(CONFIG_PM_ENABLE_TM),y) UNIT_SRC += src/pm_tm.c UNIT_SRC += src/pm_tm_ovsdb.c endif +ifeq ($(CONFIG_PM_ENABLE_OBJM),y) +UNIT_SRC += src/pm_objm.c +UNIT_DEPS += src/lib/oms +endif + +ifeq ($(CONFIG_PM_GW_OFFLINE_CFG),y) +UNIT_SRC += src/pm_gw_offline_cfg.c +endif -UNIT_CFLAGS := -I$(UNIT_PATH)/inc +UNIT_CFLAGS += -I$(UNIT_PATH)/inc UNIT_LDFLAGS += -lev UNIT_DEPS += src/lib/common UNIT_DEPS += src/lib/osp UNIT_DEPS += src/lib/ovsdb UNIT_DEPS += src/lib/schema +UNIT_DEPS += src/lib/module diff --git a/src/qm/src/qm_mqtt.c b/src/qm/src/qm_mqtt.c index 78bbe5d9..3b959746 100644 --- a/src/qm/src/qm_mqtt.c +++ b/src/qm/src/qm_mqtt.c @@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "mosqev.h" #include "dppline.h" #include "target.h" +#include "osp_unit.h" #include "log.h" #include "ds_dlist.h" #include "opensync_stats.pb-c.h" @@ -519,7 +520,7 @@ bool qm_mqtt_init(void) * Use the device serial number as client ID */ char cID[64]; - if (true != target_id_get(cID, sizeof(cID))) + if (true != osp_unit_id_get(cID, sizeof(cID))) { LOGE("acquiring device id number\n"); goto error; diff --git a/src/sm/fut/sm_inspect_leaf_report.sh b/src/sm/fut/sm_inspect_leaf_report.sh new file mode 100755 index 00000000..71c40fc0 --- /dev/null +++ b/src/sm/fut/sm_inspect_leaf_report.sh @@ -0,0 +1,103 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/sm_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed sm' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] \$1 \$2 \$3 \$4 \$5 + +where arguments are: + sm_report_radio=\$1 -- freq_band that is reported inside SM manager in logs (string)(required) + - example: + Caesar: + 50U freq_band is reported as 5GU + 50L freq_band is reported as 5GL + Tyrion: + 50L freq_band is reported as 5G + sm_reporting_interval=\$2 -- used as reporting_interval column in Wifi_Stats_Config (int)(required) + sm_sampling_interval=\$3 -- used as sampling_interval column in Wifi_Stats_Config (int)(required) + sm_report_type=\$4 -- used as report_type column in Wifi_Stats_Config (string)(required) + sm_leaf_mac=\$5 -- inspect logs for given Leaf MAC address reports (string)(required) + +Script does following: + - insert into Wifi_Stats_Config appropriate leaf (client) reporting configuration + - tail logs (/tmp/logs/messages - logread -f) for matching patterns for SM leaf reporting + - log messages are device/platform dependent + +Dependent on: + - running WM/NM managers - min_wm2_setup.sh - existance of active interfaces + - sm_setup.sh + - sm_reporting_env_setup.sh + - existence of connected Leaf device - if not, test will timeout + +Example of usage: + $(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 5 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +sm_radio_type=$1 +sm_reporting_interval=$2 +sm_sampling_interval=$3 +sm_report_type=$4 +sm_leaf_mac=$5 + +tc_name="sm/$(basename "$0")" + +log "$tc_name: Inspecting leaf report on $sm_radio_type for leaf $sm_leaf_mac" + +inspect_leaf_report \ + "$sm_radio_type" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" \ + "$sm_leaf_mac" || die "sm/$(basename "$0"): inspect_leaf_report - Failed" + +pass diff --git a/src/sm/fut/sm_inspect_neighbor_report.sh b/src/sm/fut/sm_inspect_neighbor_report.sh new file mode 100755 index 00000000..aea083df --- /dev/null +++ b/src/sm/fut/sm_inspect_neighbor_report.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/sm_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed sm' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] \$1 \$2 \$3 \$4 \$5 + +where arguments are: + sm_report_radio=\$1 -- freq_band that is reported inside SM manager in logs (string)(required) + - example: + Caesar: + 50U freq_band is reported as 5GU + 50L freq_band is reported as 5GL + Tyrion: + 50L freq_band is reported as 5G + sm_channel=\$2 -- channel to inspect survey reporting on (int)(required) + sm_survey_type=\$3 -- type of channel survey type in Wifi_Stats_Config (string)(required) + - example + - on-chan - inspect survey reporting on given channel + - off-chan - inspect survey reporting off channel + sm_reporting_interval=\$4 -- used as reporting_interval column value in Wifi_Stats_Config table (int)(required) + sm_sampling_interval=\$5 -- used as sampling_interval column value in Wifi_Stats_Config table (int)(required) + sm_report_type=\$6 -- used as report_type column value in Wifi_Stats_Config table (string)(required) + sm_neighbor_mac=\$7 -- inspect logs for given Neighbor MAC address reports (string)(required) + sm_neighbor_ssid=\$8 -- inspect logs for given Neighbor SSID address reports (string)(required) + +Script does following: + - insert into Wifi_Stats_Config appropriate neighbor reporting configuration + - tail logs (/tmp/logs/messages - logread -f) for matching patterns for SM neighbor reporting + - log messages are device/platform dependent + +Dependent on: + - running WM/NM managers - min_wm2_setup.sh - existance of active interfaces + - sm_setup.sh + - sm_reporting_env_setup.sh + - existence of given neighbor - if not, test will timeout + +Example of usage: + $(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 8 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +sm_radio_type=$1 +sm_channel=$2 +sm_survey_type=$3 +sm_reporting_interval=$4 +sm_sampling_interval=$5 +sm_report_type=$6 +sm_neighbor_ssid=$7 +sm_neighbor_mac=$8 + +tc_name="sm/$(basename "$0")" + +log "$tc_name: Inspecting neighbor report on $sm_radio_type $sm_survey_type for $sm_neighbor_mac $sm_neighbor_ssid" + +inspect_neighbor_report \ + "$sm_radio_type" \ + "$sm_channel" \ + "$sm_survey_type" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" \ + "$sm_neighbor_ssid" \ + "$sm_neighbor_mac" || die "sm/$(basename "$0"): inspect_neighbor_report - Failed" + +pass diff --git a/src/sm/fut/sm_inspect_survey_report.sh b/src/sm/fut/sm_inspect_survey_report.sh new file mode 100755 index 00000000..862f7580 --- /dev/null +++ b/src/sm/fut/sm_inspect_survey_report.sh @@ -0,0 +1,108 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/sm_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed sm' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] \$1 \$2 \$3 \$4 \$5 \$6 + +where arguments are: + sm_report_radio=\$1 -- freq_band that is reported inside SM manager in logs (string)(required) + - example: + Caesar: + 50U freq_band is reported as 5GU + 50L freq_band is reported as 5GL + Tyrion: + 50L freq_band is reported as 5G + sm_channel=\$2 -- channel to inspect survey reporting on (int)(required) + sm_survey_type=\$3 -- type of channel survey type in Wifi_Stats_Config (string)(required) + - example + - on-chan - inspect survey reporting on given channel + - off-chan - inspect survey reporting off channel + sm_reporting_interval=\$4 -- used as reporting_interval value for Wifi_Stats_Config (int)(required) + sm_sampling_interval=\$5 -- used as sampling_interval value for Wifi_Stats_Config (int)(required) + sm_report_type=\$6 -- used as report_type value for Wifi_Stats_Config (string)(required) + +Script does following: + - insert into Wifi_Stats_Config appropriate survey reporting configuration + - tail logs (/tmp/logs/messages - logread -f) for matching patterns for initiating SM survey reporting + - log messages are device/platform dependent + +Dependent on: + - running WM/NM managers - min_wm2_setup.sh - existance of active interfaces + - sm_setup.sh + - sm_reporting_env_setup.sh + +Example of usage: + $(basename "$0") +" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 6 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +sm_radio_type=$1 +sm_channel=$2 +sm_survey_type=$3 +sm_reporting_interval=$4 +sm_sampling_interval=$5 +sm_report_type=$6 + +tc_name="sm/$(basename "$0")" + +log "$tc_name: Inspecting survey report on $sm_radio_type $sm_survey_type channel $sm_channel" + +inspect_survey_report \ + "$sm_radio_type" \ + "$sm_channel" \ + "$sm_survey_type" \ + "$sm_reporting_interval" \ + "$sm_sampling_interval" \ + "$sm_report_type" || die "sm/$(basename "$0"): inspect_survey_report - Failed" + +pass diff --git a/src/sm/fut/sm_setup.sh b/src/sm/fut/sm_setup.sh new file mode 100755 index 00000000..83e685ad --- /dev/null +++ b/src/sm/fut/sm_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for SM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/sm_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="sm/$(basename "$0")" + +sm_setup_test_environment "$@" && + log "$tc_name: sm_setup_test_environment - Success " || + die "$tc_name: sm_setup_test_environment - Failed" + +exit 0 diff --git a/src/sm/fut/unit.mk b/src/sm/fut/unit.mk new file mode 100644 index 00000000..bcf1b8dc --- /dev/null +++ b/src/sm/fut/unit.mk @@ -0,0 +1,37 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_sm + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_SM),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/sm + +UNIT_FILE := sm_setup.sh +UNIT_FILE += sm_inspect_leaf_report.sh +UNIT_FILE += sm_inspect_neighbor_report.sh +UNIT_FILE += sm_inspect_survey_report.sh diff --git a/src/sm/src/sm_mqtt.c b/src/sm/src/sm_mqtt.c index 3075e17d..219c52b3 100644 --- a/src/sm/src/sm_mqtt.c +++ b/src/sm/src/sm_mqtt.c @@ -28,12 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "log.h" +#include "util.h" #include "os_time.h" #include "os_nif.h" #include "mosqev.h" #include "dppline.h" -#include "target.h" -#include "log.h" +#include "osp_unit.h" #include "sm.h" @@ -77,7 +78,7 @@ bool sm_mqtt_init(void) * Use the device serial number as client ID */ char cID[64]; - if (true != target_id_get(cID, sizeof(cID))) + if (true != osp_unit_id_get(cID, sizeof(cID))) { LOGE("acquiring device id number\n"); goto error; diff --git a/src/sm/src/sm_survey_report.c b/src/sm/src/sm_survey_report.c index 3e464e83..b7b7dc0e 100644 --- a/src/sm/src/sm_survey_report.c +++ b/src/sm/src/sm_survey_report.c @@ -428,6 +428,7 @@ bool sm_survey_report_calculate_average ( CALC(chan_self); CALC(chan_rx); CALC(chan_busy_ext); + CALC(chan_noise); } #define AVG(_name) do { \ @@ -465,6 +466,7 @@ bool sm_survey_report_calculate_average ( AVG(chan_self); AVG(chan_rx); AVG(chan_busy_ext); + AVG(chan_noise); ds_dlist_insert_tail(report_list, report_entry); } @@ -519,7 +521,7 @@ bool sm_survey_report_calculate_raw ( memcpy(report_entry, record_entry, sizeof(*report_entry)); LOGD("Sending %s %s %u survey report " - "{busy=%u tx=%u self=%u rx=%u ext=%u duration=%u}", + "{busy=%u tx=%u self=%u rx=%u ext=%u noise=%d duration=%u}", radio_get_name_from_cfg(radio_cfg_ctx), radio_get_scan_name_from_type(scan_type), report_entry->info.chan, @@ -528,6 +530,7 @@ bool sm_survey_report_calculate_raw ( report_entry->chan_self, report_entry->chan_rx, report_entry->chan_busy_ext, + report_entry->chan_noise, report_entry->duration_ms); ds_dlist_insert_tail(report_list, report_entry); @@ -723,7 +726,7 @@ bool sm_survey_update_list_cb ( result_entry); LOGD("Processed %s %s %u survey percent " - "{busy=%u tx=%u self=%u rx=%u ext=%u duration=%u}", + "{busy=%u tx=%u self=%u rx=%u ext=%u noise=%d duration=%u}", radio_get_name_from_cfg(radio_cfg_ctx), radio_get_scan_name_from_type(scan_type), result_entry->info.chan, @@ -732,6 +735,7 @@ bool sm_survey_update_list_cb ( result_entry->chan_self, result_entry->chan_rx, result_entry->chan_busy_ext, + result_entry->chan_noise, result_entry->duration_ms); result_entry->info.timestamp_ms = diff --git a/src/tools/osps/src/osps_main.c b/src/tools/osps/src/osps_main.c index 20768c8f..2720c1fb 100644 --- a/src/tools/osps/src/osps_main.c +++ b/src/tools/osps/src/osps_main.c @@ -51,6 +51,7 @@ static int osps_help(int argc, char *argv[]); static int osps_get(int argc, char *argv[]); static int osps_set(int argc, char *argv[]); static int osps_del(int argc, char *argv[]); +static int osps_erase(int argc, char *argv[]); void osps_command_register(struct osps_command *oc) { @@ -357,6 +358,74 @@ static int osps_del(int argc, char *argv[]) return 0; } +/* + * =========================================================================== + * ERASE command + * =========================================================================== + */ +static struct osps_command osps_erase_cmd = OSPS_COMMAND_INIT( + "erase", + osps_erase, + "erase STORE ; Delete all keys from persistent storage", + "\n" + "Arguments:\n" + "\n" + " STORE - The persistent store name\n"); + +static int osps_erase(int argc, char *argv[]) +{ + osp_ps_t *ps; + int flags; + + if (argc != 2) + { + osps_usage("erase", "Invalid number of arguments."); + return OSPS_CLI_ERROR; + } + + /* First open in read-only mode just to see if the store exists */ + flags = OSP_PS_READ; + if (osps_preserve) flags |= OSP_PS_PRESERVE; + + ps = osp_ps_open(argv[1], flags); + if (ps == NULL) + { + fprintf(stderr, "Error opening store (RO): %s", argv[1]); + return 1; + } + + if (!osp_ps_close(ps)) + { + fprintf(stderr, "Warning: Error closing store (RO): %s\n", argv[1]); + } + + /* + * Re-open store in write mode + */ + flags = OSP_PS_WRITE; + if (osps_preserve) flags |= OSP_PS_PRESERVE; + + ps = osp_ps_open(argv[1], flags); + if (ps == NULL) + { + fprintf(stderr, "Error opening store (RW): %s", argv[1]); + return 1; + } + + if (!osp_ps_erase(ps)) + { + fprintf(stderr, "Unable to erase store: %s\n", argv[1]); + } + + if (!osp_ps_close(ps)) + { + fprintf(stderr, "Warning: Error closing store: %s\n", argv[1]); + return 1; + } + + return 0; +} + int main(int argc, char *argv[]) { struct osps_command *oc; @@ -378,6 +447,7 @@ int main(int argc, char *argv[]) osps_command_register(&osps_get_cmd); osps_command_register(&osps_set_cmd); osps_command_register(&osps_del_cmd); + osps_command_register(&osps_erase_cmd); /* * Initialize modules diff --git a/src/tools/preboot/src/preboot.c b/src/tools/preboot/src/preboot.c index 34e447d8..0ca970b4 100644 --- a/src/tools/preboot/src/preboot.c +++ b/src/tools/preboot/src/preboot.c @@ -38,7 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "osp.h" +#include "osp_reboot.h" #if 1 #include "util.h" #include "const.h" diff --git a/src/um/fut/um_corrupt_image.sh b/src/um/fut/um_corrupt_image.sh new file mode 100755 index 00000000..683435bf --- /dev/null +++ b/src/um/fut/um_corrupt_image.sh @@ -0,0 +1,109 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh http://url_to_image +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Corrupt FW image" + +log "$tc_name: Setting firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node firmware_url set to $fw_url" || + raise "update_ovsdb_entry - Failed to set firmware_url to $fw_url in AWLAN_Node" -l "$tc_name" -tc + +fw_start_code=$(get_um_code "UPG_STS_FW_DL_START") +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_start_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_start_code" -l "$tc_name" -tc + +fw_stop_code=$(get_um_code "UPG_STS_FW_DL_END") +log "$tc_name: Waiting for FW download finish" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_stop_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_stop_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_stop_code" -l "$tc_name" -tc + +log "$tc_name: Setting AWLAN_Node upgrade_timer to 1" +update_ovsdb_entry AWLAN_Node -u upgrade_timer 1 && + log "$tc_name: update_ovsdb_entry - AWLAN_Node upgrade_timer set to 1" || + raise "update_ovsdb_entry - Failed to set upgrade_timer to 1 in AWLAN_Node" -l "$tc_name" -tc + +fw_fail_code=$(get_um_code "UPG_ERR_IMG_FAIL") +log "$tc_name: Waiting for FW corrupt image code UPG_ERR_IMG_FAIL - $fw_fail_code" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_fail_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_fail_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_fail_code" -l "$tc_name" -tc + +pass diff --git a/src/um/fut/um_corrupt_md5_sum.sh b/src/um/fut/um_corrupt_md5_sum.sh new file mode 100755 index 00000000..74c58563 --- /dev/null +++ b/src/um/fut/um_corrupt_md5_sum.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh http://url_to_image +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Corrupt FW image" + +log "$tc_name: Setting firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node firmware_url set to $fw_url" || + raise "update_ovsdb_entry - Failed to set firmware_url to $fw_url in AWLAN_Node" -l "$tc_name" -tc + +fw_start_code=$(get_um_code "UPG_STS_FW_DL_START") +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_start_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_start_code" -l "$tc_name" -tc + +fw_err_code=$(get_um_code "UPG_ERR_MD5_FAIL") +log "$tc_name: Waiting for UPG_ERR_MD5_FAIL upgrade status $fw_err_code" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_err_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_err_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_err_code" -l "$tc_name" -tc + + +pass diff --git a/src/um/fut/um_missing_md5_sum.sh b/src/um/fut/um_missing_md5_sum.sh new file mode 100755 index 00000000..70c40937 --- /dev/null +++ b/src/um/fut/um_missing_md5_sum.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh http://url_to_image +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Corrupt FW image" + +log "$tc_name: Setting firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node firmware_url set to $fw_url" || + raise "update_ovsdb_entry - Failed to set firmware_url to $fw_url in AWLAN_Node" -l "$tc_name" -tc + +fw_start_code=$(get_um_code "UPG_STS_FW_DL_START") +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_start_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_start_code" -l "$tc_name" -tc + +fw_err_code=$(get_um_code "UPG_ERR_DL_MD5") +log "$tc_name: Waiting for UPG_ERR_DL_MD5 upgrade status $fw_err_code" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$fw_err_code" && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_err_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_err_code" -l "$tc_name" -tc + + +pass diff --git a/src/um/fut/um_set_correct_firmware_pass.sh b/src/um/fut/um_set_correct_firmware_pass.sh new file mode 100755 index 00000000..a355a1b8 --- /dev/null +++ b/src/um/fut/um_set_correct_firmware_pass.sh @@ -0,0 +1,102 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + fw_pass=\$3 -- used as firmware_pass in AWLAN_Node table - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh http://url_to_image fw_pass +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +fw_pass=$3 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Corrupt FW image" + +log "$tc_name: Setting firmware_url to $fw_url and firmware_pass to $fw_pass" +update_ovsdb_entry AWLAN_Node \ + -u firmware_pass $fw_pass \ + -u firmware_url $fw_url && + log "$tc_name: update_ovsdb_entry - AWLAN_Node table updated" || + raise "update_ovsdb_entry - Failed to update AWLAN_Node table" -l "$tc_name" -tc + +fw_dwl_start_code=$(get_um_code "UPG_STS_FW_DL_START") +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $fw_dwl_start_code && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_dwl_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_dwl_start_code" -l "$tc_name" -tc + +fw_dwl_stop_code=$(get_um_code "UPG_STS_FW_DL_END") +log "$tc_name: Waiting for FW download finish" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $fw_dwl_stop_code && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $fw_dwl_stop_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $fw_dwl_stop_code" -l "$tc_name" -tc + +pass diff --git a/src/um/fut/um_set_firmware_url.sh b/src/um/fut/um_set_firmware_url.sh new file mode 100755 index 00000000..54545bdd --- /dev/null +++ b/src/um/fut/um_set_firmware_url.sh @@ -0,0 +1,108 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + fw_name=\$3 -- used as FW name to validate file and md5 sum files - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh /tmp/pfirmware http://url_to_image image_name.eim +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +fw_name=${fw_url##*/} +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Download FW - firmware_url" + +log "$tc_name: Setting firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node firmware_url set to $fw_url" || + raise "update_ovsdb_entry - Failed to set firmware_url to $fw_url in AWLAN_Node" -l "$tc_name" -tc + +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $(get_um_code "UPG_STS_FW_DL_START") && + log "$tc_name: wait_ovsdb_entry - Success to wait" || + raise "wait_ovsdb_entry - Failed to wait" -l "$tc_name" -tc + +log "$tc_name: Waiting for FW download finish" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $(get_um_code "UPG_STS_FW_DL_END") && + log "$tc_name: wait_ovsdb_entry - Success to wait" || + raise "wait_ovsdb_entry - Failed to wait" -l "$tc_name" -tc + +log "$tc_name: Checking for image in /tmp/pfirmware" +wait_for_function_response 0 "ls $fw_path/$fw_name" && + log "$tc_name: Image exists in $fw_path" || + raise "Image doesn't exist in $fw_path" -l "$tc_name" -tc + +log "$tc_name: Checking for image md5 sum in $fw_path" +wait_for_function_response 0 "ls $fw_path/$fw_name.md5" && + log "$tc_name: Image exists in $fw_path" || + raise "Image doesn't exist in $fw_path" -l "$tc_name" -tc + +pass diff --git a/src/um/fut/um_set_invalid_firmware_pass.sh b/src/um/fut/um_set_invalid_firmware_pass.sh new file mode 100755 index 00000000..7bf1c762 --- /dev/null +++ b/src/um/fut/um_set_invalid_firmware_pass.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + fw_pass=\$2 -- used as firmware_pass in AWLAN_Node table - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh http://url_to_image invalid_fw_pass +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +fw_pass=$3 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Corrupt FW image" +log "$tc_name: Setting firmware_url to $fw_url and firmware_pass to $fw_pass" + +update_ovsdb_entry AWLAN_Node \ + -u firmware_pass "$fw_pass" \ + -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - Success to update" || + raise "$tc_name: update_ovsdb_entry - Failed to update" -l "$tc_name" -tc + +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $(get_um_code "UPG_STS_FW_DL_START") && + log "$tc_name: wait_ovsdb_entry - Success to wait" || + raise "$tc_name: wait_ovsdb_entry - Failed to wait" -l "$tc_name" -tc + +log "$tc_name: Waiting for FW download finish" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $(get_um_code "UPG_STS_FW_DL_END") && + log "$tc_name: wait_ovsdb_entry - Success to wait" || + raise "$tc_name: wait_ovsdb_entry - Failed to wait" -l "$tc_name" -tc + +log "$tc_name: Setting AWLAN_Node upgrade_timer to 1 and " +update_ovsdb_entry AWLAN_Node -u upgrade_timer 1 && + log "$tc_name: update_ovsdb_entry - Success to update" || + raise "$tc_name: update_ovsdb_entry - Failed to update" -l "$tc_name" -tc + +log "$tc_name: Waiting for FW corrupt image code UPG_ERR_IMG_FAIL - $(get_um_code "UPG_ERR_IMG_FAIL")" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $(get_um_code "UPG_ERR_IMG_FAIL") && + log "$tc_name: wait_ovsdb_entry - Success to wait" || + raise "$tc_name: wait_ovsdb_entry - Failed to wait" -l "$tc_name" -tc + +pass diff --git a/src/um/fut/um_set_invalid_firmware_url.sh b/src/um/fut/um_set_invalid_firmware_url.sh new file mode 100755 index 00000000..18ba3ec6 --- /dev/null +++ b/src/um/fut/um_set_invalid_firmware_url.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh https://s3-us-west-2.amazonaws.com/invalid_url +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 1 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Download FW - invalid firmware_url" + +log "$tc_name: Setting firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - Success to update" || + raise "update_ovsdb_entry - Failed to update" -l "$tc_name" -tc + +log "$tc_name: Waiting for UM DL of FW image failed" +wait_ovsdb_entry AWLAN_Node -is upgrade_status "$(get_um_code "UPG_ERR_DL_FW")" && + log "$tc_name: wait_ovsdb_entry - Success to wait" || + raise "wait_ovsdb_entry - Failed to wait" -l "$tc_name" -tc + +pass diff --git a/src/um/fut/um_set_upgrade_dl_timer.sh b/src/um/fut/um_set_upgrade_dl_timer.sh new file mode 100755 index 00000000..94eeb80d --- /dev/null +++ b/src/um/fut/um_set_upgrade_dl_timer.sh @@ -0,0 +1,103 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + fw_dl_timer=\$3 -- used as upgrade_dl_timer in AWLAN_Node table - (int)(required) + +this script is dependent on following: + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh http://url_to_image image_name.eim 10 +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [[ $# -lt 2 ]]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +fw_path=$1 +fw_url=$2 +fw_dl_timer=$3 +tc_name="um/$(basename "$0")" + +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Download FW - upgrade_dl_timer - 2 seconds +/-" + +log "$tc_name: Setting upggrade_dl_timer to $fw_dl_timer firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node \ + -u upgrade_dl_timer $fw_dl_timer \ + -u firmware_url $fw_url && + log "$tc_name: update_ovsdb_entry - Success to update" || + raise "update_ovsdb_entry - Failed to update" -l "$tc_name" -tc + +start_time=$(date -D "%H:%M:%S" +"%Y.%m.%d-%H:%M:%S") + +dl_start_code=$(get_um_code "UPG_STS_FW_DL_START") +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $dl_start_code && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $dl_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $dl_start_code" -l "$tc_name" -tc + +log "$tc_name: Waiting for FW download finish" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $(get_um_code "UPG_STS_FW_DL_END") && + fw_dl_timer_result 0 $start_time $fw_dl_timer || + fw_dl_timer_result 1 $start_time $fw_dl_timer + +pass diff --git a/src/um/fut/um_set_upgrade_timer.sh b/src/um/fut/um_set_upgrade_timer.sh new file mode 100755 index 00000000..5fb61d02 --- /dev/null +++ b/src/um/fut/um_set_upgrade_timer.sh @@ -0,0 +1,130 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +usage=" +$(basename "$0") [-h] \$1 \$2 \$3 \$4 + +where options are: + -h show this help message + +where arguments are: + fw_path=\$1 -- download path of UM - used to clear the folder on UM setup - (string)(required) + fw_url=\$2 -- used as firmware_url in AWLAN_Node table - (string)(required) + fw_up_timer=\$3 -- used as upgrade_time in AWLAN_Node table - (int)(required) + +this script is dependent on following: + - logread on device + - running UM manager + - udhcpc on interface + +example of usage: + /tmp/fut-base/shell/nm2/$(basename "$0").sh /plume/pfirmware http://url_to_image 10 +" + +while getopts hcs:fs: option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + + +fw_path=${1} +fw_url=${2} +fw_up_timer=${3} +fw_name=${4} +tc_name="um/$(basename "$0")" +[ $# -ne 4 ] && raise "Requires 4 input arguments" -l "${tc_name}" -arg +trap ' + reset_um_triggers $fw_path || true + run_setup_if_crashed um || true +' EXIT SIGINT SIGTERM + +log "$tc_name: UM Download FW - upgrade_timer - 2 seconds +/-" + +log "$tc_name: Setting firmware_url to $fw_url" +update_ovsdb_entry AWLAN_Node -u firmware_url "$fw_url" && + log "$tc_name: update_ovsdb_entry - AWLAN_Node firmware_url set to $fw_url" || + raise "update_ovsdb_entry - Failed to set firmware_url to $fw_url in AWLAN_Node" -l "$tc_name" -tc + +dl_start_code=$(get_um_code "UPG_STS_FW_DL_START") +log "$tc_name: Waiting for FW download start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $dl_start_code && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $dl_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $dl_start_code" -l "$tc_name" -tc + +dl_finish_code=$(get_um_code "UPG_STS_FW_DL_END") +log "$tc_name: Waiting for FW download finish" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $dl_finish_code && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $dl_finish_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $dl_finish_code" -l "$tc_name" -tc + +log "$tc_name: Setting AWLAN_Node upgrade_timer to $fw_up_timer" +update_ovsdb_entry AWLAN_Node -u upgrade_timer $fw_up_timer && + log "$tc_name: update_ovsdb_entry - AWLAN_Node upgrade_timer set to $fw_up_timer" || + raise "update_ovsdb_entry - Failed to set upgrade_timer to $fw_up_timer in AWLAN_Node" -l "$tc_name" -tc + +# Delete image file on device to skip upgrade process +if [ -n "$fw_path" ] && [ -n "$fw_name" ]; then + rm -rf "$fw_path/$fw_name" +fi + +start_time=$(date -D "%H:%M:%S" +"%Y.%m.%d-%H:%M:%S") + +upg_start_code=$(get_um_code "UPG_STS_FW_WR_START") +log "$tc_name: Waiting for UM upgrade start" +wait_ovsdb_entry AWLAN_Node -is upgrade_status $upg_start_code && + log "$tc_name: wait_ovsdb_entry - AWLAN_Node upgrade_status is $upg_start_code" || + raise "wait_ovsdb_entry - Failed to set upgrade_status in AWLAN_Node to $upg_start_code" -l "$tc_name" -tc + +end_time=$(date -D "%H:%M:%S" +"%Y.%m.%d-%H:%M:%S") + +t1=$(date -u -d "$start_time" +"%s") +t2=$(date -u -d "$end_time" +"%s") + +upgrade_time=$(( t2 - t1 )) +upgrade_time_lower=$(( $upgrade_time - 2 )) +upgrade_time_upper=$(( $upgrade_time + 2 )) + +if [ "$upgrade_time_lower" -le "$fw_up_timer" ] && [ "$upgrade_time_upper" -ge "$fw_up_timer" ];then + log "$tc_name: Upgrade started in given upgrade_timer - given $fw_up_timer - resulted in $upgrade_time" +else + raise "Upgrade DID NOT start in given upgrade_timer - given $fw_up_timer - resulted in $upgrade_time" -l "$tc_name" -tc +fi + +pass diff --git a/src/um/fut/um_setup.sh b/src/um/fut/um_setup.sh new file mode 100755 index 00000000..85bd6ffc --- /dev/null +++ b/src/um/fut/um_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for UM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source ${FUT_TOPDIR}/shell/lib/unit_lib.sh +source ${FUT_TOPDIR}/shell/lib/um_lib.sh +source ${LIB_OVERRIDE_FILE} + +tc_name="um/$(basename "$0")" + +um_setup_test_environment "$@" && + log "$tc_name: um_setup_test_environment - Success " || + raise "$tc_name: um_setup_test_environment - Failed" -l "$tc_name" -ds + +exit 0 diff --git a/src/um/fut/unit.mk b/src/um/fut/unit.mk new file mode 100644 index 00000000..944b8916 --- /dev/null +++ b/src/um/fut/unit.mk @@ -0,0 +1,43 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_um + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_UM),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/um + +UNIT_FILE := um_setup.sh +UNIT_FILE += um_corrupt_image.sh +UNIT_FILE += um_corrupt_md5_sum.sh +UNIT_FILE += um_missing_md5_sum.sh +UNIT_FILE += um_set_correct_firmware_pass.sh +UNIT_FILE += um_set_firmware_url.sh +UNIT_FILE += um_set_invalid_firmware_pass.sh +UNIT_FILE += um_set_invalid_firmware_url.sh +UNIT_FILE += um_set_upgrade_dl_timer.sh +UNIT_FILE += um_set_upgrade_timer.sh diff --git a/src/um/src/um_ovsdb.c b/src/um/src/um_ovsdb.c index eb4d3c22..8aab2d58 100644 --- a/src/um/src/um_ovsdb.c +++ b/src/um/src/um_ovsdb.c @@ -41,12 +41,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ovsdb.h" #include "ovsdb_update.h" #include "log.h" +#include "util.h" #include "json_util.h" #include "schema.h" -#include "target.h" #include "os_proc.h" #include "ovsdb_sync.h" -#include "osp.h" +#include "osp_upg.h" #include "um.h" #include "ovsdb.h" #include "ovsdb_table.h" diff --git a/src/wano/inc/wano.h b/src/wano/inc/wano.h new file mode 100644 index 00000000..315a4620 --- /dev/null +++ b/src/wano/inc/wano.h @@ -0,0 +1,478 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef WANO_H_INCLUDED +#define WANO_H_INCLUDED + +/* + * =========================================================================== + * WANO Public API -- primarily used by WANO plugins + * =========================================================================== + */ + +#include +#include + +#include "const.h" +#include "ds_tree.h" +#include "osn_types.h" +#include "reflink.h" +#include "util.h" + +#include "wano_ppline_stam.h" + +/* + * =========================================================================== + * WANO Plug-in API + * =========================================================================== + */ + +struct wano_plugin; +struct wano_plugin_handle; +struct wano_plugin_iter; + +#define WANO_PLUGIN_MASK_L2 (1 << 0) +#define WANO_PLUGIN_MASK_IPV4 (1 << 1) +#define WANO_PLUGIN_MASK_IPV6 (1 << 2) +#define WANO_PLUGIN_MASK_ALL UINT64_MAX + +typedef struct wano_plugin_handle wano_plugin_handle_t; +typedef struct wano_plugin_iter wano_plugin_iter_t; +struct wano_plugin_status; + +typedef void wano_plugin_status_fn_t( + wano_plugin_handle_t *wh, + struct wano_plugin_status *status); + +typedef wano_plugin_handle_t *wano_plugin_ops_init_fn_t( + const struct wano_plugin *wm, + const char *ifname, + wano_plugin_status_fn_t *status_fn); + +typedef void wano_plugin_ops_run_fn_t(wano_plugin_handle_t *wh); +typedef void wano_plugin_ops_fini_fn_t(wano_plugin_handle_t *wh); + +/** + * WANO plug-ins are probed from high to low priority. + * + */ +struct wano_plugin +{ + const char * const wanp_name; /**< Plug-in name */ + const double wanp_priority; /**< Plug-in priority */ + const uint64_t wanp_mask; /**< Plug-in exclusion mask */ + wano_plugin_ops_init_fn_t * const wanp_init; /**< OPS: Init function */ + wano_plugin_ops_run_fn_t * const wanp_run; /**< OPS: Run function */ + wano_plugin_ops_fini_fn_t * const wanp_fini; /**< OPS: Fini function */ + ds_tree_node_t _wanp_tnode; /* Internal: r/b tree node structure */ +}; + +/** + * A WANO plug-in handle references a single plug-in instance and its resources + */ +struct wano_plugin_handle +{ + const struct wano_plugin *wh_plugin; /**< Pointer to struct plugin */ + char wh_ifname[C_IFNAME_LEN]; /**< Interface name */ + void *wh_data; /**< Private data */ +}; + +/** + * WAN plug-in iterator -- function used for traversing the registered plug-ins + * list. Plug-ins are returned in a sorted order from the highest to the lowest + * priority + */ +struct wano_plugin_iter +{ + ds_tree_iter_t wpi_iter; /**< Tree iterator */ +}; + +/** + * Use this macro to initialize struct wano_plugin + */ +#define WANO_PLUGIN_INIT(name, priority, mask, init_fn, run_fn, fini_fn) \ +(struct wano_plugin) \ +{ \ + .wanp_name = (name), \ + .wanp_priority = (priority), \ + .wanp_mask = (mask), \ + .wanp_init = (init_fn), \ + .wanp_run = (run_fn), \ + .wanp_fini = (fini_fn), \ +} + +/** + * Plug-in status reporting structure + */ +struct wano_plugin_status +{ + enum + { + WANP_OK, /* WANO link was successfully provisioned */ + WANP_ERROR, /* Error occurred while provisioning plug-in, skip to the next plugin */ + WANP_SKIP, /* Skip this plug-in */ + WANP_BUSY, /* Plug-in is busy doing work, stop the timeout timer */ + WANP_RESTART, /* Error occurred while provisioning plug-in, restart the pipeline */ + WANP_ABORT, /* Abort this plug-in and terminate the current plug-in pipeline */ + } + ws_type; + + /** WAN interface, valid for WAN_OK and WANP_NEW */ + char ws_ifname[C_IFNAME_LEN]; + /** WAN interface type, valid for WANP_OK and WANP_NEW */ + char ws_iftype[16]; +}; + +#define WANO_PLUGIN_STATUS(type, ...) \ +(struct wano_plugin_status) \ +{ \ + .ws_type = (type), \ + __VA_ARGS__ \ +} + +/** + * Register a WANO plug-in + * + * @param[in] wm Pointer to a WANO plugin structure + */ +void wano_plugin_register(struct wano_plugin *wm); + +/** + * Unregister a WANO plug-in + * + * @param[in] wm Pointer to a WANO plugin structure + */ +void wano_plugin_unregister(struct wano_plugin *wm); + +/** + * Reset current plug-in iterator and return the head of the list (entry with + * lowest priority). + * + * @return + * Return a pointer to a plug-in structure (struct wano_plugin) or NULL if no + * plug-ins are registered. + */ +struct wano_plugin *wano_plugin_first(wano_plugin_iter_t *iter); + +/** + * After wano_plugin_first() is called, return the next element in descending + * priority * order + */ +struct wano_plugin *wano_plugin_next(wano_plugin_iter_t *iter); + +/** + * Find a WANO plug-in by name + * + * @param[in] name WANO plug-in name + * + * @return + * This function returns a WANO plug-in structure on success or a NULL pointer + * if the plug-in couldn't be found + */ +struct wano_plugin *wano_plugin_find(const char *name); + +/** + * Initialize a WANO plug-in instance + * + * @param[in] wm Pointer to a WANO plug-in structure + * @param[in] ifname Interface name + * @param[in] status_fn Pointer to the status update function callback + * + * @return + * This function returns a pointer to a WANO plug-in handle (instance) or NULL + * on error or if the plug-in could not be initialized for the specific + * interface (for example, if it is not supported). + */ +wano_plugin_handle_t *wano_plugin_init( + struct wano_plugin *wm, + const char *ifname, + wano_plugin_status_fn_t *status_fn); + +/** + * Start a WANO plug-in link bringup sequence + * + * @param[in] wh Pointer to a WANO plug-in instance + */ +void wano_plugin_run(wano_plugin_handle_t *wh); + +/** + * Release a WANO plug-in instance + * + * If the WAN link bringup sequence has been started with wano_plugin_run(), this + * function will abort it + * + * @param[in] wh Pointer to a WANO plug-in instance + * + * @note + * This function may trigger wan_status_fn_t callbacks + */ +bool wano_plugin_fini(wano_plugin_handle_t *wh); + +/** + * Retrieve the plugin's name + */ +static inline const char *wano_plugin_name(wano_plugin_handle_t *wh) +{ + return wh->wh_plugin->wanp_name; +} + +/* + * =========================================================================== + * WANO Interface State API -- used to query cached interface status from + * OVSDB + * + * Listening to events from Wifi_Inet_State is a common pattern in WANO + * plug-ins. This plug-in implements caching mechanisms and event subscription + * services for the Wifi_Inet_State table. + * + * =========================================================================== + */ + +/** + * Structure used to register to wano_inet_state events + */ +struct wano_inet_state_event; +struct wano_inet_state; + +typedef struct wano_inet_state_event wano_inet_state_event_t; + +typedef void wano_inet_state_event_fn_t( + struct wano_inet_state_event *event, + struct wano_inet_state *state); + +/** + * Wifi_Inet_State cache structure + */ +struct wano_inet_state +{ + bool is_inet_state_valid; /**< True if structure is valid (present in OVSDB) */ + bool is_master_state_valid; /**< True if structure is valid (present in OVSDB) */ + char is_ifname[C_IFNAME_LEN]; /**< The interface name, also the primary key */ + char is_ip_assign_scheme[32]; /**< Cached "ip_assign_scheme" column */ + bool is_enabled; /**< Cached "enable" column */ + bool is_network; /**< Cached "network" column */ + bool is_nat; /**< Cached "NAT" column */ + osn_ip_addr_t is_ipaddr; /**< Cached IPv4 address */ + osn_ip_addr_t is_netmask; /**< Cached netmask */ + osn_ip_addr_t is_gateway; /**< Cached gateway */ + osn_ip_addr_t is_dns1; /**< Primary DNS server */ + osn_ip_addr_t is_dns2; /**< Secondary DNS server */ + bool is_port_state; /**< Port state */ + ds_tree_node_t is_tnode; /**< Tree node */ + reflink_t is_reflink; /**< Event subscribers */ +}; + +struct wano_inet_state_event +{ + wano_inet_state_event_fn_t + *ise_event_fn; /**< Event handler function */ + reflink_t ise_inet_state_reflink; /**< Reflink to wano_inet_state */ + struct wano_inet_state *ise_inet_state; /**< Pointer to inet state */ + ev_async ise_async; /**< Async watcher, for forcing update refreshes */ + bool ise_init; /**< True if the structure was properly initialized */ +}; + +/** + * Initialize the wano_inet_state_event_t structure and subscribe to Wifi_Inet_State updates for interface @p ifname + */ + +bool wano_inet_state_event_init( + wano_inet_state_event_t *self, + const char *ifname, + wano_inet_state_event_fn_t *fn); + +/** + * Force a async state refresh. The callback will be invoked asynchronously next time the libev event loop is run. + */ +void wano_inet_state_event_refresh(wano_inet_state_event_t *self); + +/** + * Deinitialize wano_inet_state_event_t and stop listening for events on interface @p ifname + */ +void wano_inet_state_event_fini(wano_inet_state_event_t *self); + +/* + * =========================================================================== + * WANO Inet Config API -- Wrappers for writing/updating Wifi_Inet_Config + * =========================================================================== + */ + +/** + * Tristate type; this is used to represent bools with the additional + * option of having a value of "none" (unset). + */ +typedef enum wano_tri +{ + WANO_TRI_NONE = 0, + WANO_TRI_TRUE, + WANO_TRI_FALSE, +} +wano_tri_t; + +struct wano_inet_config_args +{ + const char *if_type; /**< Maps to Wifi_Inet_Config:if_type */ + wano_tri_t enabled; /**< Maps to Wifi_Inet_Config:enabled */ + wano_tri_t network; /**< Maps to Wifi_Inet_Config:network */ + wano_tri_t nat; /**< Maps to Wifi_Inet_Config:NAT */ + const char *ip_assign_scheme; /**< Maps to Wifi_Inet_Config:ip_assign_scheme */ + const char *inet_addr; /**< Maps to Wifi_Inet_Config:inet_addr */ + const char *netmask; /**< Maps to Wifi_Inet_Config:netmask */ + const char *gateway; /**< Maps to Wifi_Inet_Config:gateway */ + const char *dns1; /**< Maps to Wifi_Inet_config::dns */ + const char *dns2; /**< Maps to Wifi_Inet_config::dns */ + const char *parent_ifname; /**< Maps to Wifi_Inet_Config:parent_ifname */ + const int vlan_id; /**< Maps to Wifi_Inet_Config:vlan_id */ +}; + +#define WANO_INET_CONFIG_UPDATE(ifname, ...) \ + wano_inet_config_update(ifname, &(struct wano_inet_config_args){ __VA_ARGS__ }) + +/** + * Update the OVSDB Wifi_Inet_Config. Fields with a default value of 0 are not updated. + * + * bools are split into two fields, one to disable and one to enable the + * option. For example, the "enabled" column can be set to true by setting + * the .if_enabled field to true, and set to false by setting the .if_disabled field + * to true. + * + * Example usage (via the above macro wrapper): + * + * WIFI_INET_CONFIG_UPDATE("eth0", .if_enable = true, ip_assign_scheme = "none", network_enable = true); + */ +bool wano_inet_config_update(const char *ifname, struct wano_inet_config_args *args); + +/* + * =========================================================================== + * WANO Connection_Manager_Uplink API - Wrapper for updating the + * Connection_Manager_Uplink table + * =========================================================================== + */ + +struct wano_connection_manager_uplink_args +{ + const char *if_type; + int priority; + wano_tri_t has_L2; + wano_tri_t has_L3; +}; + +bool wano_connection_manager_uplink_flush(void); + +#define WANO_CONNECTION_MANAGER_UPLINK_UPDATE(ifname, ...) \ + wano_connection_manager_uplink_update(ifname, &(struct wano_connection_manager_uplink_args){ __VA_ARGS__ }) + +bool wano_connection_manager_uplink_update( + const char *ifname, + struct wano_connection_manager_uplink_args *args); + +bool wano_connection_manager_uplink_delete(const char *ifname); + +/* + * =========================================================================== + * WANO Plugin Pipelines + * + * A plug-in pipeline manages execution of plug-ins on an interface. The + * pipeline is responsible for scheduling plug-ins in series or in parallel + * depending on the plug-in and pipeline masks. + * =========================================================================== + */ + +/** + * Object representing a plug-in pipeline + */ +typedef struct wano_ppline wano_ppline_t; + +enum wano_ppline_status +{ + /** At least one plug-in was provisioned */ + WANO_PPLINE_OK, + /** + * No plug-in was provisioned because the plug-in list queue was exhausted or + * the plug-in pipeline was aborted. + */ + WANO_PPLINE_IDLE, + /** + * The pipeline was restarted, either carrier loss was detected or a plug-in + * requested a restart + */ + WANO_PPLINE_RESTART, +}; + +/** + * WANO plug-in pipeline status callback + */ +typedef void wano_ppline_status_fn_t(wano_ppline_t *self, enum wano_ppline_status status); + +/** + * WAN pipeline structure + */ +struct wano_ppline +{ + char wpl_ifname[C_IFNAME_LEN]; /**< Interface name */ + char wpl_iftype[32]; /**< Interface type */ + uint64_t wpl_plugin_emask; /**< Exclusion mask */ + uint64_t wpl_plugin_rmask; /**< Mask of currently running plug-in types */ + uint64_t wpl_plugin_imask; /**< Interface reset mask */ + struct wano_plugin *wpl_plugin_next; /**< Next plugin in the pipeline */ + wano_plugin_iter_t wpl_plugin_iter; /**< Plug-in iterator */ + ds_dlist_t wpl_plugin_waitq; /**< Queue of waiting plug-ins */ + ds_dlist_t wpl_plugin_runq; /**< Queue of currently running plug-ins */ + wano_ppline_state_t wpl_state; /**< STAM state machine */ + wano_inet_state_event_t wpl_inet_state_event; /**< Interface status monitoring */ + wano_ppline_status_fn_t *wpl_status_fn; /**< Status callback */ + bool wpl_carrier_exception; /**< Generate a PPLINE_RESTART exception on carrier loss */ + bool wpl_init; /**< True if successfully initialized */ +}; + +/** + * Initialize a plug-in pipeline on the specified interface. + * + * Only plug-ins matching the mask @p mask will be provisioned, if a plug-in + * doesn't satisfy all the bits in @p mask, it will be skipped. + * + * @param[in] self wano_ppline_t object to be initialized + * @param[in] ifname interface to runt he plug-in pipeline on + * @param[in] emask Plug-in exclusion mask -- prevents certain types of + * plug-ins from running on this pipeline + * + * @return + * In case of error, false is return and the object referenced by @p self should + * be considered invalid. + */ +bool wano_ppline_init( + wano_ppline_t *self, + const char *ifname, + const char *iftype, + uint64_t emask, + wano_ppline_status_fn_t *status_fn); + +/** + * Terminate the plug-in pipeline and stop all currently active plug-ins. + */ +void wano_ppline_fini(wano_ppline_t *self); + +#endif /* WANO_H_INCLUDED */ diff --git a/src/wano/inc/wano_localconfig.h b/src/wano/inc/wano_localconfig.h new file mode 100644 index 00000000..555ed51e --- /dev/null +++ b/src/wano/inc/wano_localconfig.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef WANO_LOCALCONFIG_H_INCLUDED +#define WANO_LOCALCONFIG_H_INCLUDED + +#include "wano_localconfig.pjs.h" +#include "pjs_gen_h.h" + +bool wano_localconfig_load(struct wano_localconfig *wc); + +#endif /* WANO_LOCALCONFIG_H_INCLUDED */ + diff --git a/src/wano/inc/wano_localconfig.pjs.h b/src/wano/inc/wano_localconfig.pjs.h new file mode 100644 index 00000000..0ab7ca3e --- /dev/null +++ b/src/wano/inc/wano_localconfig.pjs.h @@ -0,0 +1,60 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define PJS_LOCALCONFIG_PPPOE \ + PJS(wano_localconfig_pppoe, \ + PJS_BOOL(enabled) \ + PJS_STRING(username, 256) \ + PJS_STRING(password, 256)) \ + +#define PJS_LOCALCONFIG_DATASERVICE \ + PJS(wano_localconfig_dataservice, \ + PJS_BOOL(enabled) \ + PJS_INT(VLAN) \ + PJS_INT(QoS)) + +#define PJS_LOCALCONFIG_STATICIPV4 \ + PJS(wano_localconfig_staticipv4, \ + PJS_BOOL(enabled) \ + PJS_STRING(ip, 16) \ + PJS_STRING(subnet, 16) \ + PJS_STRING(gateway, 16) \ + PJS_STRING(primaryDns, 16) \ + PJS_STRING(secondaryDns, 16)) + +#define PJS_LOCALCONFIG \ + PJS(wano_localconfig, \ + PJS_STRING(wanConnectionType, 32) \ + PJS_SUB_Q(PPPoE, wano_localconfig_pppoe) \ + PJS_SUB_Q(DataService, wano_localconfig_dataservice) \ + PJS_SUB_Q(staticIPv4, wano_localconfig_staticipv4)) + +#define PJS_GEN_TABLE \ + PJS_LOCALCONFIG_PPPOE \ + PJS_LOCALCONFIG_DATASERVICE \ + PJS_LOCALCONFIG_STATICIPV4 \ + PJS_LOCALCONFIG + diff --git a/src/wano/kconfig/Kconfig.managers b/src/wano/kconfig/Kconfig.managers new file mode 100644 index 00000000..b845236b --- /dev/null +++ b/src/wano/kconfig/Kconfig.managers @@ -0,0 +1,67 @@ +menuconfig MANAGER_WANO + bool "WAN Orchestrator (WANO)" + default n + help + Enable WAN Orchestrator (WANO) + +if MANAGER_WANO + config MANAGER_WANO_CFG + string "WANO Startup configuration" + default "wano;false;needs_plan_b=true" + help + WAN Orchestrator startup configuration + + config MANAGER_WANO_IFACE_LIST + string "WANO Interface List" + default "eth0" + help + Space separated interface list that will be used for WAN probing. + + config MANAGER_WANO_PLUGIN_TIMEOUT + int "WAN plug-in link probing timeout" + default 60 + help + If the WAN plug-in probing doesn't reach a conclusion in the amount + of time defined by this option, it is terminated and WANO moves to + the next plug-in in the list. + + config MANAGER_WANO_PLUGIN_DHCPV4 + bool "WANO IPv4 DHCP plugin" + default n + help + WANO DHCPv4 plug-in for interface configuration via the DHCPv4 + protocol. + + config MANAGER_WANO_PLUGIN_DHCPV6 + bool "WANO IPv6 DHCP plugin" + default n + help + WANO DHCPv6 plug-in for interface configuration via the DHCPv6/RA + protocol. + + config MANAGER_WANO_PLUGIN_STATIC_IPV4 + bool "WANO static IPv4 plugin" + default n + help + Plugin configuring static IP address on WAN interfaces. + Configuration parameters are read from "wanp" key-value OPS, here + is the list of parameters: + "static-ipv4-ip-addr" : The IP address (string) + "static-ipv4-netmask" : The netmask (string) + "static-ipv4-gateway" : The gateway (string) + "static-ipv4-ping-addrs" : Addresses for ping (semicolon separated + list) + config MANAGER_WANO_PLUGIN_PPPOE + bool "WANO pppoe plugin" + default n + help + WANO pppoe plug-in for interface configuration via the pppoe + protocol. Configuration is read from persistant storage. + + config MANAGER_WANO_PLUGIN_VLAN + bool "WANO VLAN plugin" + default n + help + WANO pppoe plug-in for VLAN interface configuration. The VLAN + configuration is read from persistent storage. +endif diff --git a/src/wano/src/wano_connection_manager_uplink.c b/src/wano/src/wano_connection_manager_uplink.c new file mode 100644 index 00000000..1dd25f28 --- /dev/null +++ b/src/wano/src/wano_connection_manager_uplink.c @@ -0,0 +1,104 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "schema.h" +#include "ovsdb_table.h" + +#include "wano.h" + +bool wano_connection_manager_uplink_flush(void) +{ + int rc; + + ovsdb_table_t table_Connection_Manager_Uplink; + OVSDB_TABLE_INIT(Connection_Manager_Uplink, if_name); + + /* Passing an empty array as the where statement effectively deletes all rows */ + rc = ovsdb_table_delete_where(&table_Connection_Manager_Uplink, json_array()); + return rc < 0; +} + +bool wano_connection_manager_uplink_delete(const char *ifname) +{ + ovsdb_table_t table_Connection_Manager_Uplink; + + OVSDB_TABLE_INIT(Connection_Manager_Uplink, if_name); + + return ovsdb_table_delete_simple( + &table_Connection_Manager_Uplink, + "if_name", + ifname); +} + +bool wano_connection_manager_uplink_update( + const char *ifname, + struct wano_connection_manager_uplink_args *args) +{ + ovsdb_table_t table_Connection_Manager_Uplink; + struct schema_Connection_Manager_Uplink conn_up; + + memset(&conn_up, 0, sizeof(conn_up)); + conn_up._partial_update = true; + + SCHEMA_SET_STR(conn_up.if_name, ifname); + + if (args->if_type != NULL) + { + SCHEMA_SET_STR(conn_up.if_type, args->if_type); + } + + if (args->priority != 0) + { + SCHEMA_SET_INT(conn_up.priority, args->priority); + } + + if (args->has_L2 == WANO_TRI_TRUE) + { + SCHEMA_SET_INT(conn_up.has_L2, true); + } + else if (args->has_L2 == WANO_TRI_FALSE) + { + SCHEMA_SET_INT(conn_up.has_L2, false); + } + + if (args->has_L3 == WANO_TRI_TRUE) + { + SCHEMA_SET_INT(conn_up.has_L3, true); + } + else if (args->has_L3 == WANO_TRI_FALSE) + { + SCHEMA_SET_INT(conn_up.has_L3, false); + } + + OVSDB_TABLE_INIT(Connection_Manager_Uplink, if_name); + + return ovsdb_table_upsert_simple( + &table_Connection_Manager_Uplink, + "if_name", + (char *)ifname, + &conn_up, + false); +} diff --git a/src/wano/src/wano_inet_config.c b/src/wano/src/wano_inet_config.c new file mode 100644 index 00000000..55c273ba --- /dev/null +++ b/src/wano/src/wano_inet_config.c @@ -0,0 +1,136 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ovsdb_table.h" +#include "schema.h" +#include "wano.h" +#include "wano_internal.h" + +bool wano_inet_config_update( + const char *ifname, + struct wano_inet_config_args *args) +{ + struct schema_Wifi_Inet_Config inet_config; + ovsdb_table_t table_Wifi_Inet_Config; + + memset(&inet_config, 0, sizeof(inet_config)); + inet_config._partial_update = true; + + OVSDB_TABLE_INIT(Wifi_Inet_Config, if_name); + + /* + * Fill in the parameters + */ + SCHEMA_SET_STR(inet_config.if_name, ifname); + + if (args->if_type != NULL) + { + SCHEMA_SET_STR(inet_config.if_type, args->if_type); + } + + if (args->enabled == WANO_TRI_TRUE) + { + SCHEMA_SET_INT(inet_config.enabled, true); + } + + if (args->enabled == WANO_TRI_FALSE) + { + SCHEMA_SET_INT(inet_config.enabled, false); + } + + if (args->network == WANO_TRI_TRUE) + { + SCHEMA_SET_INT(inet_config.network, true); + } + + if (args->network == WANO_TRI_FALSE) + { + SCHEMA_SET_INT(inet_config.network, false); + } + + if (args->nat == WANO_TRI_TRUE) + { + SCHEMA_SET_INT(inet_config.NAT, true); + } + + if (args->nat == WANO_TRI_FALSE) + { + SCHEMA_SET_INT(inet_config.NAT, false); + } + + if (args->ip_assign_scheme != NULL) + { + SCHEMA_SET_STR(inet_config.ip_assign_scheme, args->ip_assign_scheme); + } + + if (args->inet_addr != NULL) + { + SCHEMA_SET_STR(inet_config.inet_addr, args->inet_addr); + } + + if (args->netmask != NULL) + { + SCHEMA_SET_STR(inet_config.netmask, args->netmask); + } + + if (args->gateway != NULL) + { + SCHEMA_SET_STR(inet_config.gateway, args->gateway); + } + + if (args->dns1 != NULL) + { + inet_config.dns_present = true; + STRSCPY(inet_config.dns_keys[inet_config.dns_len], "primary"); + STRSCPY(inet_config.dns[inet_config.dns_len], args->dns1); + inet_config.dns_len++; + } + + if (args->dns2 != NULL) + { + inet_config.dns_present = true; + STRSCPY(inet_config.dns_keys[inet_config.dns_len], "secondary"); + STRSCPY(inet_config.dns[inet_config.dns_len], args->dns2); + inet_config.dns_len++; + } + + if (args->parent_ifname != NULL) + { + SCHEMA_SET_STR(inet_config.parent_ifname, args->parent_ifname); + } + + if (args->vlan_id != 0) + { + SCHEMA_SET_INT(inet_config.vlan_id, args->vlan_id); + } + + return ovsdb_table_upsert_simple( + &table_Wifi_Inet_Config, + "if_name", + (char *)ifname, + &inet_config, + false); +} diff --git a/src/wano/src/wano_inet_state.c b/src/wano/src/wano_inet_state.c new file mode 100644 index 00000000..730388f4 --- /dev/null +++ b/src/wano/src/wano_inet_state.c @@ -0,0 +1,394 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * =========================================================================== + * WANO Wifi_Inet_State + * =========================================================================== + */ +#include "ovsdb_table.h" +#include "schema.h" + +#include "wano.h" +#include "wano_internal.h" + +static ovsdb_table_t table_Wifi_Inet_State; +static ovsdb_table_t table_Wifi_Master_State; + +/** + * List of cached Wifi_Inet_State structures + * + * Note: An entry on this list may exists even if there are no corresponding + * entries in OVSDB. The reason for this is that plugins can register to events + * for interfaces that do not exist yet in Wifi_Inet_State. + */ +static ds_tree_t wano_inet_state_list = DS_TREE_INIT( + ds_str_cmp, + struct wano_inet_state, + is_tnode); + +static reflink_fn_t wano_inet_state_reflink_fn; +static struct wano_inet_state *wano_inet_state_get(const char *ifname); +static void wano_inet_state_event_async_fn(struct ev_loop *loop, ev_async *w, int revent); + +void callback_Wifi_Inet_State( + ovsdb_update_monitor_t *self, + struct schema_Wifi_Inet_State *old, + struct schema_Wifi_Inet_State *new); + +void callback_Wifi_Master_State( + ovsdb_update_monitor_t *self, + struct schema_Wifi_Master_State *old, + struct schema_Wifi_Master_State *new); + +bool wano_inet_state_init(void) +{ + /* Register to Wifi_Inet_State */ + OVSDB_TABLE_INIT(Wifi_Inet_State, if_name); + if (!OVSDB_TABLE_MONITOR(Wifi_Inet_State, true)) + { + LOG(INFO, "inet_state: Error monitoring Wifi_Inet_State"); + return false; + } + + OVSDB_TABLE_INIT(Wifi_Master_State, if_name); + if (!OVSDB_TABLE_MONITOR(Wifi_Master_State, true)) + { + LOG(INFO, "inet_state: Error monitoring Wifi_Master_State"); + return false; + } + + return true; +} + +void wano_inet_state_reflink_fn(reflink_t *obj, reflink_t *sender) +{ + struct wano_inet_state *is; + + /* Received event from subscriber? */ + if (sender != NULL) + { + LOG(WARN, "inet_state: Received event from subscriber."); + return; + } + + is = CONTAINER_OF(obj, struct wano_inet_state, is_reflink); + LOG(DEBUG, "inet_state: Reached 0 count: %s", is->is_ifname); + ds_tree_remove(&wano_inet_state_list, is); + reflink_fini(&is->is_reflink); + free(is); +} + +struct wano_inet_state *wano_inet_state_get(const char *ifname) +{ + struct wano_inet_state *is; + + is = ds_tree_find(&wano_inet_state_list, (void *)ifname); + if (is != NULL) + { + return is; + } + + is = calloc(1, sizeof(struct wano_inet_state)); + STRSCPY(is->is_ifname, ifname); + + reflink_init(&is->is_reflink, "wano_inet_state"); + reflink_set_fn(&is->is_reflink, wano_inet_state_reflink_fn); + + ds_tree_insert(&wano_inet_state_list, is, is->is_ifname); + + return is; +} + +/** + * Wifi_Inet_State OVSDB monitor function + */ +void callback_Wifi_Inet_State( + ovsdb_update_monitor_t *mon, + struct schema_Wifi_Inet_State *old, + struct schema_Wifi_Inet_State *new) +{ + struct wano_inet_state *is; + const char *ifname; + int ii; + + ifname = (mon->mon_type == OVSDB_UPDATE_DEL) ? old->if_name : new->if_name; + + is = wano_inet_state_get(ifname); + if (is == NULL) + { + LOG(ERR, "inet_state: %s: Error acquiring inet_state object (Wifi_Inet_State monitor).", ifname); + return; + } + + switch (mon->mon_type) + { + case OVSDB_UPDATE_NEW: + LOG(DEBUG, "inet_state: %s: Wifi_Inet_State NEW", ifname); + reflink_ref(&is->is_reflink, 1); + break; + + case OVSDB_UPDATE_MODIFY: + break; + + case OVSDB_UPDATE_DEL: + LOG(DEBUG, "inet_state: %s: Wifi_Inet_State DEL", ifname); + /* Dereference inet_state and return */ + is->is_inet_state_valid = false; + reflink_ref(&is->is_reflink, -1); + return; + + default: + LOG(ERR, "inet_state: %s: Wifi_Inet_state monitor update error.", ifname); + return; + } + + /* + * Update cache + */ + is->is_inet_state_valid = true; + is->is_enabled = new->enabled; + is->is_network = new->network; + is->is_nat = new->NAT; + + STRSCPY(is->is_ip_assign_scheme, new->ip_assign_scheme); + + is->is_ipaddr = OSN_IP_ADDR_INIT; + if (new->inet_addr[0] != '\0' && + strcmp(new->inet_addr, "0.0.0.0") != 0 && + !osn_ip_addr_from_str(&is->is_ipaddr, new->inet_addr)) + { + LOG(WARN, "inet_state: %s: Error parsing Wifi_Inet_State:inet_addr: '%s'", ifname, new->inet_addr); + } + + is->is_netmask = OSN_IP_ADDR_INIT; + if (new->netmask[0] != '\0' && + strcmp(new->netmask, "0.0.0.0") != 0 && + !osn_ip_addr_from_str(&is->is_netmask, new->netmask)) + { + LOG(WARN, "inet_state: %s: Error parsing Wifi_Inet_State:netmask: '%s'", ifname, new->netmask); + } + + is->is_gateway = OSN_IP_ADDR_INIT; + if (new->gateway[0] != '\0' && + strcmp(new->gateway, "0.0.0.0") != 0 && + !osn_ip_addr_from_str(&is->is_gateway, new->gateway)) + { + LOG(WARN, "inet_state: %s: Error parsing Wifi_Inet_State:gateway: '%s'", ifname, new->gateway); + } + + is->is_dns1 = OSN_IP_ADDR_INIT; + is->is_dns2 = OSN_IP_ADDR_INIT; + + for (ii = 0; ii < new->dns_len; ii++) + { + osn_ip_addr_t *dns; + + if (strcmp(new->dns_keys[ii], "primary") == 0) + { + dns = &is->is_dns1; + } + else if (strcmp(new->dns_keys[ii], "secondary") == 0) + { + dns = &is->is_dns2; + } + else + { + continue; + } + + if (!osn_ip_addr_from_str(dns, new->dns[ii])) + { + LOG(DEBUG, "inet_state: %s: Error parsing Wifi_Inet_State:dns[%s] = %s", + ifname, new->dns_keys[ii], new->dns[ii]); + continue; + } + } + + LOG(DEBUG, "inet_state: %s: Wifi_Inet_State ADD/MOD[%d] enabled=%d, network=%d, inet_addr=" + PRI_osn_ip_addr" netmask="PRI_osn_ip_addr" gateway="PRI_osn_ip_addr" ip_assign_scheme=%s dns1=%s dns2=%s", + ifname, + mon->mon_type == OVSDB_UPDATE_MODIFY, + is->is_enabled, + is->is_network, + FMT_osn_ip_addr(is->is_ipaddr), + FMT_osn_ip_addr(is->is_netmask), + FMT_osn_ip_addr(is->is_gateway), + is->is_ip_assign_scheme, + FMT_osn_ip_addr(is->is_dns1), + FMT_osn_ip_addr(is->is_dns2)); + + reflink_signal(&is->is_reflink); +} + +/** + * Wifi_Master_State OVSDB monitor function + */ +void callback_Wifi_Master_State( + ovsdb_update_monitor_t *mon, + struct schema_Wifi_Master_State *old, + struct schema_Wifi_Master_State *new) +{ + struct wano_inet_state *is; + const char *ifname; + + ifname = (mon->mon_type == OVSDB_UPDATE_DEL) ? old->if_name : new->if_name; + + is = wano_inet_state_get(ifname); + if (is == NULL) + { + LOG(ERR, "inet_state: %s: Error acquiring inet_state object (Wifi_Master_State monitor).", ifname); + return; + } + + switch (mon->mon_type) + { + case OVSDB_UPDATE_NEW: + LOG(DEBUG, "inet_state: %s: Wifi_Master_State NEW", ifname); + reflink_ref(&is->is_reflink, 1); + break; + + case OVSDB_UPDATE_MODIFY: + break; + + case OVSDB_UPDATE_DEL: + LOG(DEBUG, "inet_state: %s: Wifi_Master_State DEL", ifname); + /* Dereference inet_state and return */ + is->is_master_state_valid = false; + reflink_ref(&is->is_reflink, -1); + return; + + default: + LOG(ERR, "inet_state: Wifi_Master_State monitor update error."); + return; + } + + is->is_master_state_valid = true; + is->is_port_state = strcmp(new->port_state, "active") == 0; + + if (new->inet_addr[0] == '\0' || + strcmp(new->inet_addr, "0.0.0.0") == 0 || + !osn_ip_addr_from_str(&is->is_ipaddr, new->inet_addr)) + { + is->is_ipaddr = OSN_IP_ADDR_INIT; + } + + LOG(DEBUG, "inet_state: Wifi_Master_State ADD/MOD[%d] ifname=%s,", + mon->mon_type == OVSDB_UPDATE_MODIFY, + is->is_ifname); + + reflink_signal(&is->is_reflink); +} + +void wano_inet_state_event_reflink_fn(reflink_t *ref, reflink_t *sender) +{ + wano_inet_state_event_t *self = CONTAINER_OF(ref, wano_inet_state_event_t, ise_inet_state_reflink); + + if (sender == NULL) + { + LOG(DEBUG, "inet_state_event: Reached 0 count: %s", + self->ise_inet_state->is_ifname); + return; + } + + /* + * Propagate events only when we get a valid Wifi_Inet_State and a valid + * Wifi_Master_State update. + * + * Always use the async event since we want to avoid re-entrancy issues + * with reflinks. + */ + if (self->ise_inet_state->is_inet_state_valid && + self->ise_inet_state->is_master_state_valid) + { + wano_inet_state_event_refresh(self); + } +} + +/** + * Register to Wifi_Inet_State update events + */ +bool wano_inet_state_event_init( + wano_inet_state_event_t *self, + const char *ifname, + wano_inet_state_event_fn_t *fn) +{ + memset(self, 0, sizeof(*self)); + + self->ise_event_fn = fn; + + self->ise_inet_state = wano_inet_state_get(ifname); + if (self->ise_inet_state == NULL) + { + LOG(ERR, "inet_state: %s: Error acquiring inet_state object.", ifname); + return false; + } + + reflink_init(&self->ise_inet_state_reflink, "wifi_inet_state_event.ie_inet_state_reflink"); + reflink_set_fn(&self->ise_inet_state_reflink, wano_inet_state_event_reflink_fn); + reflink_connect(&self->ise_inet_state_reflink, &self->ise_inet_state->is_reflink); + + ev_async_init(&self->ise_async, wano_inet_state_event_async_fn); + ev_async_start(EV_DEFAULT, &self->ise_async); + + self->ise_init = true; + + wano_inet_state_event_refresh(self); + + return true; +} + +void wano_inet_state_event_fini(wano_inet_state_event_t *self) +{ + if (!self->ise_init) + { + return; + } + + self->ise_init = false; + + ev_async_stop(EV_DEFAULT, &self->ise_async); + reflink_disconnect(&self->ise_inet_state_reflink, &self->ise_inet_state->is_reflink); + reflink_fini(&self->ise_inet_state_reflink); +} + +/* + * Force a state refresh + */ +void wano_inet_state_event_refresh(wano_inet_state_event_t *self) +{ + ev_async_send(EV_DEFAULT, &self->ise_async); +} + +void wano_inet_state_event_async_fn(struct ev_loop *loop, ev_async *w, int revent) +{ + (void)loop; + (void)revent; + + wano_inet_state_event_t *self = CONTAINER_OF(w, wano_inet_state_event_t, ise_async); + + self->ise_event_fn(self, self->ise_inet_state); +} diff --git a/src/wano/src/wano_internal.h b/src/wano/src/wano_internal.h new file mode 100644 index 00000000..99a4f549 --- /dev/null +++ b/src/wano/src/wano_internal.h @@ -0,0 +1,43 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef WANO_INTERNAL_H_INCLUDED +#define WANO_INTERNAL_H_INCLUDED + +#include + +#include "wano.h" +#include "const.h" +#include "ds_dlist.h" + +/* + * =========================================================================== + * Wifi_Inet_State/Wifi_Master_State + * =========================================================================== + */ +bool wano_inet_state_init(void); + +#endif /* WANO_INTERNAL_H_INCLUDED */ diff --git a/src/wano/src/wano_localconfig.c b/src/wano/src/wano_localconfig.c new file mode 100644 index 00000000..213afea7 --- /dev/null +++ b/src/wano/src/wano_localconfig.c @@ -0,0 +1,110 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include "log.h" +#include "osp_ps.h" + +#include "wano_localconfig.h" + +#include "wano_localconfig.pjs.h" +#include "pjs_gen_c.h" + +bool wano_localconfig_load(struct wano_localconfig *wc) +{ + pjs_errmsg_t perr; + json_error_t jerr; + ssize_t bufsz; + + json_t *jbuf = NULL; + osp_ps_t *ps = NULL; + char *buf = NULL; + + bool retval = false; + + ps = osp_ps_open("local_config", OSP_PS_PRESERVE | OSP_PS_READ); + if (ps == NULL) + { + LOG(DEBUG, "wano_localconfig: Unable to open local_config store."); + goto exit; + } + + bufsz = osp_ps_get(ps, "wan", NULL, 0); + if (bufsz <= 0) + { + LOG(DEBUG, "wano_localconfig: No 'wan' key in store."); + goto exit; + } + + buf = malloc(bufsz + 1); + if (buf == NULL) + { + LOG(ERR, "wano_localconfig: Unable to allocate buffer for local_config."); + goto exit; + } + + if (osp_ps_get(ps, "wan", buf, bufsz) != bufsz) + { + LOG(ERR, "wano_localcnfig: Short read when reading 'wan' key."); + goto exit; + } + + /* Null terminate it, just in case */ + buf[bufsz] = '\0'; + + jbuf = json_loads(buf, 0, &jerr); + if (jbuf == NULL) + { + LOG(ERR, "wano_localconfig: Error parsing local_config: %s", jerr.text); + goto exit; + } + + if (!wano_localconfig_from_json(wc, jbuf, false, perr)) + { + LOG(ERR, "wano_localconfig: Invalid configuration: %s", perr); + goto exit; + } + + retval = true; +exit: + if (jbuf != NULL) + { + json_decref(jbuf); + } + + if (buf != NULL) + { + free(buf); + } + + if (ps != NULL) + { + osp_ps_close(ps); + } + + return retval; +} diff --git a/src/wano/src/wano_main.c b/src/wano/src/wano_main.c new file mode 100644 index 00000000..95062432 --- /dev/null +++ b/src/wano/src/wano_main.c @@ -0,0 +1,162 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include + +#include "const.h" +#include "json_util.h" +#include "log.h" +#include "module.h" +#include "os.h" +#include "os_backtrace.h" +#include "ovsdb.h" +#include "target.h" + +#include "wano.h" +#include "wano_internal.h" + +#define MODULE_ID LOG_MODULE_ID_MAIN + +static log_severity_t wano_log_severity = LOG_SEVERITY_INFO; + +/* + * WANO plug-in pipelines associated with built-in interfaces + */ +static int wano_builtin_pplines_len = 0; +static wano_ppline_t *wano_builtin_pplines = NULL; + +/* + * Start built-in WAN interfaces + */ +void wano_start_builtin_ifaces(void) +{ + char iflist[] = CONFIG_MANAGER_WANO_IFACE_LIST; + char *pif; + char *psave; + int ii; + + /* Split interface string and calculate its length */ + wano_builtin_pplines_len = 0; + for (pif = strtok_r(iflist, " ", &psave); + pif != NULL; + pif = strtok_r(NULL, " ", &psave)) + { + wano_builtin_pplines_len++; + } + + wano_builtin_pplines = calloc(wano_builtin_pplines_len, sizeof(wano_builtin_pplines[0])); + + pif = iflist; + for (ii = 0; ii < wano_builtin_pplines_len; ii++) + { + /* Add plug-in pipeline to interface */ + if (!wano_ppline_init(&wano_builtin_pplines[ii], pif, "eth", 0, NULL)) + { + LOG(ERR, "wano: %s: Error starting plug-in interface on built-in interface.", pif); + } + else + { + LOG(NOTICE, "wano: %s: Started plug-in pipeline on built-in interface.", pif); + } + + /* Move to next interface */ + pif += strlen(pif) + 1; + } +} + +void wano_stop_builtin_ifaces(void) +{ + int ii; + + for (ii = 0; ii < wano_builtin_pplines_len; ii++) + { + wano_ppline_fini(&wano_builtin_pplines[ii]); + } +} + +int main(int argc, char *argv[]) +{ + // Parse command-line arguments + if (os_get_opt(argc, argv, &wano_log_severity)) + { + return 1; + } + + // enable logging + target_log_open("WANO", 0); + LOG(NOTICE, "Starting WAN Orchestrator - WANO"); + log_severity_set(wano_log_severity); + log_register_dynamic_severity(EV_DEFAULT); + + backtrace_init(); + + json_memdbg_init(EV_DEFAULT); + + // Connect to ovsdb + if (!ovsdb_init_loop(EV_DEFAULT, "WANO")) + { + LOG(EMERG, "Initializing WANO (Failed to initialize OVSDB)"); + return 1; + } + + // Initialize the Wifi_Inet_State/Wifi_Master_State watchers + if (!wano_inet_state_init()) + { + LOG(EMERG, "Error initializing WANO Inet_State."); + return 1; + } + + // Initialize WAN plug-ins + module_init(); + + // Delete all Connection_Manager_Uplink rows + if (wano_connection_manager_uplink_flush()) + { + LOG(WARN, "wano: Error clearing the Connection_Manager_Uplink table."); + } + + // Scan built-in list of WAN interfaces and start each one + wano_start_builtin_ifaces(); + + ev_run(EV_DEFAULT, 0); + + wano_stop_builtin_ifaces(); + + if (!ovsdb_stop_loop(EV_DEFAULT)) + { + LOG(ERR, "Stopping WANO (Failed to stop OVSDB"); + } + + module_fini(); + + ev_default_destroy(); + + LOG(NOTICE, "Exiting WANO"); + + return 0; +} diff --git a/src/wano/src/wano_plugin.c b/src/wano/src/wano_plugin.c new file mode 100644 index 00000000..043ae744 --- /dev/null +++ b/src/wano/src/wano_plugin.c @@ -0,0 +1,150 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * =========================================================================== + * WAN Orchestrator Plug-in management + * =========================================================================== + */ + +#include "log.h" +#include "module.h" +#include "osa_assert.h" + +#include "wano.h" + +static ds_key_cmp_t wanp_cmp; + +static ds_tree_t wano_plugin_list = DS_TREE_INIT(wanp_cmp, struct wano_plugin, _wanp_tnode); + +void wano_plugin_register(struct wano_plugin *wp) +{ + LOG(INFO, "wano_plugin: Registering plug-in: %s (priority %g)", + wp->wanp_name, wp->wanp_priority); + + ds_tree_insert(&wano_plugin_list, wp, wp); +} + +void wano_plugin_unregister(struct wano_plugin *wp) +{ + LOG(INFO, "wano_plugin: Un-registering plug-in: %s (priority %g)", + wp->wanp_name, wp->wanp_priority); + + ASSERT(ds_tree_find(&wano_plugin_list, wp) != NULL, "WANO plug-in double unregister") + + ds_tree_remove(&wano_plugin_list, wp); +} + +struct wano_plugin *wano_plugin_first(wano_plugin_iter_t *iter) +{ + return ds_tree_ifirst(&iter->wpi_iter, &wano_plugin_list); +} + +struct wano_plugin *wano_plugin_next(wano_plugin_iter_t *iter) +{ + return ds_tree_inext(&iter->wpi_iter); +} + +struct wano_plugin *wano_plugin_find(const char *name) +{ + struct wano_plugin *wp; + + /* + * We cannot really do a lookup only by name as the comparator function + * requires both the priority and the name. + * + * We want to return the plug-in with the lowest priority that matches the + * name + */ + ds_tree_foreach(&wano_plugin_list, wp) + { + if (strcmp(wp->wanp_name, name) == 0) return wp; + } + + return NULL; +} + +wano_plugin_handle_t *wano_plugin_init( + struct wano_plugin *wp, + const char *ifname, + wano_plugin_status_fn_t *status_fn) +{ + wano_plugin_handle_t *wh; + + ASSERT(wp->wanp_init != NULL, "WANO plugin has NULL init function") + + wh = wp->wanp_init(wp, ifname, status_fn); + if (wh == NULL) + { + return NULL; + } + + wh->wh_plugin = wp; + STRSCPY(wh->wh_ifname, ifname); + + return wh; +} + +void wano_plugin_run(wano_plugin_handle_t *wh) +{ + ASSERT(wh->wh_plugin != NULL, "WANO handle has NULL plug-in reference") + ASSERT(wh->wh_plugin->wanp_run != NULL, "WANO plug-in has NULL run function") + + wh->wh_plugin->wanp_run(wh); +} + +bool wano_plugin_fini(wano_plugin_handle_t *wh) +{ + ASSERT(wh->wh_plugin != NULL, "WANO handle has NULL plug-in reference") + ASSERT(wh->wh_plugin->wanp_fini != NULL, "WANO plug-in has NULL fini function") + + wh->wh_plugin->wanp_fini(wh); + return true; +} + +/** + * Plug-in comparator function -- compares the priority and the name + */ +int wanp_cmp(void *_a, void *_b) +{ + int c; + + struct wano_plugin *a = _a; + struct wano_plugin *b = _b; + + /* + * We want an ordered list sorted by priority, therefore compare the + * priority first. + */ + c = a->wanp_priority - b->wanp_priority; + if (c != 0) return c; + + c = strcmp(a->wanp_name, b->wanp_name); + if (c != 0) return c; + + return 0; +} + diff --git a/src/wano/src/wano_ppline.c b/src/wano/src/wano_ppline.c new file mode 100644 index 00000000..77e9c0ce --- /dev/null +++ b/src/wano/src/wano_ppline.c @@ -0,0 +1,885 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * =========================================================================== + * WAN plug-in pipeline management module + * + * A plug-in pipeline is responsible for executing plug-ins on an interface. + * There can be multiple independent pipelines running on a single interface. + * Plug-ins can be executed in series or in parallel, depending on the plug-in + * and pipeline masks. + * + * There can be multiple pipe-lines associated with a single interface as + * plug-ins are capable of creating their own pipelines. + * =========================================================================== + */ +#include +#include + +#include + +#include "osa_assert.h" +#include "ovsdb_sync.h" +#include "ovsdb_table.h" + +#include "wano.h" +#include "wano_internal.h" + +/* + * Structure describing a single plug-in running on the pipeline + */ +struct wano_ppline_plugin +{ + /** True if the plug-in has been started (wano_plugin_run() was called) */ + bool wpp_running; + /** Parent pipeline */ + wano_ppline_t *wpp_ppline; + /** Plug-in structure */ + struct wano_plugin *wpp_plugin; + /** Plug-in status */ + struct wano_plugin_status wpp_status; + /** Plug-in status update async watcher */ + ev_async wpp_status_async; + /** Plug-in handle */ + wano_plugin_handle_t *wpp_handle; + /** Plug-in timeout timer */ + ev_timer wpp_timeout; + /** Linked list node structure */ + ds_dlist_t wpp_dnode; +}; + +static void wano_ppline_start_queues(wano_ppline_t *self); +static void wano_ppline_stop_queues(wano_ppline_t *self); +static void wano_ppline_schedule(wano_ppline_t *self); +static bool wano_ppline_runq_add(wano_ppline_t *self, struct wano_ppline_plugin *wpp); +static bool wano_ppline_runq_start(wano_ppline_t *self); +static void __wano_ppline_runq_stop(wano_ppline_t *self, struct wano_ppline_plugin *wpp); +static void wano_ppline_runq_del(wano_ppline_t *self, struct wano_ppline_plugin *wpp); +static void wano_ppline_runq_flush(wano_ppline_t *self); +static wano_inet_state_event_fn_t wano_ppline_inet_state_event_fn; +static wano_plugin_status_fn_t wano_ppline_plugin_status_fn; +static void wano_ppline_status_async_fn(struct ev_loop *, ev_async *ev, int revent); +static void wano_ppline_plugin_timeout_fn(struct ev_loop *loop, ev_timer *w, int revent); +static void wano_ppline_reset_ipv6(wano_ppline_t *self); + +bool wano_ppline_init( + wano_ppline_t *self, + const char *ifname, + const char *iftype, + uint64_t emask, + wano_ppline_status_fn_t *status_fn) +{ + memset(self, 0, sizeof(*self)); + + STRSCPY_WARN(self->wpl_ifname, ifname); + STRSCPY_WARN(self->wpl_iftype, iftype); + self->wpl_plugin_emask = emask; + self->wpl_status_fn = status_fn; + + ds_dlist_init(&self->wpl_plugin_waitq, struct wano_ppline_plugin, wpp_dnode); + ds_dlist_init(&self->wpl_plugin_runq, struct wano_ppline_plugin, wpp_dnode); + + /* Subscribe to Wifi_Inet_State events */ + if (!wano_inet_state_event_init( + &self->wpl_inet_state_event, + self->wpl_ifname, + wano_ppline_inet_state_event_fn)) + { + LOG(ERR, "wano: %s: Error initializing inet_state_event object", self->wpl_ifname); + return false; + } + + self->wpl_init = true; + + LOG(NOTICE, "wano: %s: Created WAN pipeline on interface.", ifname); + + return true; +} + +/* + * Dispose of a wano_ppline_t object + */ +void wano_ppline_fini(wano_ppline_t *self) +{ + if (!self->wpl_init) + { + return; + } + + self->wpl_init = false; + + wano_inet_state_event_fini(&self->wpl_inet_state_event); + + wano_ppline_stop_queues(self); +} + +/* + * Initialize the plug-in run and wait queue + */ +void wano_ppline_start_queues(wano_ppline_t *self) +{ + struct wano_plugin *wp; + wano_plugin_iter_t wpi; + + /* + * Populate the waitqueue + */ + for (wp = wano_plugin_first(&wpi); wp != NULL; wp = wano_plugin_next(&wpi)) + { + struct wano_ppline_plugin *wpp; + + /* Skip all plug-ins in the exclusion mask */ + if (wp->wanp_mask & self->wpl_plugin_emask) continue; + + wpp = calloc(1, sizeof(struct wano_ppline_plugin)); + ASSERT(wpp != NULL, "failed to allocate wano_ppline_plugin"); + + wpp->wpp_ppline = self; + wpp->wpp_plugin = wp; + + ds_dlist_insert_tail(&self->wpl_plugin_waitq, wpp); + } + + if (ds_dlist_is_empty(&self->wpl_plugin_waitq)) + { + LOG(WARN, "wano: %s: Plug-in pipeline is empty (mask = %"PRIx64").", + self->wpl_ifname, self->wpl_plugin_emask); + } +} + +void wano_ppline_stop_queues(wano_ppline_t *self) +{ + ds_dlist_iter_t iter; + struct wano_ppline_plugin *wpp; + + /* + * Free the waiting queue + */ + ds_dlist_foreach_iter(&self->wpl_plugin_waitq, wpp, iter) + { + ds_dlist_iremove(&iter); + free(wpp); + } + + /* + * Free the running queue and terminate all currently running plug-ins + */ + wano_ppline_runq_flush(self); + + self->wpl_plugin_rmask = 0; +} + +/* + * Schedule next WAN plug-in on the interface. + * + * @return + * Return false if there's no more work present on the pipeline (all plug-ins + * were executed and the wait queue is empty). + */ +void wano_ppline_schedule(wano_ppline_t *self) +{ + struct wano_ppline_plugin *wpp; + ds_dlist_iter_t iter; + + /* + * Scan the current wait queue + */ + ds_dlist_foreach_iter(&self->wpl_plugin_waitq, wpp, iter) + { + /* Check if a plug-in can run according to the current run mask */ + if (self->wpl_plugin_rmask & wpp->wpp_plugin->wanp_mask) + { + LOG(DEBUG, "wano: %s: Blocked plug-in %s", + self->wpl_ifname, + wpp->wpp_plugin->wanp_name); + continue; + } + + ds_dlist_iremove(&iter); + + if (!wano_ppline_runq_add(self, wpp)) + { + /* Plug-in was unable to start, continue */ + free(wpp); + continue; + } + + self->wpl_plugin_imask |= wpp->wpp_plugin->wanp_mask; + } +} + +/* + * Add plug-in to the run-queue + */ +bool wano_ppline_runq_add(wano_ppline_t *self, struct wano_ppline_plugin *wpp) +{ + wpp->wpp_running = false; + + wpp->wpp_handle = wano_plugin_init( + wpp->wpp_plugin, + self->wpl_ifname, + wano_ppline_plugin_status_fn); + + if (wpp->wpp_handle == NULL) + { + LOG(INFO, "wano: %s: Skipping plug-in %s", + self->wpl_ifname, + wpp->wpp_plugin->wanp_name); + return false; + } + + wpp->wpp_handle->wh_data = wpp; + + self->wpl_plugin_rmask |= wpp->wpp_plugin->wanp_mask; + ds_dlist_insert_head(&self->wpl_plugin_runq, wpp); + + return true; +} + +/* + * Scan the run-queue and start all plug-ins that are not yet started + */ +bool wano_ppline_runq_start(wano_ppline_t *self) +{ + struct wano_ppline_plugin *wpp; + + if (ds_dlist_is_empty(&self->wpl_plugin_runq)) + { + return false; + } + + ds_dlist_foreach(&self->wpl_plugin_runq, wpp) + { + if (wpp->wpp_running) + { + continue; + } + + LOG(INFO, "wano: %s: Starting plug-in %s", + self->wpl_ifname, + wpp->wpp_plugin->wanp_name); + + ev_timer_init(&wpp->wpp_timeout, wano_ppline_plugin_timeout_fn, CONFIG_MANAGER_WANO_PLUGIN_TIMEOUT, 0.0); + ev_timer_start(EV_DEFAULT, &wpp->wpp_timeout); + + ev_async_init(&wpp->wpp_status_async, wano_ppline_status_async_fn); + ev_async_start(EV_DEFAULT, &wpp->wpp_status_async); + + wano_plugin_run(wpp->wpp_handle); + + wpp->wpp_running = true; + } + + return true; +} + +/* + * Remove a plug-in on the run queue; if the plug-in is running, terminate it + */ +void __wano_ppline_runq_stop(wano_ppline_t *self, struct wano_ppline_plugin *wpp) +{ + self->wpl_plugin_rmask &= ~wpp->wpp_plugin->wanp_mask; + + /* If the plug-in reported its own interface for WAN, clear the uplink table */ + if (wpp->wpp_status.ws_ifname[0] != '\0') + { + if (!wano_connection_manager_uplink_delete(wpp->wpp_status.ws_ifname)) + { + LOG(ERR, "wano: %s: Error clearing Connection_Manager_Uplink.", + wpp->wpp_status.ws_ifname); + } + } + + if (wpp->wpp_handle != NULL) + { + wano_plugin_fini(wpp->wpp_handle); + wpp->wpp_handle = NULL; + } + + /* Stop the async status handler */ + ev_async_stop(EV_DEFAULT, &wpp->wpp_status_async); + + /* Stop the timeout handler */ + ev_timer_stop(EV_DEFAULT, &wpp->wpp_timeout); +} + +void wano_ppline_runq_del(wano_ppline_t *self, struct wano_ppline_plugin *wpp) +{ + /* Remove the plug-in from the runqueue and clear the run mask */ + __wano_ppline_runq_stop(self, wpp); + ds_dlist_remove(&self->wpl_plugin_runq, wpp); +} + +static void wano_ppline_runq_flush(wano_ppline_t *self) +{ + ds_dlist_iter_t iter; + struct wano_ppline_plugin *wpp; + + ds_dlist_foreach_iter(&self->wpl_plugin_runq, wpp, iter) + { + ds_dlist_iremove(&iter); + __wano_ppline_runq_stop(self, wpp); + free(wpp); + } +} + +void wano_ppline_inet_state_event_fn( + struct wano_inet_state_event *event, + struct wano_inet_state *status) +{ + wano_ppline_t *self = CONTAINER_OF(event, wano_ppline_t, wpl_inet_state_event); + if (self->wpl_carrier_exception && !status->is_port_state) + { + LOG(NOTICE, "wano: %s: Carrier loss detected.", self->wpl_ifname); + self->wpl_carrier_exception = false; + wano_ppline_state_do(&self->wpl_state, wano_ppline_exception_PPLINE_RESTART, NULL); + } + else + { + wano_ppline_state_do(&self->wpl_state, wano_ppline_do_INET_STATE_UPDATE, status); + } +} + +void wano_ppline_plugin_status_fn(wano_plugin_handle_t *ph, struct wano_plugin_status *ps) +{ + struct wano_ppline_plugin *wpp = ph->wh_data; + + /* Update local copy of the status and schedule an async event */ + wpp->wpp_status = *ps; + ev_async_send(EV_DEFAULT, &wpp->wpp_status_async); +} + +/* + * Process plug-in events asynchronously. Note that if a plug-in sends several + * events in a rapid succession, they may get compressed into a single event. + */ +void wano_ppline_status_async_fn(struct ev_loop *loop, ev_async *ev, int revent) +{ + (void)loop; + (void)revent; + + struct wano_ppline_plugin *wpp = CONTAINER_OF(ev, struct wano_ppline_plugin, wpp_status_async); + wano_ppline_t *self = wpp->wpp_ppline; + char *ifname = self->wpl_ifname; + char *iftype = self->wpl_iftype; + + switch (wpp->wpp_status.ws_type) + { + case WANP_OK: + LOG(INFO, "wano: %s: WAN Plug-in success: %s", + self->wpl_ifname, wano_plugin_name(wpp->wpp_handle)); + + /* Stop the timeout timer */ + ev_timer_stop(EV_DEFAULT, &wpp->wpp_timeout); + + /* Use the interface name and type reported in the plug-in status */ + if (wpp->wpp_status.ws_ifname[0] != '\0') + { + ifname = wpp->wpp_status.ws_ifname; + } + + if (wpp->wpp_status.ws_iftype[0] != '\0') + { + iftype = wpp->wpp_status.ws_iftype; + } + + /* Update the connection manager table */ + if (!WANO_CONNECTION_MANAGER_UPLINK_UPDATE( + ifname, + .if_type = iftype, + .has_L2 = WANO_TRI_TRUE, + .has_L3 = WANO_TRI_TRUE)) + { + LOG(WARN, "wano: %s: Error updating Connection_Manager_Uplink table (has_L3 = true).", + self->wpl_ifname); + } + + /* Notify upper layers */ + if (self->wpl_status_fn != NULL) + { + self->wpl_status_fn(self, WANO_PPLINE_OK); + } + return; + + case WANP_SKIP: + LOG(INFO, "wano: %s: Plug-in requested skip: %s", self->wpl_ifname, wano_plugin_name(wpp->wpp_handle)); + wano_ppline_runq_del(self, wpp); + free(wpp); + wano_ppline_state_do(&self->wpl_state, wano_ppline_do_PLUGIN_UPDATE, NULL); + break; + + case WANP_BUSY: + LOG(INFO, "wano: %s: Plug-in %s is busy, stopping timeout timer.", self->wpl_ifname, wano_plugin_name(wpp->wpp_handle)); + + /* Stop the timeout timer */ + ev_timer_stop(EV_DEFAULT, &wpp->wpp_timeout); + break; + + case WANP_ERROR: + LOG(ERR, "wano: %s: Error detected running plug-in: %s. Skipping.", + self->wpl_ifname, wano_plugin_name(wpp->wpp_handle)); + + wano_ppline_runq_del(self, wpp); + free(wpp); + wano_ppline_state_do(&self->wpl_state, wano_ppline_do_PLUGIN_UPDATE, NULL); + break; + + case WANP_RESTART: + wano_ppline_state_do(&self->wpl_state, wano_ppline_exception_PPLINE_RESTART, NULL); + break; + + case WANP_ABORT: + /* + * Abort processing of the current pipeline + */ + wano_ppline_state_do(&self->wpl_state, wano_ppline_exception_PPLINE_ABORT, NULL); + break; + } +} + +void wano_ppline_plugin_timeout_fn(struct ev_loop *loop, ev_timer *w, int revent) +{ + (void)loop; + (void)revent; + + struct wano_ppline_plugin *wpp = CONTAINER_OF(w, struct wano_ppline_plugin, wpp_timeout); + wano_ppline_t *self = wpp->wpp_ppline; + + LOG(NOTICE, "wano: %s: Plug-in timed out: %s. Terminating.", + self->wpl_ifname, wano_plugin_name(wpp->wpp_handle)); + + wano_ppline_runq_del(self, wpp); + free(wpp); + + wano_ppline_state_do(&self->wpl_state, wano_ppline_do_PLUGIN_UPDATE, NULL); +} + +void wano_ppline_reset_ipv6(wano_ppline_t *self) +{ + ovsdb_table_t table_IP_Interface; + ovsdb_table_t table_DHCPv6_Client; + ovsdb_table_t table_DHCPv6_Server; + ovsdb_table_t table_IPv6_RouteAdv; + + struct schema_IP_Interface ip_interface; + + OVSDB_TABLE_INIT(IP_Interface, _uuid); + OVSDB_TABLE_INIT(DHCPv6_Client, _uuid); + OVSDB_TABLE_INIT(DHCPv6_Server, _uuid); + OVSDB_TABLE_INIT(IPv6_RouteAdv, _uuid); + + if (!ovsdb_table_select_one(&table_IP_Interface, "if_name", self->wpl_ifname, &ip_interface)) + { + /* No entry in IP_Interface -- we're good */ + LOG(INFO, "wano: %s: IP_Interface no entry for if_name.", self->wpl_ifname); + return; + } + + ovsdb_table_delete_where(&table_DHCPv6_Client, ovsdb_where_uuid("ip_interface", ip_interface._uuid.uuid)); + ovsdb_table_delete_where(&table_DHCPv6_Server, ovsdb_where_uuid("interface", ip_interface._uuid.uuid)); + ovsdb_table_delete_where(&table_IPv6_RouteAdv, ovsdb_where_uuid("interface", ip_interface._uuid.uuid)); + ovsdb_table_delete_where(&table_IP_Interface, ovsdb_where_uuid("_uuid", ip_interface._uuid.uuid)); +} + +/* + * =========================================================================== + * State Machine + * =========================================================================== + */ + +/* + * Move to the IF_L2_RESET state if WANO_PLUGIN_MASK_L2 is not set + */ +enum wano_ppline_state wano_ppline_state_INIT( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)action; + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + + /* Remove any entries in the Connection_Manager_Uplink table */ + if (wano_connection_manager_uplink_delete(self->wpl_ifname)) + { + LOG(INFO, "wano: %s: Stale Connection_Manager_Uplink entry was removed.", self->wpl_ifname); + } + + if (!WANO_CONNECTION_MANAGER_UPLINK_UPDATE( + self->wpl_ifname, + .if_type = self->wpl_iftype, + .has_L2 = WANO_TRI_FALSE)) + { + LOG(WARN, "wano: %s: Error updating Connection_Manager_Uplink (iftype = %s, has_L2 = false)", + self->wpl_ifname, self->wpl_iftype); + } + + wano_ppline_start_queues(self); + + /* + * Do not reset the interface L2 layer + */ + if (self->wpl_plugin_emask & WANO_PLUGIN_MASK_L2) + { + return wano_ppline_IF_ENABLE; + } + + return wano_ppline_IF_L2_RESET; +} + +/* + * The IF_L2_RESET state simply sets the Wifi_Inet_Config:enabled,network fields + * to false and waits until Wifi_Inet_State reflects the change. + */ +enum wano_ppline_state wano_ppline_state_IF_L2_RESET( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + struct wano_inet_state *is = data; + + switch (action) + { + case wano_ppline_do_STATE_INIT: + LOG(INFO, "wano: %s: Resetting interface L2.", self->wpl_ifname); + if (!WANO_INET_CONFIG_UPDATE( + self->wpl_ifname, + .if_type = self->wpl_iftype, + .enabled = WANO_TRI_FALSE, + .network = WANO_TRI_FALSE)) + { + LOG(WARN, "wano: %s: Error writing Wifi_Inet_Config in IF_L2_RESET.", self->wpl_ifname); + } + + wano_inet_state_event_refresh(&self->wpl_inet_state_event); + return 0; + + case wano_ppline_do_INET_STATE_UPDATE: + if (is->is_enabled) break; + if (is->is_network) break; + + return wano_ppline_IF_ENABLE; + + default: + break; + } + + return 0; +} + +/* + * Re-enable the interface -- set Wifi_Inet_Config:enabled,network to true + * and wait until Wifi_Inet_State reflects the change + */ +enum wano_ppline_state wano_ppline_state_IF_ENABLE( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + struct wano_inet_state *is = data; + + switch (action) + { + case wano_ppline_do_STATE_INIT: + LOG(INFO, "wano: %s: Enabling interface.", self->wpl_ifname); + if (!WANO_INET_CONFIG_UPDATE( + self->wpl_ifname, + .if_type = self->wpl_iftype, + .enabled = WANO_TRI_TRUE, + .network = WANO_TRI_TRUE, + .nat = WANO_TRI_TRUE)) + { + LOG(WARN, "wano: %s: Error writing Wifi_Inet_Config in IF_ENABLE.", self->wpl_ifname); + } + wano_inet_state_event_refresh(&self->wpl_inet_state_event); + return 0; + + case wano_ppline_do_INET_STATE_UPDATE: + if (!is->is_enabled) break; + if (!is->is_network) break; + if (!is->is_nat) break; + return wano_ppline_IF_CARRIER; + + default: + break; + } + + return 0; +} + +/* + * Wait until there's carrier on the interface + */ +enum wano_ppline_state wano_ppline_state_IF_CARRIER( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + struct wano_inet_state *is = data; + + switch (action) + { + case wano_ppline_do_STATE_INIT: + LOG(INFO, "wano: %s: Waiting for carrier.", self->wpl_ifname); + wano_inet_state_event_refresh(&self->wpl_inet_state_event); + break; + + case wano_ppline_do_INET_STATE_UPDATE: + if (!is->is_port_state) + { + break; + } + + self->wpl_carrier_exception = true; + + if (!WANO_CONNECTION_MANAGER_UPLINK_UPDATE(self->wpl_ifname, .has_L2 = WANO_TRI_TRUE)) + { + LOG(WARN, "wano: %s: Error updating Connection_Manager_Uplinkg talbe (has_L2 = true).", + self->wpl_ifname); + } + + LOG(INFO, "wano: %s: Carrier detected.", self->wpl_ifname); + return wano_ppline_PLUGIN_SCHED; + + default: + break; + } + + return 0; +} + +enum wano_ppline_state wano_ppline_state_PLUGIN_SCHED( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)action; + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + + switch (action) + { + case wano_ppline_do_STATE_INIT: + LOG(DEBUG, "Scheduling plugins."); + wano_ppline_schedule(self); + break; + + default: + break; + } + + return wano_ppline_IF_IPV4_RESET; +} + +enum wano_ppline_state wano_ppline_state_IF_IPV4_RESET( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)action; + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + struct wano_inet_state *is = data; + + switch (action) + { + case wano_ppline_do_STATE_INIT: + if (!(self->wpl_plugin_imask & WANO_PLUGIN_MASK_IPV4)) + { + return wano_ppline_IF_IPV6_RESET; + } + + LOG(INFO, "wano: %s: An IPv4 plugin is scheduled to run, resetting IPv4 settings.", + self->wpl_ifname); + + self->wpl_plugin_imask &= ~WANO_PLUGIN_MASK_IPV4; + + WANO_INET_CONFIG_UPDATE(self->wpl_ifname, .ip_assign_scheme = "none"); + wano_inet_state_event_refresh(&self->wpl_inet_state_event); + break; + + case wano_ppline_do_INET_STATE_UPDATE: + if (strcmp(is->is_ip_assign_scheme, "none") != 0) break; + return wano_ppline_IF_IPV6_RESET; + + default: + break; + } + + return 0; +} + +enum wano_ppline_state wano_ppline_state_IF_IPV6_RESET( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)state; + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + + switch (action) + { + case wano_ppline_do_STATE_INIT: + if (!(self->wpl_plugin_imask & WANO_PLUGIN_MASK_IPV6)) + { + return wano_ppline_PLUGIN_RUN; + } + + LOG(INFO, "wano: %s: An IPv6 plugin is scheduled to run, resetting IPv6 settings.", + self->wpl_ifname); + + wano_ppline_reset_ipv6(self); + + self->wpl_plugin_imask &= ~WANO_PLUGIN_MASK_IPV6; + return wano_ppline_PLUGIN_RUN; + + default: + break; + } + + return 0; +} + +enum wano_ppline_state wano_ppline_state_PLUGIN_RUN( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)state; + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + + switch (action) + { + case wano_ppline_do_STATE_INIT: + if (wano_ppline_runq_start(self)) + { + break; + } + + LOG(NOTICE, "wano: %s: Pipeline has no active plug-ins.", self->wpl_ifname); + return wano_ppline_IDLE; + + case wano_ppline_do_PLUGIN_UPDATE: + return wano_ppline_PLUGIN_SCHED; + + default: + break; + } + + return 0; +} + +enum wano_ppline_state wano_ppline_state_IDLE( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)state; + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + + switch (action) + { + case wano_ppline_do_STATE_INIT: + /* + * Update connection manager table + */ + if (!WANO_CONNECTION_MANAGER_UPLINK_UPDATE(self->wpl_ifname, .has_L3 = WANO_TRI_FALSE)) + { + LOG(WARN, "wano: %s: Error updating the Connection_Manager_Uplink table (has_L3 = false)", + self->wpl_ifname); + } + + if (self->wpl_status_fn != NULL) + { + self->wpl_status_fn(self, WANO_PPLINE_IDLE); + } + + /* + * Disable NAT + */ + if (!WANO_INET_CONFIG_UPDATE( + self->wpl_ifname, + .nat = WANO_TRI_FALSE)) + { + LOG(WARN, "wano: %s: Error disabling NAT.", self->wpl_ifname); + } + + break; + + default: + break; + } + + return 0; +} + +enum wano_ppline_state wano_ppline_state_EXCEPTION( + wano_ppline_state_t *state, + enum wano_ppline_action action, + void *data) +{ + (void)data; + + wano_ppline_t *self = CONTAINER_OF(state, wano_ppline_t, wpl_state); + + /* + * Tear-down the wait and run queues and any plug-ins on them + */ + wano_ppline_stop_queues(self); + + switch (action) + { + case wano_ppline_exception_PPLINE_RESTART: + /* Return to the init state */ + if (self->wpl_status_fn != NULL) + { + self->wpl_status_fn(self, WANO_PPLINE_RESTART); + } + + return wano_ppline_INIT; + + case wano_ppline_exception_PPLINE_ABORT: + return wano_ppline_IDLE; + + default: + break; + } + + return 0; +} diff --git a/src/wano/src/wano_ppline.dot b/src/wano/src/wano_ppline.dot new file mode 100644 index 00000000..a76080c3 --- /dev/null +++ b/src/wano/src/wano_ppline.dot @@ -0,0 +1,20 @@ +digraph { + INIT[init="true"]; + + INIT -> IF_L2_RESET[label="STATE_INIT"]; + INIT -> IF_ENABLE[label="STATE_INIT"]; + IF_L2_RESET -> IF_ENABLE [label="INET_STATE_UPDATE"]; + IF_ENABLE -> IF_CARRIER[label="INET_STATE_UPDATE"]; + IF_CARRIER -> PLUGIN_SCHED [label="INET_STATE_UPDATE"]; + PLUGIN_SCHED -> IF_IPV4_RESET; + IF_IPV4_RESET -> PLUGIN_SCHED [label="PLUGIN_UPDATE"]; + IF_IPV4_RESET -> IF_IPV6_RESET [label="STATE_INIT,INET_STATE_UPDATE"]; + IF_IPV6_RESET -> PLUGIN_SCHED [label="PLUGIN_UPDATE"]; + IF_IPV6_RESET -> PLUGIN_RUN [label="STATE_INIT,INET_STATE_UPDATE"]; + PLUGIN_RUN -> PLUGIN_SCHED [label="PLUGIN_UPDATE"]; + PLUGIN_RUN -> PLUGIN_RUN [label="INET_STATE_UPDATE"]; + PLUGIN_RUN -> IDLE [label="STATE_INIT"]; + + EXCEPTION-> INIT [label="!PPLINE_RESTART"]; + EXCEPTION -> IDLE [label="!PPLINE_ABORT"]; +} diff --git a/src/wano/src/wanp_dhcpv4.c b/src/wano/src/wanp_dhcpv4.c new file mode 100644 index 00000000..eb97a5b1 --- /dev/null +++ b/src/wano/src/wanp_dhcpv4.c @@ -0,0 +1,255 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "log.h" +#include "module.h" +#include "ovsdb_table.h" +#include "schema.h" +#include "wano.h" +#include "osa_assert.h" + +#include "wanp_dhcpv4_stam.h" + +struct wanp_dhcpv4_handle +{ + wano_plugin_handle_t wd4_handle; + wanp_dhcpv4_state_t wd4_state; + wano_plugin_status_fn_t *wd4_status_fn; + wano_inet_state_event_t wd4_inet_state_watcher; + osn_ip_addr_t wd4_ipaddr; +}; + +static void wanp_dhcpv4_module_start(void); +static void wanp_dhcpv4_module_stop(void); +static wano_plugin_ops_init_fn_t wanp_dhcpv4_init; +static wano_plugin_ops_run_fn_t wanp_dhcpv4_run; +static wano_plugin_ops_fini_fn_t wanp_dhcpv4_fini; +static wano_inet_state_event_fn_t wanp_dhcpv4_inet_state_event_fn; + +static struct wano_plugin wanp_dhcpv4 = WANO_PLUGIN_INIT( + "dhcpv4", + 100, + WANO_PLUGIN_MASK_IPV4, + wanp_dhcpv4_init, + wanp_dhcpv4_run, + wanp_dhcpv4_fini); + +/* + * =========================================================================== + * State Machine + * =========================================================================== + */ +enum wanp_dhcpv4_state wanp_dhcpv4_state_INIT( + wanp_dhcpv4_state_t *state, + enum wanp_dhcpv4_action action, + void *data) +{ + (void)state; + (void)action; + (void)data; + + return wanp_dhcpv4_ENABLE_DHCP; +} + +enum wanp_dhcpv4_state wanp_dhcpv4_state_ENABLE_DHCP( + wanp_dhcpv4_state_t *state, + enum wanp_dhcpv4_action action, + void *data) +{ + struct wanp_dhcpv4_handle *wd4; + struct wano_inet_state *is; + + wd4 = CONTAINER_OF(state, struct wanp_dhcpv4_handle, wd4_state); + is = data; + + switch (action) + { + case wanp_dhcpv4_do_STATE_INIT: + LOG(INFO, "wanp_dhcpv4: %s: Enabling DHCP on interface.", wd4->wd4_handle.wh_ifname); + WANO_INET_CONFIG_UPDATE( + wd4->wd4_handle.wh_ifname, + .enabled = WANO_TRI_TRUE, + .network = WANO_TRI_TRUE, + .ip_assign_scheme = "dhcp"); + break; + + case wanp_dhcpv4_do_INET_STATE_UPDATE: + if (is->is_enabled != true) break; + if (is->is_network != true) break; + if (strcmp(is->is_ip_assign_scheme, "dhcp") != 0) break; + if (is->is_port_state != true) break; + + return wanp_dhcpv4_WAIT_IP; + + default: + return 0; + } + + return 0; +} + +enum wanp_dhcpv4_state wanp_dhcpv4_state_WAIT_IP( + wanp_dhcpv4_state_t *state, + enum wanp_dhcpv4_action action, + void *data) +{ + struct wanp_dhcpv4_handle *self; + + (void)action; + (void)data; + + self = CONTAINER_OF(state, struct wanp_dhcpv4_handle, wd4_state); + + if (memcmp(&self->wd4_ipaddr, &OSN_IP_ADDR_INIT, sizeof(OSN_IP_ADDR_INIT)) == 0) + { + return 0; + } + + LOG(INFO, "wanp_dhcpv4: Acquired DHCPv4 address: "PRI_osn_ip_addr, FMT_osn_ip_addr(self->wd4_ipaddr)); + + wano_inet_state_event_fini(&self->wd4_inet_state_watcher); + + return wanp_dhcpv4_RUNNING; +} + +enum wanp_dhcpv4_state wanp_dhcpv4_state_RUNNING( + wanp_dhcpv4_state_t *state, + enum wanp_dhcpv4_action action, + void *data) +{ + (void)action; + (void)data; + + struct wanp_dhcpv4_handle *wd4 = CONTAINER_OF(state, struct wanp_dhcpv4_handle, wd4_state); + + if (action == wanp_dhcpv4_do_STATE_INIT) + { + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_OK); + STRSCPY(ws.ws_ifname, wd4->wd4_handle.wh_ifname); + STRSCPY(ws.ws_iftype, "eth"); + wd4->wd4_status_fn(&wd4->wd4_handle, &ws); + } + + LOG(INFO, "DHCPV4_RUNNING: %s", wanp_dhcpv4_action_str(action)); + + return 0; +} + +enum wanp_dhcpv4_state wanp_dhcpv4_state_EXCEPTION( + wanp_dhcpv4_state_t *state, + enum wanp_dhcpv4_action action, + void *data) +{ + (void)state; + (void)action; + (void)data; + + LOG(INFO, "DHCPV4_EXCEPTION: %s", wanp_dhcpv4_action_str(action)); + + return 0; +} + +/* + * =========================================================================== + * Plugin implementation + * =========================================================================== + */ +wano_plugin_handle_t *wanp_dhcpv4_init( + const struct wano_plugin *wp, + const char *ifname, + wano_plugin_status_fn_t *status_fn) +{ + struct wanp_dhcpv4_handle *wd4; + + wd4 = calloc(1, sizeof(struct wanp_dhcpv4_handle)); + ASSERT(wd4 != NULL, "Error allocating DHCPv4 object") + + wd4->wd4_handle.wh_plugin = wp; + STRSCPY(wd4->wd4_handle.wh_ifname, ifname); + wd4->wd4_status_fn = status_fn; + + return &wd4->wd4_handle; +} + +void wanp_dhcpv4_run(wano_plugin_handle_t *wh) +{ + struct wanp_dhcpv4_handle *wdh = CONTAINER_OF(wh, struct wanp_dhcpv4_handle, wd4_handle); + + (void)wdh; + (void)wanp_dhcpv4_inet_state_event_fn; + + /* Register to Wifi_Inet_State events, this will also kick-off the state machine */ + wano_inet_state_event_init( + &wdh->wd4_inet_state_watcher, + wdh->wd4_handle.wh_ifname, + wanp_dhcpv4_inet_state_event_fn); +} + +void wanp_dhcpv4_fini(wano_plugin_handle_t *wh) +{ + struct wanp_dhcpv4_handle *wdh = CONTAINER_OF(wh, struct wanp_dhcpv4_handle, wd4_handle); + + wano_inet_state_event_fini(&wdh->wd4_inet_state_watcher); + + free(wh); +} + +/* + * =========================================================================== + * Misc + * =========================================================================== + */ +void wanp_dhcpv4_inet_state_event_fn( + wano_inet_state_event_t *ise, + struct wano_inet_state *is) +{ + struct wanp_dhcpv4_handle *wd4 = CONTAINER_OF(ise, struct wanp_dhcpv4_handle, wd4_inet_state_watcher); + + wd4->wd4_ipaddr = is->is_ipaddr; + + if (wanp_dhcpv4_state_do(&wd4->wd4_state, wanp_dhcpv4_do_INET_STATE_UPDATE, is) < 0) + { + LOG(ERR, "wanp_dhcpv4: Error sending action INET_STATE_UPDATE to state machine."); + } +} + +/* + * =========================================================================== + * Module Support + * =========================================================================== + */ +void wanp_dhcpv4_module_start(void) +{ + wano_plugin_register(&wanp_dhcpv4); +} + +void wanp_dhcpv4_module_stop(void) +{ + wano_plugin_unregister(&wanp_dhcpv4); +} + +MODULE(wanp_dhcpv4, wanp_dhcpv4_module_start, wanp_dhcpv4_module_stop) + diff --git a/src/wano/src/wanp_dhcpv4.dot b/src/wano/src/wanp_dhcpv4.dot new file mode 100644 index 00000000..d0dd64ab --- /dev/null +++ b/src/wano/src/wanp_dhcpv4.dot @@ -0,0 +1,12 @@ +digraph { + INIT[init=true]; + INIT -> ENABLE_DHCP [label="STATE_INIT"]; + ENABLE_DHCP -> WAIT_IP [label="INET_STATE_UPDATE"]; + WAIT_IP -> RUNNING; + + TIMEOUT_EX[label="Timeout occurred"]; + CANCEL_EX[label="WAN cancelled"]; + + TIMEOUT_EX -> EXCEPTION [label="!TIMEOUT"]; + CANCEL_EX -> EXCEPTION [label="!CANCEL"]; +} diff --git a/src/wano/src/wanp_dhcpv6.c b/src/wano/src/wanp_dhcpv6.c new file mode 100644 index 00000000..f7221c46 --- /dev/null +++ b/src/wano/src/wanp_dhcpv6.c @@ -0,0 +1,379 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "module.h" +#include "osa_assert.h" +#include "ovsdb_sync.h" +#include "ovsdb_table.h" + +#include "wano.h" + +#include "wanp_dhcpv6_stam.h" + +/* + * Structure representing a single DHCPv6 plug-in instance + */ +struct wanp_dhcpv6 +{ + wano_plugin_handle_t wd6_handle; + wano_plugin_status_fn_t *wd6_status_fn; + wanp_dhcpv6_state_t wd6_state; + osn_ip_addr_t wd6_ipaddr; + bool wd6_has_global_ip; + bool wd6_ovsdb_subscribed; + ds_tree_node_t wd6_tnode; +}; + +static void wanp_dhcpv6_module_start(void); +static void wanp_dhcpv6_module_stop(void); +static wano_plugin_ops_init_fn_t wanp_dhcpv6_init; +static wano_plugin_ops_run_fn_t wanp_dhcpv6_run; +static wano_plugin_ops_fini_fn_t wanp_dhcpv6_fini; +static void wanp_dhcpv6_ovsdb_reset(struct wanp_dhcpv6 *self); + +void callback_IP_Interface( + ovsdb_update_monitor_t *self, + struct schema_IP_Interface *old, + struct schema_IP_Interface *new); + +static ovsdb_table_t table_IP_Interface; +static ovsdb_table_t table_DHCPv6_Client; +static ovsdb_table_t table_IPv6_Address; + +/* List of handles subscribed to OVSDB events */ +static ds_tree_t wanp_dhcpv6_ovsdb_list = DS_TREE_INIT(ds_str_cmp, struct wanp_dhcpv6, wd6_tnode); + +static struct wano_plugin wanp_dhcpv6 = WANO_PLUGIN_INIT( + "dhcpv6", + 100, + WANO_PLUGIN_MASK_IPV6, + wanp_dhcpv6_init, + wanp_dhcpv6_run, + wanp_dhcpv6_fini); + + +/* + * =========================================================================== + * Plugin implementation + * =========================================================================== + */ +wano_plugin_handle_t *wanp_dhcpv6_init( + const struct wano_plugin *wp, + const char *ifname, + wano_plugin_status_fn_t *status_fn) +{ + struct wanp_dhcpv6 *self; + + self = calloc(1, sizeof(struct wanp_dhcpv6)); + ASSERT(self != NULL, "Error allocating DHCPv6 object"); + + self->wd6_handle.wh_plugin = wp; + STRSCPY(self->wd6_handle.wh_ifname, ifname); + self->wd6_status_fn = status_fn; + + return &self->wd6_handle; +} + +void wanp_dhcpv6_run(wano_plugin_handle_t *wh) +{ + struct wanp_dhcpv6 *self = CONTAINER_OF(wh, struct wanp_dhcpv6, wd6_handle); + + wanp_dhcpv6_state_do(&self->wd6_state, wanp_dhcpv6_do_INIT, NULL); +} + +void wanp_dhcpv6_fini(wano_plugin_handle_t *wh) +{ + struct wanp_dhcpv6 *self = CONTAINER_OF(wh, struct wanp_dhcpv6, wd6_handle); + + if (self->wd6_ovsdb_subscribed) + { + ds_tree_remove(&wanp_dhcpv6_ovsdb_list, self); + self->wd6_ovsdb_subscribed = false; + } + + wanp_dhcpv6_ovsdb_reset(self); + + free(self); +} + +/* + * =========================================================================== + * OVSDB Interface + * =========================================================================== + */ + +void callback_IP_Interface( + ovsdb_update_monitor_t *mon, + struct schema_IP_Interface *old, + struct schema_IP_Interface *new) +{ + struct schema_IPv6_Address ipv6_address; + struct wanp_dhcpv6 *self; + int ii; + + const char *ifname = (mon->mon_type == OVSDB_UPDATE_DEL) ? old->if_name : new->if_name; + + self = ds_tree_find(&wanp_dhcpv6_ovsdb_list, (void *)ifname); + if (self == NULL) + { + return; + } + + self->wd6_has_global_ip = false; + if (mon->mon_type != OVSDB_UPDATE_DEL) + { + /* + * Scan the IP_Interface:ipv6_addr uuid set and check if there are any + * global IPv6 Addresses. If there are, assume RA/DHCPv6 succeeded in + * provisioning the WAN IPv6 link. + */ + for (ii = 0; ii < new->ipv6_addr_len; ii++) + { + if (!ovsdb_table_select_one_where( + &table_IPv6_Address, + ovsdb_where_uuid("_uuid", new->ipv6_addr[ii].uuid), + &ipv6_address)) + { + LOG(WARN, "wanp_dhcpv6: %s: Unable to find IPv6_Address row with uuid: %s", + self->wd6_handle.wh_ifname, new->ipv6_addr[ii].uuid); + continue; + } + + if (strcmp(ipv6_address.origin, "auto_configured") != 0) + { + self->wd6_has_global_ip = true; + } + } + } + + if (self->wd6_ovsdb_subscribed) + { + wanp_dhcpv6_state_do(&self->wd6_state, wanp_dhcpv6_do_OVSDB_UPDATE, NULL); + } +} + +bool wanp_dhcpv6_ovsdb_enable(struct wanp_dhcpv6 *self) +{ + struct schema_IP_Interface ip_interface; + struct schema_DHCPv6_Client dhcpv6_client; + + memset(&ip_interface, 0, sizeof(ip_interface)); + ip_interface._partial_update = true; + SCHEMA_SET_STR(ip_interface.name, self->wd6_handle.wh_ifname); + SCHEMA_SET_STR(ip_interface.if_name, self->wd6_handle.wh_ifname); + SCHEMA_SET_STR(ip_interface.status, "up"); + SCHEMA_SET_INT(ip_interface.enable, true); + + if (!ovsdb_table_upsert_simple( + &table_IP_Interface, + "name", + self->wd6_handle.wh_ifname, + &ip_interface, + true)) + { + LOG(ERR, "wanp_dhcpv6: %s: Error upserting IP_Interface.", + self->wd6_handle.wh_ifname); + return false; + } + + memset(&dhcpv6_client, 0, sizeof(dhcpv6_client)); + dhcpv6_client._partial_update = true; + SCHEMA_SET_INT(dhcpv6_client.enable, true); + SCHEMA_SET_INT(dhcpv6_client.request_address, true); + SCHEMA_SET_INT(dhcpv6_client.request_prefixes, true); + SCHEMA_SET_UUID(dhcpv6_client.ip_interface, ip_interface._uuid.uuid); + + if (!ovsdb_table_upsert_where( + &table_DHCPv6_Client, + ovsdb_where_uuid("ip_interface", ip_interface._uuid.uuid), + &dhcpv6_client, + false)) + { + LOG(ERR, "wanp_dhcpv6: %s: Error upserting DHCPv6_Client.", + self->wd6_handle.wh_ifname); + return false; + } + + return true; +} + +void wanp_dhcpv6_ovsdb_reset(struct wanp_dhcpv6 *self) +{ + struct schema_IP_Interface ip_interface; + + if (!ovsdb_table_select_one(&table_IP_Interface, "if_name", self->wd6_handle.wh_ifname, &ip_interface)) + { + /* No entry in IP_Interface -- we're good */ + LOG(DEBUG, "wanp_dhcpv6: %s: IP_Interface no entry for if_name.", self->wd6_handle.wh_ifname); + return; + } + + if (ovsdb_table_delete_where(&table_DHCPv6_Client, ovsdb_where_uuid("ip_interface", ip_interface._uuid.uuid)) < 0) + { + LOG(WARN, "wanp_dhcpv6: %s: Error deleting DHCPv6_Client row.", + self->wd6_handle.wh_ifname); + } + + if (ovsdb_table_delete_where(&table_IP_Interface, ovsdb_where_uuid("_uuid", ip_interface._uuid.uuid)) < 0) + { + LOG(WARN, "wanp_dhcpv6: %s: Error deleting IP_Interface row.", + self->wd6_handle.wh_ifname); + } +} + +/* + * =========================================================================== + * State Machine + * =========================================================================== + */ +enum wanp_dhcpv6_state wanp_dhcpv6_state_INIT( + wanp_dhcpv6_state_t *state, + enum wanp_dhcpv6_action action, + void *data) +{ + (void)state; + (void)data; + + switch (action) + { + case wanp_dhcpv6_do_INIT: + return wanp_dhcpv6_ENABLE; + + default: + break; + } + + return 0; +} + +enum wanp_dhcpv6_state wanp_dhcpv6_state_ENABLE( + wanp_dhcpv6_state_t *state, + enum wanp_dhcpv6_action action, + void *data) +{ + (void)state; + (void)action; + (void)data; + + struct wanp_dhcpv6 *self = CONTAINER_OF(state, struct wanp_dhcpv6, wd6_state); + + switch (action) + { + case wanp_dhcpv6_do_STATE_INIT: + LOG(INFO, "wanp_dhcpv6: %s: Enabling DHCPv6/RA on interface.", + self->wd6_handle.wh_ifname); + + wanp_dhcpv6_ovsdb_reset(self); + wanp_dhcpv6_ovsdb_enable(self); + + /* Subscribe to OVSDB events */ + self->wd6_ovsdb_subscribed = true; + ds_tree_insert(&wanp_dhcpv6_ovsdb_list, self, self->wd6_handle.wh_ifname); + /* Fallthrough */ + + case wanp_dhcpv6_do_OVSDB_UPDATE: + if (!self->wd6_has_global_ip) + { + return 0; + } + return wanp_dhcpv6_IDLE; + + default: + break; + } + + return 0; +} + +enum wanp_dhcpv6_state wanp_dhcpv6_state_IDLE( + wanp_dhcpv6_state_t *state, + enum wanp_dhcpv6_action action, + void *data) +{ + (void)data; + + struct wanp_dhcpv6 *self = CONTAINER_OF(state, struct wanp_dhcpv6, wd6_state); + + switch (action) + { + case wanp_dhcpv6_do_STATE_INIT: + LOG(INFO, "wano_dhcpv6: %s: Acquired global IP.", + self->wd6_handle.wh_ifname); + + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_OK); + STRSCPY(ws.ws_ifname, self->wd6_handle.wh_ifname); + STRSCPY(ws.ws_iftype, "eth"); + self->wd6_status_fn(&self->wd6_handle, &ws); + break; + + case wanp_dhcpv6_do_OVSDB_UPDATE: + if (!self->wd6_has_global_ip) + { + LOG(INFO, "wano_dhcpv6: %s: Lost global IP, aborting.", + self->wd6_handle.wh_ifname); + + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_ERROR); + STRSCPY(ws.ws_ifname, self->wd6_handle.wh_ifname); + STRSCPY(ws.ws_iftype, "eth"); + self->wd6_status_fn(&self->wd6_handle, &ws); + } + break; + + default: + break; + } + + return 0; +} + +/* + * =========================================================================== + * Module Support + * =========================================================================== + */ +void wanp_dhcpv6_module_start(void) +{ + + /* Subscribe to IP_Interface changes */ + OVSDB_TABLE_INIT(IP_Interface, name); + OVSDB_TABLE_INIT(DHCPv6_Client, _uuid); + OVSDB_TABLE_INIT(IPv6_Address, _uuid); + + if (!OVSDB_TABLE_MONITOR(IP_Interface, true)) + { + LOG(ERR, "dhcpv6: Error monitoring IP_Interface. Plug-in won't be available."); + return; + } + + wano_plugin_register(&wanp_dhcpv6); +} + +void wanp_dhcpv6_module_stop(void) +{ + wano_plugin_unregister(&wanp_dhcpv6); +} + +MODULE(wanp_dhcpv6, wanp_dhcpv6_module_start, wanp_dhcpv6_module_stop) diff --git a/src/wano/src/wanp_dhcpv6.dot b/src/wano/src/wanp_dhcpv6.dot new file mode 100644 index 00000000..bed13675 --- /dev/null +++ b/src/wano/src/wanp_dhcpv6.dot @@ -0,0 +1,5 @@ +digraph { + INIT[init=true]; + INIT -> ENABLE [label="INIT"]; + ENABLE -> IDLE [label="OVSDB_UPDATE"]; +} diff --git a/src/wano/src/wanp_pppoe.c b/src/wano/src/wanp_pppoe.c new file mode 100644 index 00000000..0f6ca64b --- /dev/null +++ b/src/wano/src/wanp_pppoe.c @@ -0,0 +1,374 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "log.h" +#include "module.h" +#include "ovsdb_table.h" +#include "schema.h" +#include "wano.h" +#include "osp_ps.h" +#include "osa_assert.h" +#include "json_util.h" + +#include "wano_localconfig.h" + +#include "wanp_pppoe_stam.h" + +struct wanp_pppoe_handle +{ + wano_plugin_handle_t wpoe_handle; + wanp_pppoe_state_t wpoe_state; + wano_plugin_status_fn_t *wpoe_status_fn; + wano_inet_state_event_t wpoe_inet_state_watcher; + osn_ip_addr_t wpoe_ipaddr; + char wpoe_ppp_ifname[C_IFNAME_LEN]; + struct wano_localconfig_pppoe wpoe_cred; + struct wano_plugin_status wpoe_status; +}; + +static void wanp_pppoe_module_start(void); +static void wanp_pppoe_module_stop(void); +static wano_plugin_ops_init_fn_t wanp_pppoe_init; +static wano_plugin_ops_run_fn_t wanp_pppoe_run; +static wano_plugin_ops_fini_fn_t wanp_pppoe_fini; +static wano_inet_state_event_fn_t wanp_pppoe_inet_state_event_fn; +static bool wanp_pppoe_get_credentials(struct wano_localconfig_pppoe *cred); + +static struct wano_plugin wanp_pppoe = WANO_PLUGIN_INIT( + "pppoe", + 50, + WANO_PLUGIN_MASK_ALL, + wanp_pppoe_init, + wanp_pppoe_run, + wanp_pppoe_fini); + +/* + * =========================================================================== + * State Machine + * =========================================================================== + */ +enum wanp_pppoe_state wanp_pppoe_state_INIT( + wanp_pppoe_state_t *state, + enum wanp_pppoe_action action, + void *data) +{ + (void)action; + (void)data; + + struct wanp_pppoe_handle *wpoe; + + wpoe = CONTAINER_OF(state, struct wanp_pppoe_handle, wpoe_state); + + switch (action) + { + case wanp_pppoe_do_STATE_INIT: + break; + + case wanp_pppoe_do_INIT: + LOG(DEBUG, "wanp_pppoe: Reading credentials from persistent storage"); + if (wanp_pppoe_get_credentials(&wpoe->wpoe_cred) == false) + { + LOG(NOTICE, "wanp_pppoe: No PPPoE configuration is present. Skipping plug-in."); + wpoe->wpoe_status_fn( + &wpoe->wpoe_handle, + &WANO_PLUGIN_STATUS(WANP_SKIP)); + break; + } + return wanp_pppoe_ENABLE_PPPOE; + + default: + break; + } + + return 0; +} + +enum wanp_pppoe_state wanp_pppoe_state_ENABLE_PPPOE( + wanp_pppoe_state_t *state, + enum wanp_pppoe_action action, + void *data) +{ + struct wanp_pppoe_handle *wpoe; + struct wano_inet_state *is; + + struct schema_Wifi_Inet_Config inet_config; + ovsdb_table_t table_Wifi_Inet_Config; + + wpoe = CONTAINER_OF(state, struct wanp_pppoe_handle, wpoe_state); + is = data; + + switch (action) + { + case wanp_pppoe_do_STATE_INIT: + LOG(INFO, "wanp_pppoe: Enabling PPPOE interface %s with parent if: %s.", + wpoe->wpoe_ppp_ifname, + wpoe->wpoe_handle.wh_ifname); + + // Insert new pppoe interface in Wifi_Inet_Config table + OVSDB_TABLE_INIT(Wifi_Inet_Config, if_name); + memset(&inet_config, 0, sizeof(inet_config)); + inet_config._partial_update = true; + + SCHEMA_SET_INT(inet_config.enabled, false); + SCHEMA_SET_INT(inet_config.network, false); + SCHEMA_SET_STR(inet_config.parent_ifname, wpoe->wpoe_handle.wh_ifname); + SCHEMA_SET_STR(inet_config.if_type, "pppoe"); + SCHEMA_KEY_VAL_APPEND(inet_config.ppp_options, "username", wpoe->wpoe_cred.username); + SCHEMA_KEY_VAL_APPEND(inet_config.ppp_options, "password", wpoe->wpoe_cred.password); + SCHEMA_SET_STR(inet_config.if_name, wpoe->wpoe_ppp_ifname); + + ovsdb_table_upsert_simple( + &table_Wifi_Inet_Config, + "if_name", + wpoe->wpoe_ppp_ifname, + &inet_config, + false); + + /* Start monitoring Wifi_Inet_State events */ + wano_inet_state_event_init( + &wpoe->wpoe_inet_state_watcher, + wpoe->wpoe_ppp_ifname, + wanp_pppoe_inet_state_event_fn); + break; + + case wanp_pppoe_do_INET_STATE_UPDATE: + if (is->is_enabled) break; + if (is->is_network) break; + return wanp_pppoe_WAIT_IP; + + default: + return 0; + } + + return 0; +} + +enum wanp_pppoe_state wanp_pppoe_state_WAIT_IP( + wanp_pppoe_state_t *state, + enum wanp_pppoe_action action, + void *data) +{ + struct wanp_pppoe_handle *wpoe; + struct wano_inet_state *is = data; + + wpoe = CONTAINER_OF(state, struct wanp_pppoe_handle, wpoe_state); + + switch (action) + { + case wanp_pppoe_do_STATE_INIT: + LOG(INFO, "wanp_pppoe: %s: Waiting for PPPOE address.", wpoe->wpoe_ppp_ifname); + if (!WANO_INET_CONFIG_UPDATE( + wpoe->wpoe_ppp_ifname, + .enabled = WANO_TRI_TRUE, + .network = WANO_TRI_TRUE)) + { + LOG(WARN, "wanp_pppoe: %s: Error re-eanbling PPPoE interface %s.", + wpoe->wpoe_handle.wh_ifname, + wpoe->wpoe_ppp_ifname); + return 0; + } + + break; + + case wanp_pppoe_do_INET_STATE_UPDATE: + if (!is->is_enabled) break; + if (!is->is_network) break; + if (memcmp(&is->is_ipaddr, &OSN_IP_ADDR_INIT, sizeof(OSN_IP_ADDR_INIT)) == 0) break; + + LOG(INFO, "wanp_pppoe: Acquired PPPOE address: "PRI_osn_ip_addr, FMT_osn_ip_addr(wpoe->wpoe_ipaddr)); + // Stop listening to inet state events + wano_inet_state_event_fini(&wpoe->wpoe_inet_state_watcher); + return wanp_pppoe_RUNNING; + + default: + break; + } + + return 0; +} + +enum wanp_pppoe_state wanp_pppoe_state_RUNNING( + wanp_pppoe_state_t *state, + enum wanp_pppoe_action action, + void *data) +{ + (void)action; + (void)data; + + struct wanp_pppoe_handle *wpoe = CONTAINER_OF(state, struct wanp_pppoe_handle, wpoe_state); + + if (action == wanp_pppoe_do_STATE_INIT) + { + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_OK); + + STRSCPY(ws.ws_ifname, wpoe->wpoe_ppp_ifname); + STRSCPY(ws.ws_iftype, "pppoe"); + + wpoe->wpoe_status_fn( &wpoe->wpoe_handle, &ws); + } + + LOG(INFO, "wanp_pppoe: PPPOE_RUNNING: %s", wanp_pppoe_action_str(action)); + + return 0; +} + +enum wanp_pppoe_state wanp_pppoe_state_DONE( + wanp_pppoe_state_t *state, + enum wanp_pppoe_action action, + void *data) +{ + (void)action; + (void)data; + struct wanp_pppoe_handle *wpoe; + + LOG(INFO, "wanp_pppoe: PPPOE_DONE: %s", wanp_pppoe_action_str(action)); + + wpoe = CONTAINER_OF(state, struct wanp_pppoe_handle, wpoe_state); + + if (action == wanp_pppoe_do_STATE_INIT) + { + wpoe->wpoe_status_fn(&wpoe->wpoe_handle, &WANO_PLUGIN_STATUS(WANP_OK)); + } + + return 0; +} + +enum wanp_pppoe_state wanp_pppoe_state_EXCEPTION( + wanp_pppoe_state_t *state, + enum wanp_pppoe_action action, + void *data) +{ + (void)state; + (void)action; + (void)data; + + LOG(INFO, "wanp_pppoe: PPPOE_EXCEPTION: %s", wanp_pppoe_action_str(action)); + + return 0; +} + +/* + * =========================================================================== + * Plugin implementation + * =========================================================================== + */ +wano_plugin_handle_t *wanp_pppoe_init( + const struct wano_plugin *wp, + const char *ifname, + wano_plugin_status_fn_t *status_fn) +{ + struct wanp_pppoe_handle *wpoe; + + wpoe = calloc(1, sizeof(struct wanp_pppoe_handle)); + ASSERT(wpoe != NULL, "Error allocating PPPOE object") + + wpoe->wpoe_handle.wh_plugin = wp; + STRSCPY(wpoe->wpoe_handle.wh_ifname, ifname); + // Concat name of new interface from "ppp-" and parent interface name + STRSCPY_WARN(wpoe->wpoe_ppp_ifname, "ppp-"); + STRSCAT(wpoe->wpoe_ppp_ifname, wpoe->wpoe_handle.wh_ifname); + wpoe->wpoe_status_fn = status_fn; + + return &wpoe->wpoe_handle; +} + +void wanp_pppoe_run(wano_plugin_handle_t *wh) +{ + struct wanp_pppoe_handle *wph = CONTAINER_OF(wh, struct wanp_pppoe_handle, wpoe_handle); + + if (wanp_pppoe_state_do(&wph->wpoe_state, wanp_pppoe_do_INIT, NULL) < 0) + { + LOG(ERR, "wanp_pppoe: %s: Error initializing state machine.", wph->wpoe_ppp_ifname); + } + +} + +void wanp_pppoe_fini(wano_plugin_handle_t *wh) +{ + struct wanp_pppoe_handle *wph = CONTAINER_OF(wh, struct wanp_pppoe_handle, wpoe_handle); + + wano_inet_state_event_fini(&wph->wpoe_inet_state_watcher); + + free(wph); +} + +/* + * =========================================================================== + * Misc + * =========================================================================== + */ +void wanp_pppoe_inet_state_event_fn( + wano_inet_state_event_t *ise, + struct wano_inet_state *is) +{ + struct wanp_pppoe_handle *wpoe = CONTAINER_OF(ise, struct wanp_pppoe_handle, wpoe_inet_state_watcher); + + wpoe->wpoe_ipaddr = is->is_ipaddr; + + if (wanp_pppoe_state_do(&wpoe->wpoe_state, wanp_pppoe_do_INET_STATE_UPDATE, is) < 0) + { + LOG(ERR, "wanp_pppoe: Error sending action INET_STATE_UPDATE to state machine."); + } +} + +bool wanp_pppoe_get_credentials(struct wano_localconfig_pppoe *cred) +{ + struct wano_localconfig lc; + + if (!wano_localconfig_load(&lc)) + { + LOG(DEBUG, "wanp_pppoe: No local configuration present."); + return false; + } + + if (!lc.PPPoE_exists) + { + LOG(DEBUG, "wanp_pppoe: No PPPoE configuration present in local config."); + return false; + } + + *cred = lc.PPPoE; + + return true; +} + +/* + * =========================================================================== + * Module Support + * =========================================================================== + */ +void wanp_pppoe_module_start(void) +{ + wano_plugin_register(&wanp_pppoe); +} + +void wanp_pppoe_module_stop(void) +{ + wano_plugin_unregister(&wanp_pppoe); +} + +MODULE(wanp_pppoe, wanp_pppoe_module_start, wanp_pppoe_module_stop) + diff --git a/src/wano/src/wanp_pppoe.dot b/src/wano/src/wanp_pppoe.dot new file mode 100644 index 00000000..452e98a8 --- /dev/null +++ b/src/wano/src/wanp_pppoe.dot @@ -0,0 +1,13 @@ +digraph { + INIT[init=true]; + INIT -> ENABLE_PPPOE [label="INIT"]; + ENABLE_PPPOE -> WAIT_IP [label="INET_STATE_UPDATE"]; + ENABLE_PPPOE -> DONE; + WAIT_IP -> RUNNING; + + TIMEOUT_EX[label="Timeout occurred"]; + CANCEL_EX[label="WAN cancelled"]; + + TIMEOUT_EX -> EXCEPTION [label="!TIMEOUT"]; + CANCEL_EX -> EXCEPTION [label="!CANCEL"]; +} diff --git a/src/wano/src/wanp_static_ipv4.c b/src/wano/src/wanp_static_ipv4.c new file mode 100644 index 00000000..376757d5 --- /dev/null +++ b/src/wano/src/wanp_static_ipv4.c @@ -0,0 +1,480 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "module.h" +#include "ovsdb_table.h" +#include "schema.h" +#include "wano.h" +#include "osa_assert.h" +#include "osp_ps.h" + +#include "wano_localconfig.h" +#include "wanp_static_ipv4_stam.h" + +typedef struct +{ + wano_plugin_handle_t handle; + wanp_static_ipv4_state_t state; + wano_plugin_status_fn_t *status_fn; + wano_inet_state_event_t inet_state_watcher; + osn_ip_addr_t ipaddr; + + /* ping state */ + pid_t ping_pid; + ev_child ping_pid_watcher; + int ping_fd[2]; + ev_io ping_fd_watcher; + char ping_buf[20148]; + size_t ping_buf_offset; + + /* Local config */ + struct wano_localconfig localconfig; + + osn_ip_addr_t ip_addr; + osn_ip_addr_t netmask; + osn_ip_addr_t gateway; + osn_ip_addr_t dns1; + osn_ip_addr_t dns2; +} wanp_static_ipv4_handle_t; + +static void wanp_static_ipv4_module_start(void); +static void wanp_static_ipv4_module_stop(void); +static wano_plugin_ops_init_fn_t wanp_static_ipv4_init; +static wano_plugin_ops_run_fn_t wanp_static_ipv4_run; +static wano_plugin_ops_fini_fn_t wanp_static_ipv4_fini; +static wano_inet_state_event_fn_t wanp_static_ipv4_inet_state_event_fn; + +static struct wano_plugin wanp_static_ipv4 = WANO_PLUGIN_INIT( + "static_ipv4", + 90, + WANO_PLUGIN_MASK_IPV4, + wanp_static_ipv4_init, + wanp_static_ipv4_run, + wanp_static_ipv4_fini); + + +static void ping_fd_watcher_cb(struct ev_loop *loop, ev_io *w, int revents) +{ + (void)loop; + (void)revents; + + wanp_static_ipv4_handle_t *h = CONTAINER_OF(w, wanp_static_ipv4_handle_t, ping_fd_watcher); + const size_t remaining_len = sizeof(h->ping_buf) - h->ping_buf_offset - 1; /* Space for final \0 */ + size_t read_len; + + read_len = read(h->ping_fd[0], h->ping_buf + h->ping_buf_offset, remaining_len); + h->ping_buf_offset += read_len > 0 ? read_len : 0; +} + +static void ping_pid_watcher_cb(struct ev_loop *loop, ev_child *w, int revents) +{ + (void)loop; + (void)revents; + + wanp_static_ipv4_handle_t *h = CONTAINER_OF(w, wanp_static_ipv4_handle_t, ping_pid_watcher); + enum wanp_static_ipv4_action action; + + LOGD("wanp_static_ipv4: %s: ping output\n%s", h->handle.wh_ifname, h->ping_buf); + + ev_child_stop(EV_DEFAULT_ &h->ping_pid_watcher); + h->ping_pid = 0; + + ev_io_stop(EV_DEFAULT_ &h->ping_fd_watcher); + close(h->ping_fd[0]); + h->ping_fd[0] = -1; + memset(h->ping_buf, '\0', sizeof(h->ping_buf)); + h->ping_buf_offset = 0; + + if (WIFEXITED(w->rstatus) && WEXITSTATUS(w->rstatus) == 0) + { + LOGI("wanp_static_ipv4: %s: ping succedded", h->handle.wh_ifname); + action = wanp_static_ipv4_do_PING_SUCCEEDED; + } + else + { + LOGW("wanp_static_ipv4: %s: ping faild to reach the host", h->handle.wh_ifname); + action = wanp_static_ipv4_do_PING_FAILED; + } + + if (wanp_static_ipv4_state_do(&h->state, action, NULL) < 0) + { + LOG(ERR, "wanp_static_ipv4: Error sending action %s to state machine.", + wanp_static_ipv4_action_str(action)); + } +} + +static bool ping_async(wanp_static_ipv4_handle_t* h, const char* ip_addr) +{ + const char* if_name = h->handle.wh_ifname; + pid_t pid; + + if (pipe(h->ping_fd) != 0) + { + LOGW("wanp_static_ipv4: %s: Failed to open pipe for ping", if_name); + return false; + } + + pid = fork(); + + switch (pid) + { + case 0: + close(STDOUT_FILENO); + close(h->ping_fd[0]); + dup2(h->ping_fd[1], STDOUT_FILENO); + execlp("ping", "ping", ip_addr, "-c", "5", "-I", if_name, NULL); + LOGW("wanp_static_ipv4: %s: Failed to run ping in forked process", if_name); + exit(1); + case -1: + LOGW("wanp_static_ipv4: %s: Cannot run ping, fork failed", if_name); + return false; + default: + h->ping_pid = pid; + ev_child_init(&h->ping_pid_watcher, ping_pid_watcher_cb, pid, 0); + ev_child_start(EV_DEFAULT_ &h->ping_pid_watcher); + + close(h->ping_fd[1]); + h->ping_fd[1] = -1; + ev_io_init(&h->ping_fd_watcher, ping_fd_watcher_cb, h->ping_fd[0], EV_READ); + ev_io_start(EV_DEFAULT_ &h->ping_fd_watcher); + return true; + } +} + +/* + * =========================================================================== + * State Machine + * =========================================================================== + */ +enum wanp_static_ipv4_state wanp_static_ipv4_state_INIT( + wanp_static_ipv4_state_t *state, + enum wanp_static_ipv4_action action, + void *data) +{ + (void)state; + (void)action; + (void)data; + + return wanp_static_ipv4_CONFIGURE_IP; +} + +enum wanp_static_ipv4_state wanp_static_ipv4_state_CONFIGURE_IP( + wanp_static_ipv4_state_t *state, + enum wanp_static_ipv4_action action, + void *data) +{ + wanp_static_ipv4_handle_t *h = CONTAINER_OF(state, wanp_static_ipv4_handle_t, state); + struct wano_inet_state *is = data; + + const char *dns2 = NULL; + + switch (action) + { + case wanp_static_ipv4_do_STATE_INIT: + LOG(INFO, "wanp_static_ipv4: %s: Setting ip_addr=%s netmask=%s gateway=%s", + h->handle.wh_ifname, + h->localconfig.staticIPv4.ip, + h->localconfig.staticIPv4.subnet, + h->localconfig.staticIPv4.gateway); + + if (h->localconfig.staticIPv4.secondaryDns[0] != '\0') + { + dns2 = h->localconfig.staticIPv4.secondaryDns; + } + + WANO_INET_CONFIG_UPDATE( + h->handle.wh_ifname, + .enabled = WANO_TRI_TRUE, + .network = WANO_TRI_TRUE, + .ip_assign_scheme = "static", + .inet_addr = h->localconfig.staticIPv4.ip, + .netmask = h->localconfig.staticIPv4.subnet, + .gateway = h->localconfig.staticIPv4.gateway, + .dns1 = h->localconfig.staticIPv4.primaryDns, + .dns2 = dns2); + + wano_inet_state_event_refresh(&h->inet_state_watcher); + break; + + case wanp_static_ipv4_do_INET_STATE_UPDATE: + LOG(DEBUG, "static_ipv4:%s: enabled:%d network:%d scheme:%s " + "ipaddr:"PRI_osn_ip_addr" " + "netmask:"PRI_osn_ip_addr" " + "gateway:"PRI_osn_ip_addr" " + "dns1:"PRI_osn_ip_addr" " + "dns2:"PRI_osn_ip_addr, + h->handle.wh_ifname, + is->is_enabled, + is->is_network, + is->is_ip_assign_scheme, + FMT_osn_ip_addr(is->is_ipaddr), + FMT_osn_ip_addr(is->is_netmask), + FMT_osn_ip_addr(is->is_gateway), + FMT_osn_ip_addr(is->is_dns1), + FMT_osn_ip_addr(is->is_dns2)); + if (is->is_enabled != true) break; + if (is->is_network != true) break; + if (strcmp(is->is_ip_assign_scheme, "static") != 0) break; + if (memcmp(&is->is_ipaddr, &h->ip_addr, sizeof(h->ip_addr)) != 0) break; + if (memcmp(&is->is_netmask, &h->netmask, sizeof(h->netmask)) != 0) break; + if (memcmp(&is->is_gateway, &h->gateway, sizeof(h->gateway)) != 0) break; + if (memcmp(&is->is_dns1, &h->dns1, sizeof(h->dns1)) != 0) break; + if (memcmp(&is->is_dns2, &h->dns2, sizeof(h->dns2)) != 0) break; + + wano_inet_state_event_fini(&h->inet_state_watcher); + return wanp_static_ipv4_PROBE; + + default: + break; + } + + return 0; +} + +enum wanp_static_ipv4_state wanp_static_ipv4_state_PROBE( + wanp_static_ipv4_state_t *state, + enum wanp_static_ipv4_action action, + void *data) +{ + wanp_static_ipv4_handle_t *h; + + (void)data; + + h = CONTAINER_OF(state, wanp_static_ipv4_handle_t, state); + + switch (action) + { + case wanp_static_ipv4_do_STATE_INIT: + case wanp_static_ipv4_do_PING_FAILED: + { + LOG(INFO, "wanp_static_ipv4: %s: Pinging %s", h->handle.wh_ifname, h->localconfig.staticIPv4.gateway); + if (ping_async(h, h->localconfig.staticIPv4.gateway) == false) + { + /* Ping failed, inform upper layers */ + h->status_fn(&h->handle, &WANO_PLUGIN_STATUS(WANP_ERROR)); + } + return 0; + } + + case wanp_static_ipv4_do_PING_SUCCEEDED: + return wanp_static_ipv4_RUNNING; + + default: + return 0; + } + + return wanp_static_ipv4_RUNNING; +} + +enum wanp_static_ipv4_state wanp_static_ipv4_state_RUNNING( + wanp_static_ipv4_state_t *state, + enum wanp_static_ipv4_action action, + void *data) +{ + (void)action; + (void)data; + + wanp_static_ipv4_handle_t *h = CONTAINER_OF(state, wanp_static_ipv4_handle_t, state); + + if (action == wanp_static_ipv4_do_STATE_INIT) + { + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_OK); + + STRSCPY(ws.ws_ifname, h->handle.wh_ifname); + STRSCPY(ws.ws_iftype, "eth"); + + h->status_fn(&h->handle, &ws); + } + + return 0; +} + +enum wanp_static_ipv4_state wanp_static_ipv4_state_EXCEPTION( + wanp_static_ipv4_state_t *state, + enum wanp_static_ipv4_action action, + void *data) +{ + (void)state; + (void)action; + (void)data; + + LOG(INFO, "static_ipv4_EXCEPTION: %s", wanp_static_ipv4_action_str(action)); + + return 0; +} + +/* + * =========================================================================== + * Plugin implementation + * =========================================================================== + */ +wano_plugin_handle_t *wanp_static_ipv4_init( + const struct wano_plugin *wp, + const char *ifname, + wano_plugin_status_fn_t *status_fn) +{ + wanp_static_ipv4_handle_t *h; + + h = calloc(1, sizeof(wanp_static_ipv4_handle_t)); + ASSERT(h != NULL, "Error allocating static_ipv4 object") + + h->handle.wh_plugin = wp; + STRSCPY(h->handle.wh_ifname, ifname); + h->status_fn = status_fn; + + h->ping_fd[0] = -1; + h->ping_fd[1] = -1; + + h->ip_addr = OSN_IP_ADDR_INIT; + h->netmask = OSN_IP_ADDR_INIT; + h->gateway = OSN_IP_ADDR_INIT; + h->dns1 = OSN_IP_ADDR_INIT; + h->dns2 = OSN_IP_ADDR_INIT; + + /* + * Load static configration + */ + if (!wano_localconfig_load(&h->localconfig) || !h->localconfig.staticIPv4_exists) + { + LOG(NOTICE, "static_ipv4: No static IPv4 configuration present, skipping."); + goto error; + } + + /* + * Verify that the IPs are valid + */ + if (!osn_ip_addr_from_str(&h->gateway, h->localconfig.staticIPv4.gateway)) + { + LOG(ERR, "static_ipv4: Invalid gateway configuration: %s", h->localconfig.staticIPv4.gateway); + goto error; + } + + if (!osn_ip_addr_from_str(&h->ip_addr, h->localconfig.staticIPv4.ip)) + { + LOG(ERR, "static_ipv4: Invalid IP address configuration: %s", h->localconfig.staticIPv4.ip); + goto error; + } + + if (!osn_ip_addr_from_str(&h->netmask, h->localconfig.staticIPv4.subnet)) + { + LOG(ERR, "static_ipv4: Invalid IP subnet configuration: %s", h->localconfig.staticIPv4.subnet); + goto error; + } + + if (!osn_ip_addr_from_str(&h->dns1, h->localconfig.staticIPv4.primaryDns)) + { + LOG(ERR, "static_ipv4: Invalid DNS configuration: %s", h->localconfig.staticIPv4.primaryDns); + goto error; + } + + /* secondaryDNS is optional, do not abort if it cannot be parsed */ + if (h->localconfig.staticIPv4.secondaryDns[0] != '\0' && + !osn_ip_addr_from_str(&h->dns2, h->localconfig.staticIPv4.secondaryDns)) + { + LOG(WARN, "static_ipv4: Invalid secondary DNS configuration: %s", h->localconfig.staticIPv4.secondaryDns); + } + + return &h->handle; + +error: + if (h != NULL) free(h); + return NULL; +} + +void wanp_static_ipv4_run(wano_plugin_handle_t *wh) +{ + wanp_static_ipv4_handle_t *wsh = CONTAINER_OF(wh, wanp_static_ipv4_handle_t, handle); + + /* Register to Wifi_Inet_State events, this will also kick-off the state machine */ + wano_inet_state_event_init( + &wsh->inet_state_watcher, + wsh->handle.wh_ifname, + wanp_static_ipv4_inet_state_event_fn); +} + +void wanp_static_ipv4_fini(wano_plugin_handle_t *wh) +{ + wanp_static_ipv4_handle_t *wsh = CONTAINER_OF(wh, wanp_static_ipv4_handle_t, handle); + + if (wsh->ping_pid > 0) + { + ev_child_stop(EV_DEFAULT_ &wsh->ping_pid_watcher); + kill(wsh->ping_pid, SIGILL); + waitpid(wsh->ping_pid, NULL, 0); + } + + wano_inet_state_event_fini(&wsh->inet_state_watcher); + + ev_io_stop(EV_DEFAULT_ &wsh->ping_fd_watcher); + close(wsh->ping_fd[0]); + close(wsh->ping_fd[1]); + + free(wh); +} + +/* + * =========================================================================== + * Misc + * =========================================================================== + */ +void wanp_static_ipv4_inet_state_event_fn( + wano_inet_state_event_t *ise, + struct wano_inet_state *is) +{ + wanp_static_ipv4_handle_t *h = CONTAINER_OF(ise, wanp_static_ipv4_handle_t, inet_state_watcher); + + h->ipaddr = is->is_ipaddr; + + if (wanp_static_ipv4_state_do(&h->state, wanp_static_ipv4_do_INET_STATE_UPDATE, is) < 0) + { + LOG(ERR, "wanp_static_ipv4: Error sending action INET_STATE_UPDATE to state machine."); + } +} + +/* + * =========================================================================== + * Module Support + * =========================================================================== + */ +void wanp_static_ipv4_module_start(void) +{ + wano_plugin_register(&wanp_static_ipv4); +} + +void wanp_static_ipv4_module_stop(void) +{ + wano_plugin_unregister(&wanp_static_ipv4); +} + +MODULE(wanp_static_ipv4, wanp_static_ipv4_module_start, wanp_static_ipv4_module_stop) diff --git a/src/wano/src/wanp_static_ipv4.dot b/src/wano/src/wanp_static_ipv4.dot new file mode 100644 index 00000000..149ce5a6 --- /dev/null +++ b/src/wano/src/wanp_static_ipv4.dot @@ -0,0 +1,13 @@ +digraph { + INIT[init=true]; + INIT -> CONFIGURE_IP; + CONFIGURE_IP -> PROBE [label="INET_STATE_UPDATE"]; + PROBE -> PROBE [label="PING_FAILED"]; + PROBE -> RUNNING [label="PING_SUCCEEDED"]; + + TIMEOUT_EX[label="Timeout occurred"]; + CANCEL_EX[label="WAN cancelled"]; + + TIMEOUT_EX -> EXCEPTION [label="!TIMEOUT"]; + CANCEL_EX -> EXCEPTION [label="!CANCEL"]; +} diff --git a/src/wano/src/wanp_vlan.c b/src/wano/src/wanp_vlan.c new file mode 100644 index 00000000..d569cd52 --- /dev/null +++ b/src/wano/src/wanp_vlan.c @@ -0,0 +1,390 @@ +/* +Copyright (c) 2015, Plume Design Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the Plume Design Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "module.h" +#include "osa_assert.h" + +#include "wano.h" + +#include "wanp_vlan_stam.h" +#include "wano_localconfig.h" + +/* + * Structure representing a single VLAN plug-in instance + */ +struct wanp_vlan +{ + wano_plugin_handle_t wvl_handle; + char wvl_ifvlan[C_IFNAME_LEN]; + int wvl_vlanid; + bool wvl_if_created; + wano_plugin_status_fn_t *wvl_status_fn; + wanp_vlan_state_t wvl_state; + wano_inet_state_event_t wvl_inet_state_event; + wano_ppline_t wvl_ppl; +}; + +static void wanp_vlan_module_start(void); +static void wanp_vlan_module_stop(void); +static wano_plugin_ops_init_fn_t wanp_vlan_init; +static wano_plugin_ops_run_fn_t wanp_vlan_run; +static wano_plugin_ops_fini_fn_t wanp_vlan_fini; +static wano_inet_state_event_fn_t wanp_vlan_inet_state_event_fn; +static wano_ppline_status_fn_t wanp_vlan_ppline_status_fn; + +static struct wano_plugin wanp_vlan = WANO_PLUGIN_INIT( + "vlan", + 50, + WANO_PLUGIN_MASK_ALL, + wanp_vlan_init, + wanp_vlan_run, + wanp_vlan_fini); + +/* + * =========================================================================== + * Plugin implementation + * =========================================================================== + */ +wano_plugin_handle_t *wanp_vlan_init( + const struct wano_plugin *wp, + const char *ifname, + wano_plugin_status_fn_t *status_fn) +{ + struct wano_localconfig wlc; + struct wanp_vlan *self; + + /* Load the persistent VLAN configuration and verify that it is valid */ + if (!wano_localconfig_load(&wlc)) + { + LOG(INFO, "wanp_vlan: No persistent configuration present."); + return NULL; + } + + if (!wlc.DataService_exists) + { + LOG(INFO, "wanp_vlan: No persistent VLAN configuration exists."); + return NULL; + } + + if (wlc.DataService.VLAN <= 1 || wlc.DataService.VLAN >= 4096) + { + LOG(INFO, "wanp_vlan: Invalid VLAN ID: %d", wlc.DataService.VLAN); + return NULL; + } + + self = calloc(1, sizeof(struct wanp_vlan)); + ASSERT(self != NULL, "Error allocating VLAN plug-in object") + + STRSCPY(self->wvl_handle.wh_ifname, ifname); + self->wvl_handle.wh_plugin = wp; + self->wvl_status_fn = status_fn; + + self->wvl_vlanid = wlc.DataService.VLAN; + + /* Generate the interface name */ + snprintf(self->wvl_ifvlan, sizeof(self->wvl_ifvlan), "%s.%d", self->wvl_handle.wh_ifname, self->wvl_vlanid); + + LOG(INFO, "wanp_vlan: Creating interface %s with VLAN ID %d.", self->wvl_ifvlan, self->wvl_vlanid); + + return &self->wvl_handle; +} + +void wanp_vlan_run(wano_plugin_handle_t *wh) +{ + struct wanp_vlan *self = CONTAINER_OF(wh, struct wanp_vlan, wvl_handle); + + wanp_vlan_state_do(&self->wvl_state, wanp_vlan_do_INIT, NULL); +} + +void wanp_vlan_fini(wano_plugin_handle_t *wh) +{ + struct wanp_vlan *self = CONTAINER_OF(wh, struct wanp_vlan, wvl_handle); + + wano_inet_state_event_fini(&self->wvl_inet_state_event); + + wano_ppline_fini(&self->wvl_ppl); + + /* If the VLAN interface was created, disable it */ + if (self->wvl_if_created) + { + if (!WANO_INET_CONFIG_UPDATE( + self->wvl_ifvlan, + .enabled = WANO_TRI_FALSE, + .network = WANO_TRI_FALSE)) + { + LOG(WARN, "wanp_vlan: %s: Error disabling VLAN interface %s.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + } + } + + free(self); +} + +void wanp_vlan_inet_state_event_fn(wano_inet_state_event_t *ise, struct wano_inet_state *is) +{ + struct wanp_vlan *self = CONTAINER_OF(ise, struct wanp_vlan, wvl_inet_state_event); + + wanp_vlan_state_do(&self->wvl_state, wanp_vlan_do_INET_STATE_UPDATE, is); +} + +void wanp_vlan_ppline_status_fn(wano_ppline_t *ppl, enum wano_ppline_status ps) +{ + struct wanp_vlan *self = CONTAINER_OF(ppl, struct wanp_vlan, wvl_ppl); + + wanp_vlan_state_do(&self->wvl_state, wanp_vlan_do_PPLINE_UPDATE, &ps); +} + +/* + * =========================================================================== + * OVSDB support functions + * =========================================================================== + */ + +/* + * =========================================================================== + * State Machine + * =========================================================================== + */ +enum wanp_vlan_state wanp_vlan_state_INIT( + wanp_vlan_state_t *state, + enum wanp_vlan_action action, + void *data) +{ + (void)state; + (void)data; + + switch (action) + { + case wanp_vlan_do_INIT: + return wanp_vlan_IF_CREATE; + + default: + break; + } + + return 0; +} + +enum wanp_vlan_state wanp_vlan_state_IF_CREATE( + wanp_vlan_state_t *state, + enum wanp_vlan_action action, + void *data) +{ + (void)data; + + struct wanp_vlan *self = CONTAINER_OF(state, struct wanp_vlan, wvl_state); + struct wano_inet_state *is = data; + + switch (action) + { + case wanp_vlan_do_STATE_INIT: + /* + * Register to Wifi_Inet_State events and create the VLAN interface + * by populating Wifi_Inet_Config. + */ + if (!WANO_INET_CONFIG_UPDATE( + self->wvl_ifvlan, + .if_type = "vlan", + .parent_ifname = self->wvl_handle.wh_ifname, + .vlan_id = self->wvl_vlanid, + .network = WANO_TRI_TRUE, + .enabled = WANO_TRI_TRUE, + .ip_assign_scheme = "none")) + { + LOG(ERR, "wanp_vlan: %s: Error creating VLAN interface %s.", + self->wvl_handle.wh_ifname, + self->wvl_ifvlan); + return wanp_vlan_ERROR; + } + + wano_inet_state_event_init( + &self->wvl_inet_state_event, + self->wvl_handle.wh_ifname, + wanp_vlan_inet_state_event_fn); + + self->wvl_if_created = true; + break; + + case wanp_vlan_do_INET_STATE_UPDATE: + if (!is->is_enabled) break; + if (!is->is_network) break; + if (strcmp(is->is_ip_assign_scheme, "none") != 0) break; + + LOG(INFO, "wanp_vlan: %s: VLAN interface %s was successfully created.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + + wano_inet_state_event_fini(&self->wvl_inet_state_event); + + return wanp_vlan_PPLINE_CREATE; + + default: + break; + } + + return 0; +} + +enum wanp_vlan_state wanp_vlan_state_PPLINE_CREATE( + wanp_vlan_state_t *state, + enum wanp_vlan_action action, + void *data) +{ + (void)data; + + struct wanp_vlan *self = CONTAINER_OF(state, struct wanp_vlan, wvl_state); + enum wano_ppline_status *ps = data; + + switch (action) + { + case wanp_vlan_do_STATE_INIT: + /* Create a new IPv4/IPV6 plug-in pipeline on the VLAN interface */ + if (!wano_ppline_init( + &self->wvl_ppl, + self->wvl_ifvlan, + "vlan", + ~(WANO_PLUGIN_MASK_IPV4 | WANO_PLUGIN_MASK_IPV6), + wanp_vlan_ppline_status_fn)) + { + LOG(ERR, "wanp_vlan: %s: Error creating new plug-in pipeline on interface %s.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + return wanp_vlan_ERROR; + } + break; + + case wanp_vlan_do_PPLINE_UPDATE: + switch (*ps) + { + case WANO_PPLINE_OK: + return wanp_vlan_IDLE; + + case WANO_PPLINE_IDLE: + LOG(INFO, "wanp_vlan: %s: Pipeline wasn't able to provision any plug-ins on %s.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + return wanp_vlan_ERROR; + + case WANO_PPLINE_RESTART: + LOG(INFO, "wanp_vlan: %s: Plug-in pipeline restarted on %s.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + } + break; + + default: + break; + } + + return 0; +} + +enum wanp_vlan_state wanp_vlan_state_IDLE( + wanp_vlan_state_t *state, + enum wanp_vlan_action action, + void *data) +{ + (void)data; + + struct wanp_vlan *self = CONTAINER_OF(state, struct wanp_vlan, wvl_state); + enum wano_ppline_status *ps = data; + + switch (action) + { + case wanp_vlan_do_STATE_INIT: + { + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_BUSY); + STRSCPY(ws.ws_ifname, self->wvl_handle.wh_ifname); + STRSCPY(ws.ws_iftype, "eth"); + self->wvl_status_fn(&self->wvl_handle, &ws); + break; + } + + case wanp_vlan_do_PPLINE_UPDATE: + switch (*ps) + { + case WANO_PPLINE_OK: + break; + + case WANO_PPLINE_RESTART: + LOG(INFO, "wanp_vlan: %s: Plug-in pipeline restarted on %s.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + break; + + case WANO_PPLINE_IDLE: + LOG(ERR, "wano_vlan: %s: Plug-in pipeline failed on %s.", + self->wvl_handle.wh_ifname, self->wvl_ifvlan); + return wanp_vlan_ERROR; + + } + break; + + default: + break; + } + + return 0; +} + +enum wanp_vlan_state wanp_vlan_state_ERROR( + wanp_vlan_state_t *state, + enum wanp_vlan_action action, + void *data) +{ + (void)data; + + struct wanp_vlan *self = CONTAINER_OF(state, struct wanp_vlan, wvl_state); + + switch (action) + { + case wanp_vlan_do_STATE_INIT: + { + struct wano_plugin_status ws = WANO_PLUGIN_STATUS(WANP_ERROR); + STRSCPY(ws.ws_ifname, self->wvl_handle.wh_ifname); + STRSCPY(ws.ws_iftype, "eth"); + self->wvl_status_fn(&self->wvl_handle, &ws); + break; + } + + default: + break; + } + + return 0; +} + +/* + * =========================================================================== + * Module Support + * =========================================================================== + */ +void wanp_vlan_module_start(void) +{ + wano_plugin_register(&wanp_vlan); +} + +void wanp_vlan_module_stop(void) +{ + wano_plugin_unregister(&wanp_vlan); +} + +MODULE(wanp_vlan, wanp_vlan_module_start, wanp_vlan_module_stop) diff --git a/src/wano/src/wanp_vlan.dot b/src/wano/src/wanp_vlan.dot new file mode 100644 index 00000000..8ff018fb --- /dev/null +++ b/src/wano/src/wanp_vlan.dot @@ -0,0 +1,9 @@ +digraph { + INIT[init=true]; + INIT -> IF_CREATE [label="INIT"]; + IF_CREATE -> PPLINE_CREATE [label="INET_STATE_UPDATE"]; + IF_CREATE -> ERROR [label="STATE_INIT"]; + PPLINE_CREATE -> IDLE [label="PPLINE_UPDATE"]; + PPLINE_CREATE -> ERROR [label="PPLINE_UPDATE,STATE_INIT"]; + +} diff --git a/src/wano/unit.mk b/src/wano/unit.mk new file mode 100644 index 00000000..b0558322 --- /dev/null +++ b/src/wano/unit.mk @@ -0,0 +1,89 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################### +# +# WAN Orchestrator +# +############################################################################### +UNIT_DISABLE := $(if $(CONFIG_MANAGER_WANO),n,y) + +UNIT_NAME := wano +UNIT_TYPE := BIN + +UNIT_SRC += src/wano_connection_manager_uplink.c +UNIT_SRC += src/wano_inet_config.c +UNIT_SRC += src/wano_inet_state.c +UNIT_SRC += src/wano_localconfig.c +UNIT_SRC += src/wano_main.c +UNIT_SRC += src/wano_plugin.c +UNIT_SRC += src/wano_ppline.c + +UNIT_CFLAGS += -I$(UNIT_PATH)/src +UNIT_CFLAGS += -I$(UNIT_PATH)/inc + +UNIT_EXTERN_CFLAGS += -I$(UNIT_PATH)/inc + +UNIT_DEPS += src/lib/common +UNIT_DEPS += src/lib/json_util +UNIT_DEPS += src/lib/log +UNIT_DEPS += src/lib/module +UNIT_DEPS += src/lib/osa +UNIT_DEPS += src/lib/osn +UNIT_DEPS += src/lib/osp +UNIT_DEPS += src/lib/ovsdb +UNIT_DEPS += src/lib/pjs +UNIT_DEPS += src/lib/reflink +UNIT_DEPS += src/lib/target + +# WANO pipeline state machine +$(eval $(call stam_generate,src/wano_ppline.dot)) + +############################################################################### +# WAN Plug-ins +############################################################################### +ifeq ($(CONFIG_MANAGER_WANO_PLUGIN_DHCPV4),y) +UNIT_SRC += src/wanp_dhcpv4.c +$(eval $(call stam_generate,src/wanp_dhcpv4.dot)) +endif + +ifeq ($(CONFIG_MANAGER_WANO_PLUGIN_DHCPV6),y) +UNIT_SRC += src/wanp_dhcpv6.c +$(eval $(call stam_generate,src/wanp_dhcpv6.dot)) +endif + +ifeq ($(CONFIG_MANAGER_WANO_PLUGIN_STATIC_IPV4),y) +UNIT_SRC += src/wanp_static_ipv4.c +$(eval $(call stam_generate,src/wanp_static_ipv4.dot)) +endif + +ifeq ($(CONFIG_MANAGER_WANO_PLUGIN_PPPOE),y) +UNIT_SRC += src/wanp_pppoe.c +$(eval $(call stam_generate,src/wanp_pppoe.dot)) +endif + +ifeq ($(CONFIG_MANAGER_WANO_PLUGIN_VLAN),y) +UNIT_SRC += src/wanp_vlan.c +$(eval $(call stam_generate,src/wanp_vlan.dot)) +endif diff --git a/src/wm2/fut/unit.mk b/src/wm2/fut/unit.mk new file mode 100644 index 00000000..99b77705 --- /dev/null +++ b/src/wm2/fut/unit.mk @@ -0,0 +1,50 @@ +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +UNIT_NAME := fut_wm + +UNIT_DISABLE := $(if $(CONFIG_MANAGER_WM),n,y) + +# Template type: +UNIT_TYPE := FUT +# Output directory +UNIT_DIR := shell/tests/wm + +UNIT_FILE := wm2_setup.sh +UNIT_FILE += wm2_dfs_cac_aborted.sh +UNIT_FILE += wm2_ht_mode_and_channel_iteration.sh +UNIT_FILE += wm2_immutable_radio_freq_band.sh +UNIT_FILE += wm2_immutable_radio_hw_mode.sh +UNIT_FILE += wm2_immutable_radio_hw_type.sh +UNIT_FILE += wm2_immutable_radio_if_name.sh +UNIT_FILE += wm2_set_bcn_int.sh +UNIT_FILE += wm2_set_channel.sh +UNIT_FILE += wm2_set_ht_mode.sh +UNIT_FILE += wm2_set_radio_country.sh +UNIT_FILE += wm2_set_radio_enabled.sh +UNIT_FILE += wm2_set_radio_fallback_parents.sh +UNIT_FILE += wm2_set_radio_thermal_tx_chainmask.sh +UNIT_FILE += wm2_set_radio_tx_chainmask.sh +UNIT_FILE += wm2_set_radio_tx_power.sh +UNIT_FILE += wm2_set_radio_vif_configs.sh diff --git a/src/wm2/fut/wm2_dfs_cac_aborted.sh b/src/wm2/fut/wm2_dfs_cac_aborted.sh new file mode 100755 index 00000000..612e0ea7 --- /dev/null +++ b/src/wm2/fut/wm2_dfs_cac_aborted.sh @@ -0,0 +1,182 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +MY_NAME=$(basename $BASH_SOURCE) + +usage() +{ +cat << EOF +Usage: ${MY_NAME} [-h] radio_idx if_name ssid password channel1 channel2 ht_mode hw_mode mode vif_if_name default_channel channel_type +OPTIONS: + --help|-h : this help message +ARGUMENTS: + radio_idx : Wifi_VIF_Config::vif_radio_idx - (int)(required) + if_name : Wifi_Radio_Config::if_name - (string)(required) + ssid : Wifi_VIF_Config::ssid - ssid name (string)(required) + password : Wifi_VIF_Config::security - ssid password (string)(required) + channel1 : Wifi_Radio_Config::channel - (int)(required) + channel2 : Wifi_Radio_Config::channel - (int)(required) + ht_mode : Wifi_Radio_Config::ht_mode - (string)(required) + hw_mode : Wifi_Radio_Config::hw_mode - (string)(required) + mode : Wifi_VIF_Config::mode - (string)(required) + country : Wifi_Radio_Config::country - (string)(required) + vif_if_name : Wifi_VIF_Config::if_name - (string)(required) + default_channel : default channel when bringing up the interface - (int)(required) + channel_type : 'channel' type for checking DFS or NON_DFS - (string)(required) + +Problem statement (example): + - start on ch108 and wait for cac to complete + - When radar is detected, driver moves to ch120 + - while ch108 cac is in progress (cac=10minutes), announce switch to ch124 + - channnels 116,120,124,128 are on the same vht80 unii weather channel segment + - 'device takes too long to set the channel' +Script tests the following: + - cac must be aborted on initial channel, if channel change is requested while cac is in progress. + - correct transition to cac_started amd nop_finished states +Simplified test steps (example): + - Ensure ch120 and ch100 are available for cac + - Set ch120 in Wifi_Radio_Config, wait for ch120 cac_started else fail after 30s + - Set ch100 in Wifi_Radio_Config, wait for ch120 nop_finished + and ch100 is cac_started simultaneously, else fail after 30s + +DEPENDS: + managers: NM, WM +Example: + ${MY_NAME} 4 wifi2 50L test_wifi_50L WifiPassword123 100 120 HT80 11ac ap home-ap-l50 140 DFS +EOF +} + + +while getopts h option; do + case "$option" in + h) + usage + exit 1 + ;; + esac +done + +if [ $# -lt 13 ]; then + echo 1>&2 "$0: not enough arguments" + echo usage + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel1=$5 +channel2=$6 +ht_mode=$7 +hw_mode=$8 +mode=$9 +country=${10} +vif_if_name=${11} +default_channel=${12} +channel_type=${13} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$default_channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$default_channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "$tc_name: create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Checking if CHANNEL 1 is valid" +check_channel_type "$channel1" "$if_name" "$channel_type" && + log "$tc_name: check_channel_type - Channel $channel1 is valid" || + raise "$tc_name: check_channel_type - Channel $channel1 is not valid" -l "$tc_name" -tc + +log "$tc_name: Checking if CHANNEL 2 is valid" +check_channel_type "$channel2" "$if_name" "$channel_type" && + log "$tc_name: check_channel_type - Channel $channel2 is valid" || + raise "$tc_name: check_channel_type - Channel $channel2 is not valid" -l "$tc_name" -tc + +wait_for_function_response 0 "check_is_cac_started $channel1 $if_name" && + log "$tc_name - wait_for_function_response - channel $channel1 - CAC STARTED" || + raise "$tc_name - wait_for_function_response - channel $channel1 - CAC NOT STARTED" -l "$tc_name" -tc + +log "$tc_name: Do not wait for cac to finish, changing channel to $channel2" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u channel "$channel2" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - channel $channel2" || + raise "$tc_name: update_ovsdb_entry - Failed to update Wifi_Radio_Config - channel $channel2" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is channel "$channel2" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - channel $channel2" || + raise "$tc_name: wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - channel $channel2" -l "$tc_name" -tc + +wait_for_function_response 0 "check_is_nop_finished $channel1 $if_name" && + log "$tc_name - wait_for_function_response - channel $channel1 - NOP FINISHED" || + raise "$tc_name - wait_for_function_response - channel $channel1 - NOP NOT FINISHED" -l "$tc_name" -tc + +wait_for_function_response 0 "check_is_cac_started $channel2 $if_name" && + log "$tc_name - wait_for_function_response - channel $channel2 - CAC STARTED" || + raise "$tc_name - wait_for_function_response - channel $channel2 - CAC NOT STARTED" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_ht_mode_and_channel_iteration.sh b/src/wm2/fut/wm2_ht_mode_and_channel_iteration.sh new file mode 100755 index 00000000..ac34d729 --- /dev/null +++ b/src/wm2/fut/wm2_ht_mode_and_channel_iteration.sh @@ -0,0 +1,162 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + if_name=\$1 -- used as if_name in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$2 -- used as if_name in Wifi_VIF_Config table - (string)(required) + vif_radio_idx=\$3 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + ssid=\$4 -- used as ssid in Wifi_VIF_Config table - (string)(required) + security=\$5 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$6 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$7 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$8 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$9 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$10 -- used as country in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen HW TYPE. This is IMMUTABLE field and it can't be changed. If interface is not UP it brings up +the interface, and tries to set HW TYPE to desired value. IF IMMUTABLE field is changed test will FAIL. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac US ap home-ap-l50 qca4219" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + *) + echo "$usage" + echo "Invalid option $option provided" + exit 1 + ;; + esac +done + +if [ $# -lt 10 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +if_name=${1} +vif_if_name=${2} +vif_radio_idx=${3} +ssid=${4} +security=${5} +channel=${6} +ht_mode=${7} +hw_mode=${8} +mode=${9} +country=${10} +tc_name="wm2/$(basename "$0")" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +check_is_channel_ready_for_use "$channel" "$if_name" && + log "$tc_name: check_is_channel_ready_for_use - Channel $channel is ready for use" + +log "$tc_name: Setting interface settings {ht_mode:$ht_mode, channel:$channel}" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" \ + -u ht_mode "$ht_mode" \ + -u channel "$channel" && + log "$tc_name: Wifi_Radio_Config table updated - {ht_mode:$ht_mode, channel:$channel}" || + raise "Failed to update Wifi_Radio_Config - {ht_mode:$ht_mode, channel:$channel}" -l "$tc_name" -tc + +log "$tc_name: Waiting for settings to apply to Wifi_Radio_State {channel:$channel}" +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" \ + -is channel "$channel" && + log "$tc_name: Wifi_Radio_Config reflected to Wifi_Radio_State - {channel:$channel}" || + raise "Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - {channel:$channel}" -l "$tc_name" -tc + +log "$tc_name: Waiting for settings to apply to Wifi_Radio_State {ht_mode:$ht_mode}" +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" \ + -is ht_mode "$ht_mode" && + log "$tc_name: Wifi_Radio_Config reflected to Wifi_Radio_State - {ht_mode:$ht_mode}" || + raise "Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - {ht_mode:$ht_mode}" -l "$tc_name" -tc + +log "$tc_name: Waiting for channel to apply to Wifi_VIF_State {channel:$channel}" +wait_ovsdb_entry Wifi_VIF_State -w if_name "$vif_if_name" \ + -is channel "$channel" && + log "$tc_name: Wifi_Radio_Config channel reflected to Wifi_VIF_State - {channel:$channel}" || + raise "Failed to reflect Wifi_Radio_Config channel to Wifi_VIF_State - {channel:$channel}" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_immutable_radio_freq_band.sh b/src/wm2/fut/wm2_immutable_radio_freq_band.sh new file mode 100755 index 00000000..a264030b --- /dev/null +++ b/src/wm2/fut/wm2_immutable_radio_freq_band.sh @@ -0,0 +1,159 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + freq_band=\$11 -- used as freq_band in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen FREQ BAND. This is IMMUTABLE field and it can't be changed. If interface is not UP it brings up +the interface, and tries to set FREQ BAND to desired value. IF IMMUTABLE field is changed test will FAIL. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 5GU" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +freq_band=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +original_band=$(get_ovsdb_entry_value Wifi_Radio_State freq_band -w if_name "$if_name") + +if [ "$freq_band" = "$original_band" ]; then + raise "Chosen FREQ BAND ($freq_band) needs to be DIFFERENT from default FREQ BAND ($original_band) - ['2.4G', '5G', '5GL', '5GU']" -l "$tc_name" -tc +fi + +log "$tc_name: Changing FREQ BAND to $freq_band" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u freq_band "$freq_band" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - freq_band $freq_band" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - freq_band $freq_band" -l "$tc_name" -tc + +res=$(wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is freq_band "$freq_band" -ec -f) + +log "$tc_name: Reversing FREQ BAND to normal value" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u freq_band "$original_band" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - freq_band $original_band" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - freq_band $original_band" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is freq_band "$original_band" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - freq_band $original_band" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - freq_band $original_band" -l "$tc_name" -tc + +if [ "$res" -eq 0 ]; then + raise "FAIL: Immutable field freq_band was changed to $freq_band" -l "$tc_name" -tc +fi + +pass diff --git a/src/wm2/fut/wm2_immutable_radio_hw_mode.sh b/src/wm2/fut/wm2_immutable_radio_hw_mode.sh new file mode 100755 index 00000000..981115db --- /dev/null +++ b/src/wm2/fut/wm2_immutable_radio_hw_mode.sh @@ -0,0 +1,159 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + security=\$4 -- used as ssid security at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + custom_hw_mode=\$11 -- used as custom hw_mode in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen HW MODE. This is IMMUTABLE field and it can't be changed. If interface is not UP it brings up +the interface, and tries to set HW MODE to desired value. IF IMMUTABLE field is changed test will FAIL. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 11n" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +custom_hw_mode=${11} + +tc_name="wm2/$(basename "$0")" + +if [ "$hw_mode" = "$custom_hw_mode" ]; then + raise "hosen CUSTOM HW MODE ($custom_hw_mode) needs to be DIFFERENT from default HW MODE ($hw_mode)" -l "$tc_name" -tc +fi + +log "$tc_name: Checking if interface is up" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing HW MODE to $custom_hw_mode" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u hw_mode "$custom_hw_mode" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - hw_mode $custom_hw_mode" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - hw_mode $custom_hw_mode" -l "$tc_name" -tc + +res=$(wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is hw_mode "$custom_hw_mode" -ec -f) + +log "$tc_name: Reversing HW MODE to normal value" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u hw_mode "$hw_mode" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - hw_mode $hw_mode" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - hw_mode $hw_mode" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is hw_mode "$hw_mode" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - hw_mode $hw_mode" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - hw_mode $hw_mode" -l "$tc_name" -tc + +if [ "$res" -eq 0 ]; then + raise "Immutable field HW MODE was changed to $custom_hw_mode" -l "$tc_name" -tc +fi + +pass diff --git a/src/wm2/fut/wm2_immutable_radio_hw_type.sh b/src/wm2/fut/wm2_immutable_radio_hw_type.sh new file mode 100755 index 00000000..d3c49be6 --- /dev/null +++ b/src/wm2/fut/wm2_immutable_radio_hw_type.sh @@ -0,0 +1,158 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + hw_type=\$11 -- used as hw_type in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen HW TYPE. This is IMMUTABLE field and it can't be changed. If interface is not UP it brings up +the interface, and tries to set HW TYPE to desired value. IF IMMUTABLE field is changed test will FAIL. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac US ap home-ap-l50 qca4219" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +hw_type=${11} +tc_name="wm2/$(basename "$0")" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +original_hw_type=$(get_ovsdb_entry_value Wifi_Radio_State hw_type -w if_name "$if_name") + +if [ "$original_hw_type" = "$hw_type" ]; then + raise "Chosen custom hw_type ($hw_type) needs to be DIFFERENT from default hw_type ($original_hw_type)" -l "$tc_name" -tc +fi + +log "$tc_name: Changing HW TYPE to $hw_type" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u hw_type "$hw_type" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - hw_type $hw_type" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - hw_type $hw_type" -l "$tc_name" -tc + +res=$(wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is hw_type "$hw_type" -ec -f) + +log "$tc_name: Reversing HW TYPE to normal value" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u hw_type "$original_hw_type" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - hw_type $original_hw_type" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - hw_type $original_hw_type" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is hw_type "$original_hw_type" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - hw_type $original_hw_type" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - hw_type $original_hw_type" -l "$tc_name" -tc + +if [ "$res" -eq 0 ]; then + raise "HW TYPE was changed in Wifi_Radio_State $hw_type" -l "$tc_name" -tc +fi + +pass diff --git a/src/wm2/fut/wm2_immutable_radio_if_name.sh b/src/wm2/fut/wm2_immutable_radio_if_name.sh new file mode 100755 index 00000000..dfcee192 --- /dev/null +++ b/src/wm2/fut/wm2_immutable_radio_if_name.sh @@ -0,0 +1,155 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 \$11 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + custom_if_name=\$11 -- used as custom if_name in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen IF NAME. This is IMMUTABLE field and it can't be changed. If interface is not UP it brings up +the interface, and tries to set IF NAME to desired value. IF IMMUTABLE field is changed test will FAIL. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 wifi22" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +custom_if_name=${11} + +tc_name="wm2/$(basename "$0")" + +if [ "$if_name" = "$custom_if_name" ]; then + raise "Chosen if_name ($custom_if_name) needs to be DIFFERENT from default if_name ($if_name)" -l "$tc_name" -tc +fi + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Trying to change immutable field IF NAME to $custom_if_name" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u if_name "$custom_if_name" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config" -l "$tc_name" -tc + +wait_ovsdb_entry_remove Wifi_Radio_State -w if_name "$if_name" && + log "$tc_name: wait_ovsdb_entry_remove - Entry $if_name removed from Wifi_Radio_State" || + raise "wait_ovsdb_entry_remove - Entry $if_name not removed from Wifi_Radio_State" -l "$tc_name" -tc + +log "$tc_name: Reversing changes" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$custom_if_name" -u if_name "$if_name" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is if_name "$if_name" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_bcn_int.sh b/src/wm2/fut/wm2_set_bcn_int.sh new file mode 100755 index 00000000..2b7c10b0 --- /dev/null +++ b/src/wm2/fut/wm2_set_bcn_int.sh @@ -0,0 +1,147 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + bcn_int=\$11 -- used as bcn_int in Wifi_Radio_Config table - (int)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen BEACON INTERVAL. If interface is not UP it brings up the interface, and tries to set +BEACON INTERVAL to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 36 200" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +bcn_int=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing bcn_int to $bcn_int" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u bcn_int "$bcn_int" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - bcn_int $bcn_int" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - bcn_int $bcn_int" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is bcn_int "$bcn_int" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - bcn_int $bcn_int" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - bcn_int $bcn_int" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking BEACON INTERVAL at OS level" +check_beacon_interval_at_os_level "$bcn_int" "$vif_if_name" || + log "$tc_name: check_beacon_interval_at_os_level - BEACON INTERVAL set at OS level - bcn_int $bcn_int" || + raise "check_beacon_interval_at_os_level - BEACON INTERVAL not set at OS level - bcn_int $bcn_int" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_channel.sh b/src/wm2/fut/wm2_set_channel.sh new file mode 100755 index 00000000..1afba4ae --- /dev/null +++ b/src/wm2/fut/wm2_set_channel.sh @@ -0,0 +1,156 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 \$11 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + default_channel=\$11 -- used as default channel when bringing up the interface - (int)(required) + channel_type=\$12 -- used as channel type for checking DFS or NON_DFS - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen channel. If interface is not UP it brings up the interface, checks channel TYPE and +validity, and tries to set channel to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 4 wifi2 wm_dut_5gu_network WifiPassword123 128 HT20 11ac ap US home-ap-U50 149 DFS" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 12 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +default_channel=${11} +channel_type=${12} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$default_channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Checking if channel is valid" +check_channel_type "$channel" "$if_name" "$channel_type" && + log "$tc_name: check_channel_type - Channel $channel is valid" || + raise "check_channel_type - Channel $channel is not valid" -l "$tc_name" -tc + +check_is_channel_ready_for_use "$channel" "$if_name" && + log "$tc_name: check_is_channel_ready_for_use - Channel $channel is ready for use" + +log "$tc_name: Changing channel to $channel" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u channel "$channel" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - channel $channel" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - channel $channel" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is channel "$channel" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - channel $channel" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - channel $channel" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking channel $channel at OS level" +check_channel_at_os_level "$channel" "$vif_if_name" && + log "$tc_name: check_channel_at_os_level - Channel $channel set at OS level" || + raise "check_channel_at_os_level - Channel $channel not set at OS level" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_ht_mode.sh b/src/wm2/fut/wm2_set_ht_mode.sh new file mode 100755 index 00000000..f8e92d75 --- /dev/null +++ b/src/wm2/fut/wm2_set_ht_mode.sh @@ -0,0 +1,145 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen HT MODE. If interface is not UP it brings up the interface, and tries to set HT MODE +to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 10 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing ht_mode to $ht_mode" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u ht_mode "$ht_mode" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - ht_mode $ht_mode" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - ht_mode $ht_mode" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is ht_mode "$ht_mode" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - ht_mode $ht_mode" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - ht_mode $ht_mode" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking ht_mode at OS level" +check_ht_mode_at_os_level "$ht_mode" "$vif_if_name" "$channel" && + log "$tc_name: check_ht_mode_at_os_level - ht_mode set at OS level - ht_mode $ht_mode" || + raise "check_ht_mode_at_os_level - ht_mode not set at OS level - ht_mode $ht_mode" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_radio_country.sh b/src/wm2/fut/wm2_set_radio_country.sh new file mode 100755 index 00000000..f40d417f --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_country.sh @@ -0,0 +1,141 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + vif_if_name=\$9 -- used as if_name in Wifi_VIF_Config table - (string)(required) + country=\$10 -- used as country in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen COUNTRY. If interface is not UP it brings up the interface, and tries to set COUNTRY +to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 US" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +country_to_set=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing country to $country_to_set" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u country "$country_to_set" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - country $country_to_set" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - country $country_to_set" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is country "$country_to_set" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - country $country_to_set" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - country $country_to_set" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_radio_enabled.sh b/src/wm2/fut/wm2_set_radio_enabled.sh new file mode 100755 index 00000000..b05b22b4 --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_enabled.sh @@ -0,0 +1,157 @@ + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #!/bin/sh + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$9 -- used as if_name in Wifi_VIF_Config table - (string)(required) + enabled=\$10 -- used as enabled in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen COUNTRY. If interface is not UP it brings up the interface, and tries to set COUNTRY +to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 false" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +enabled=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing enabled to $enabled" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u enabled "$enabled" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - enabled $enabled" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - enabled $enabled" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is enabled "$enabled" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - enabled $enabled" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - enabled $enabled" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking ENABLED at OS level" + +case "$enabled" in + "true") + interface_is_up "$if_name" || + raise "interface_is_up true - Interface is DISABLED" -l "$tc_name" -tc && + log "$tc_name: interface_is_up true - Interface is ENABLED at Level 2" + ;; + "false") + interface_is_up "$if_name" && + raise "interface_is_up false - Interface is ENABLED" -l "$tc_name" -tc || + log "$tc_name: interface_is_up false - Interface is DISABLED at Level 2" + ;; +esac + +pass diff --git a/src/wm2/fut/wm2_set_radio_fallback_parents.sh b/src/wm2/fut/wm2_set_radio_fallback_parents.sh new file mode 100755 index 00000000..2a67efdf --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_fallback_parents.sh @@ -0,0 +1,152 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 \$11 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table, need to be DFS channel - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + fallback_bssid=\$11 -- used as country in Wifi_Radio_Config table - (string)(required) + fallback_channel=\$12 -- used as country in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen FALLBACK_PARENTS. If interface is not UP it brings up the interface, and tries to set FALLBACK_PARENTS +to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 1 wifi1 test_wifi_50L WifiPassword123 132 HT20 11ac ap US home-ap-l50 36" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +fallback_channel=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if interface is up" +(interface_is_up "$if_name" && ${OVSH} s Wifi_VIF_State -w if_name=="$if_name") || + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +fallback_bssid=`${OVSH} s Wifi_Radio_State mac -w if_name=="$if_name" -r` +#remove empty chars +fallback_bssid=`echo "$fallback_bssid"` + +fallback_parent="[\"map\",[[\"$fallback_bssid\",$fallback_channel]]]" + +log "$tc_name: Checking if STARTING CHANNEL is valid" +check_channel_type "$channel" "$if_name" DFS && + log "$tc_name: check_channel_type - STARTING Channel $channel is valid" || + raise "check_channel_type - STARTING Channel $channel is not valid" -l "$tc_name" -tc + +log "$tc_name: Checking if FALLBACK CHANNEL is valid" +check_channel_type "$fallback_channel" "$if_name" NON_DFS && + log "$tc_name: check_channel_type - FALLBACK Channel $fallback_channel is valid" || + raise "check_channel_type - FALLBACK Channel $fallback_channel is not valid" -l "$tc_name" -tc + +log "$tc_name: Setting FALLBACK_PARENT to $fallback_channel" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u fallback_parents "$fallback_parent" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is fallback_parents "$fallback_parent" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State" -l "$tc_name" -tc + +log "$tc_name: wait_ovsdb_entry - Triggering DFS RADAR EVENT" +simulate_DFS_radar "$if_name" || + log "$tc_name: wait_ovsdb_entry - FAILED to trigger DFS RADAR EVENT" + +wait_ovsdb_entry Wifi_Radio_State -w mac "$fallback_bssid" -is channel "$fallback_channel" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config FALLBACK_PARENT activated" || + raise "wait_ovsdb_entry - Failed to activate Wifi_Radio_Config FALLBACK_PARENT" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_radio_thermal_tx_chainmask.sh b/src/wm2/fut/wm2_set_radio_thermal_tx_chainmask.sh new file mode 100755 index 00000000..c3dac653 --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_thermal_tx_chainmask.sh @@ -0,0 +1,186 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 \$11 \$12 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$9 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$10 -- used as if_name in Wifi_VIF_Config table - (string)(required) + tx_chainmask=\$11 -- used as tx_chainmask in Wifi_Radio_Config table (recomended 1, 3, 7, 15)- (int)(required) + thermal_tx_chainmask=\$12 -- used as thermal_tx_chainmask in Wifi_Radio_Config table (recomended 1, 3, 7, 15) - (int)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen THERMAL TX CHAINMASK. If interface is not UP it brings up the interface, and tries to set +THERMAL TX CHAINMASK to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 36 5" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 12 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +tx_chainmask=${11} +thermal_tx_chainmask=${12} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Determining minimal value THERMAL TX CHAINMASK ($thermal_tx_chainmask) vs TX CHAINMASK ($tx_chainmask)" +if [ "$thermal_tx_chainmask" -gt "$tx_chainmask" ]; then + value_to_check=$tx_chainmask +else + value_to_check=$thermal_tx_chainmask +fi + +log "$tc_name: Checking if THERMAL TX CHAINMASK $thermal_tx_chainmask is valid value" + +if [ "$thermal_tx_chainmask" -gt 0 ] && [ "$thermal_tx_chainmask" -le 3 ]; then + max_tx_chainmask_value=3 +elif [ "$thermal_tx_chainmask" -gt 3 ] && [ "$thermal_tx_chainmask" -le 7 ]; then + max_tx_chainmask_value=7 +elif [ "$thermal_tx_chainmask" -gt 7 ] && [ "$thermal_tx_chainmask" -le 15 ]; then + max_tx_chainmask_value=15 +else [ "$thermal_tx_chainmask" -eq 0 ] || [ "$thermal_tx_chainmask" -gt 15 ] + raise "THERMAL TX CHAINMASK $thermal_tx_chainmask is invalid" -l "$tc_name" -tc +fi + +check_radio_mimo_config $max_tx_chainmask_value "$if_name" || + raise "check_radio_mimo_config THERMAL TX CHAINMASK - Failed" -l "$tc_name" -tc + +log "$tc_name: Checking if TX CHAINMASK '$tx_chainmask' is valid" + +if [ "$tx_chainmask" -gt 0 ] && [ "$tx_chainmask" -le 3 ]; then + max_tx_chainmask_value=3 +elif [ "$tx_chainmask" -gt 3 ] && [ "$tx_chainmask" -le 7 ]; then + max_tx_chainmask_value=7 +elif [ "$tx_chainmask" -gt 7 ] && [ "$tx_chainmask" -le 15 ]; then + max_tx_chainmask_value=15 +else [ "$tx_chainmask" -eq 0 ] || [ "$tx_chainmask" -gt 15 ] + raise "TX CHAINMASK value is invalid" -l "$tc_name" -tc +fi + +check_radio_mimo_config $max_tx_chainmask_value "$if_name" || + raise "check_radio_mimo_config TX CHAINMASK- Failed" -l "$tc_name" -tc + +log "$tc_name: Checking is interface UP and running" +(interface_is_up "$if_name" && ${OVSH} s Wifi_VIF_State -w if_name=="$if_name") || + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name create_radio_vif_interface - Success" || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing tx_chainmask to $tx_chainmask" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u tx_chainmask "$tx_chainmask" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - tx_chainmask $tx_chainmask" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - tx_chainmask $tx_chainmask" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is tx_chainmask "$tx_chainmask" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - tx_chainmask $tx_chainmask" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - tx_chainmask $tx_chainmask" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking TX CHAINMASK $tx_chainmask at OS level" +check_tx_chainmask_at_os_level "$tx_chainmask" "$if_name" && + log "$tc_name: check_tx_chainmask_at_os_level - TX CHAINMASK $tx_chainmask is SET at OS level" || + raise "check_tx_chainmask_at_os_level - TX CHAINMASK $tx_chainmask is NOT set at" -l "$tc_name" -tc + +log "$tc_name: Changing thermal_tx_chainmask to $thermal_tx_chainmask" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u thermal_tx_chainmask "$thermal_tx_chainmask" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - thermal_tx_chainmask $thermal_tx_chainmask" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - thermal_tx_chainmask $thermal_tx_chainmask" -l "$tc_name" -tc + +log "$tc_name: Check did it change tx_chainmask to $value_to_check" +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is tx_chainmask "$value_to_check" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - tx_chainmask $value_to_check" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - tx_chainmask $value_to_check" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking TX CHAINMASK $value_to_check at OS level" +check_tx_chainmask_at_os_level "$value_to_check" "$if_name" && + log "$tc_name: check_tx_chainmask_at_os_level - TX CHAINMASK $value_to_check is SET at OS level" || + raise "check_tx_chainmask_at_os_level - TX CHAINMASK $value_to_check is NOT set at" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_radio_tx_chainmask.sh b/src/wm2/fut/wm2_set_radio_tx_chainmask.sh new file mode 100755 index 00000000..b3460742 --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_tx_chainmask.sh @@ -0,0 +1,162 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$8 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$9 -- used as if_name in Wifi_VIF_Config table - (string)(required) + tx_chainmask=\$10 -- used as tx_chainmask in Wifi_Radio_Config table - (int)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen TX CHAINMASK. If interface is not UP it brings up the interface, and tries to set +TX CHAINMASK to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 36 5" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +tx_chainmask=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if TX CHAINMASK $tx_chainmask is valid" + +if [ "$tx_chainmask" -gt 0 ] && [ "$tx_chainmask" -le 3 ]; then + max_tx_chainmask_value=3 +elif [ "$tx_chainmask" -gt 3 ] && [ "$tx_chainmask" -le 7 ]; then + max_tx_chainmask_value=7 +elif [ "$tx_chainmask" -gt 7 ] && [ "$tx_chainmask" -le 15 ]; then + max_tx_chainmask_value=15 +else [ "$tx_chainmask" -eq 0 ] || [ "$tx_chainmask" -gt 15 ] + raise "TX CHAINMASK value is invalid" -l "$tc_name" -tc +fi + +check_radio_mimo_config $max_tx_chainmask_value "$if_name" || + raise "check_radio_mimo_config - Failed" -l "$tc_name" -tc + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing tx_chainmask to $tx_chainmask" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u tx_chainmask "$tx_chainmask" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - tx_chainmask $tx_chainmask" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - tx_chainmask $tx_chainmask" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is tx_chainmask "$tx_chainmask" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - tx_chainmask $tx_chainmask" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - tx_chainmask $tx_chainmask" -l "$tc_name" -tc + +log "$tc_name: LEVEL 2 - checking TX CHAINMASK at OS level" +check_tx_chainmask_at_os_level "$tx_chainmask" "$if_name" && + log "$tc_name: check_tx_chainmask_at_os_level - TX CHAINMASK set at OS level - tx_chainmask $tx_chainmask" || + raise "check_tx_chainmask_at_os_level - TX CHAINMASK not set at OS level - tx_chainmask $tx_chainmask" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_radio_tx_power.sh b/src/wm2/fut/wm2_set_radio_tx_power.sh new file mode 100755 index 00000000..7f97e193 --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_tx_power.sh @@ -0,0 +1,157 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + country=\$8 -- used as country in Wifi_Radio_Config table - (string)(required) + vif_if_name=\$9 -- used as if_name in Wifi_VIF_Config table - (string)(required) + tx_power=\$10 -- used as tx_power in Wifi_Radio_Config table - (int)(required) + min_tx_power=\$11 -- used as min_tx_power to validate tx_power - (int)(optional)(default:1) + max_tx_power=\$12 -- used as max_tx_power to validate tx_power - (int)(optional)(default:32) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to set chosen TX POWER. If interface is not UP it brings up the interface, and tries to set +TX POWER to desired value. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 23" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +tx_power=${11} +min_tx_power=${12:-1} +max_tx_power=${13:-32} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if tx_power $tx_power is valid {min:$min_tx_power, max:$max_tx_power}" +if [ "$tx_power" -gt "$max_tx_power" ] || [ "$tx_power" -lt "$min_tx_power" ]; then + raise "check_radio_tx_power_validity - Chosen tx_power is not valid {min:$min_tx_power, given:$tx_power, max:$max_tx_power}" -l "$tc_name" -tc +fi +log "$tc_name: check_radio_tx_power_validity - Chosen value $tx_power is valid" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Changing tx_power to $tx_power" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u tx_power "$tx_power" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - tx_power $tx_power" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - tx_power $tx_power" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_Radio_State -w if_name "$if_name" -is tx_power "$tx_power" && + log "$tc_name: wait_ovsdb_entry - Wifi_Radio_Config reflected to Wifi_Radio_State - tx_power $tx_power" || + raise "wait_ovsdb_entry - Failed to reflect Wifi_Radio_Config to Wifi_Radio_State - tx_power $tx_power" -l "$tc_name" -ow + +log "$tc_name: LEVEL 2 - checking tx_power $tx_power at OS level" +check_tx_power_at_os_level "$tx_power" "$vif_if_name" "$if_name" && + log "$tc_name: check_tx_power_at_os_level - tx_power $tx_power set at OS level" || + raise "check_tx_power_at_os_level - tx_power $tx_power not set at OS level" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_set_radio_vif_configs.sh b/src/wm2/fut/wm2_set_radio_vif_configs.sh new file mode 100755 index 00000000..153a2bda --- /dev/null +++ b/src/wm2/fut/wm2_set_radio_vif_configs.sh @@ -0,0 +1,160 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/nm2_lib.sh" +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +trap 'run_setup_if_crashed wm || true' EXIT SIGINT SIGTERM + +usage="$(basename "$0") [-h] [-c] [-s] [-fs] \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9 \$10 + +where options are: + -h show this help message + +where arguments are: + radio_idx=\$1 -- used as vif_radio_idx in Wifi_VIF_Config table - (int)(required) + if_name=\$2 -- used as if_name in Wifi_Radio_Config table - (string)(required) + ssid=\$3 -- used as ssid in Wifi_VIF_Config table - (string)(required) + password=\$4 -- used as ssid password at security column in Wifi_VIF_Config table - (string)(required) + channel=\$5 -- used as channel in Wifi_Radio_Config table - (int)(required) + ht_mode=\$6 -- used as ht_mode in Wifi_Radio_Config table - (string)(required) + hw_mode=\$7 -- used as hw_mode in Wifi_Radio_Config table - (string)(required) + mode=\$8 -- used as mode in Wifi_VIF_Config table - (string)(required) + vif_if_name=\$9 -- used as if_name in Wifi_VIF_Config table - (string)(required) + custom_channel=\$10 -- used as custom channel in Wifi_Radio_Config table - (string)(required) + +this script is dependent on following: + - running both WM and NM manager + +Script tries to delete chosen VIF_CONFIGS. This is relation field so when deleted, changes should not be propagated to +*_State tables. If interface is not UP it brings up the interface, and tries to delete VIF_CONFIGS. After that, +it executes several checks to see if relation is really working. + +Dependent on: + - running WM/NM managers - min_wm2_setup + +example of usage: + $(basename "$0") 2 wifi1 test_wifi_50L WifiPassword123 44 HT20 11ac ap US home-ap-l50 48" + +while getopts h option; do + case "$option" in + h) + echo "$usage" + exit 1 + ;; + esac +done + +if [ $# -lt 11 ]; then + echo 1>&2 "$0: not enough arguments" + echo "$usage" + exit 2 +fi + +vif_radio_idx=$1 +if_name=$2 +ssid=$3 +security=$4 +channel=$5 +ht_mode=$6 +hw_mode=$7 +mode=$8 +country=$9 +vif_if_name=${10} +custom_channel=${11} + +tc_name="wm2/$(basename "$0")" + +log "$tc_name: Checking if Radio/VIF states are valid for test" +check_radio_vif_state \ + -if_name "$if_name" \ + -vif_if_name "$vif_if_name" \ + -vif_radio_idx "$vif_radio_idx" \ + -ssid "$ssid" \ + -channel "$channel" \ + -security "$security" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" && + log "$tc_name: Radio/VIF states are valid" || + ( + log "$tc_name: Cleaning VIF_Config" + vif_clean + log "$tc_name: Radio/VIF states are not valid, creating interface..." + create_radio_vif_interface \ + -vif_radio_idx "$vif_radio_idx" \ + -channel_mode manual \ + -if_name "$if_name" \ + -ssid "$ssid" \ + -security "$security" \ + -enabled true \ + -channel "$channel" \ + -ht_mode "$ht_mode" \ + -hw_mode "$hw_mode" \ + -mode "$mode" \ + -country "$country" \ + -vif_if_name "$vif_if_name" && + log "$tc_name: create_radio_vif_interface - Success" + ) || + raise "create_radio_vif_interface - Failed" -l "$tc_name" -tc + +log "$tc_name: Save VIF_CONFIGS field for later use" +original_vif_configs=$(get_ovsdb_entry_value Wifi_Radio_Config vif_configs -w if_name "$if_name" -raw) + +log "$tc_name: Deleting VIF_CONFIGS" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u vif_configs "[\"set\",[]]" && + log "$tc_name: VIF_CONFIGS deleted" || + raise "Failed to update Wifi_Radio_Config for VIF_CONFIGS '[\"set\",[]]'" -l "$tc_name" -tc + +log "$tc_name: TEST 1 - Update CHANNEL $custom_channel - there should be no changes in Wifi_VIF_State" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u channel "$custom_channel" && + log "$tc_name: update_ovsdb_entry - Wifi_Radio_Config table updated - channel $custom_channel" || + raise "update_ovsdb_entry - Failed to update Wifi_Radio_Config - channel $custom_channel" -l "$tc_name" -tc + +wait_ovsdb_entry Wifi_VIF_State -w if_name "$vif_if_name" -is channel "$custom_channel" -ec -f && + log "$tc_name: PASS 1 - Wifi_VIF_State was not updated - channel $custom_channel" || + log "$tc_name: FAIL 1 - Wifi_VIF_State was updated without VIF_CONFIGS relation - channel $custom_channel" + +log "$tc_name: TEST 2 - Insert VIF_CONFIGS $original_vif_configs back into Wifi_Radio_Config" +update_ovsdb_entry Wifi_Radio_Config -w if_name "$if_name" -u vif_configs "$original_vif_configs" && + log "$tc_name: VIF_CONFIGS inserted - vif_configs $original_vif_configs" || + raise "Failed to update Wifi_Radio_Config for VIF_CONFIGS - $original_vif_configs" -l "$tc_name" -tc + +log "$tc_name: TEST 2 - Checking is CHANNEL $custom_channel updated in Wifi_VIF_State" +wait_ovsdb_entry Wifi_VIF_State -w if_name "$vif_if_name" -is channel "$custom_channel" && + log "$tc_name: Channel updated - $custom_channel" || + raise "Failed to update Wifi_VIF_State for CHANNEL $custom_channel" -l "$tc_name" -tc + +pass diff --git a/src/wm2/fut/wm2_setup.sh b/src/wm2/fut/wm2_setup.sh new file mode 100755 index 00000000..064699ce --- /dev/null +++ b/src/wm2/fut/wm2_setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright (c) 2015, Plume Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the Plume Design Inc. nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +# Setup test environment for WM tests. + +# Include basic environment config from default shell file and if any from FUT framework generated /tmp/fut_set_env.sh file +if [ -e "/tmp/fut_set_env.sh" ]; then + source /tmp/fut_set_env.sh +else + source /tmp/fut-base/shell/config/default_shell.sh +fi + +source "${FUT_TOPDIR}/shell/lib/unit_lib.sh" +source "${FUT_TOPDIR}/shell/lib/wm2_lib.sh" +source "${LIB_OVERRIDE_FILE}" + +tc_name="wm2/$(basename "$0")" + +wm_setup_test_environment "$@" && + log "$tc_name: wm_setup_test_environment - Success " || + raise "wm_setup_test_environment - Failed"-l "$tc_name" -ds + +exit 0 diff --git a/src/wm2/src/wm2.h b/src/wm2/src/wm2.h index 5b0201d2..7f839df6 100644 --- a/src/wm2/src/wm2.h +++ b/src/wm2/src/wm2.h @@ -40,28 +40,10 @@ extern ovsdb_table_t table_Openflow_Tag; int wm2_radio_init(void); -bool wm2_clients_init(char *ssid); - bool wm2_clients_update(struct schema_Wifi_Associated_Clients *client, char *vif, bool associated); void wm2_radio_update_port_state(const char *cloud_vif_ifname); -// v1 api: - -void callback_Wifi_Radio_Config_v1( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_Radio_Config *old_rec, - struct schema_Wifi_Radio_Config *rconf, - ovsdb_cache_row_t *row); - -void callback_Wifi_VIF_Config_v1( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_VIF_Config *old_rec, - struct schema_Wifi_VIF_Config *vconf, - ovsdb_cache_row_t *row); - -void wm2_radio_config_init_v1(); - #endif /* WM2_H_INCLUDED */ diff --git a/src/wm2/src/wm2_clients.c b/src/wm2/src/wm2_clients.c index 42272596..7666582b 100644 --- a/src/wm2/src/wm2_clients.c +++ b/src/wm2/src/wm2_clients.c @@ -335,23 +335,11 @@ wm2_clients_update(struct schema_Wifi_Associated_Clients *schema, char *ifname, json_t *row; char oftag[32]; bool ok; - int err; int n; oftag[0] = 0; - if (schema->key_id_exists) { - err = wm2_clients_oftag_from_key_id(ifname, - schema->key_id, - oftag, - sizeof(oftag)); - if (err) - LOGW("%s: failed to convert key '%s' to oftag (%s), expect openflow/firewall issues", - ifname, schema->key_id, oftag); - - LOGD("%s: key_id '%s' => oftag '%s'", - mac, schema->key_id, oftag); - } + wm2_clients_oftag_from_key_id(ifname, schema->key_id, oftag, sizeof(oftag)); LOGD("%s: update called with keyid='%s' oftag='%s' status=%d", mac, schema->key_id, oftag, status); @@ -457,21 +445,3 @@ wm2_clients_update(struct schema_Wifi_Associated_Clients *schema, char *ifname, return true; } - -/****************************************************************************** - * PUBLIC definitions - *****************************************************************************/ -bool -wm2_clients_init(char *if_name) -{ - if (!if_name) { - LOGE("Initializing clients (input validation failed)" ); - return false; - } - - if (false == target_clients_register(if_name, wm2_clients_update)) { - return false; - } - - return true; -} diff --git a/src/wm2/src/wm2_radio.c b/src/wm2/src/wm2_radio.c index 93192b46..b92ee5df 100644 --- a/src/wm2/src/wm2_radio.c +++ b/src/wm2/src/wm2_radio.c @@ -56,6 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define WM2_DFS_FALLBACK_GRACE_PERIOD_SECONDS 10 #define REQUIRE(ctx, cond) if (!(cond)) { LOGW("%s: %s: failed check: %s", ctx, __func__, #cond); return; } #define OVERRIDE(ctx, lv, rv) if (lv != rv) { lv = rv; LOGW("%s: overriding '%s' - this is target impl bug", ctx, #lv); } +#define bitcount __builtin_popcount struct wm2_delayed { ev_timer timer; @@ -75,7 +76,6 @@ ovsdb_table_t table_Wifi_Master_State; ovsdb_table_t table_Openflow_Tag; static ds_dlist_t delayed_list = DS_DLIST_INIT(struct wm2_delayed, list); -static bool wm2_api2; static bool wm2_lookup_rstate_by_freq_band(struct schema_Wifi_Radio_State *rstate, @@ -863,6 +863,14 @@ wm2_vconf_recalc(const char *ifname, bool force) memcpy(vconf.security, vstate.security, sizeof(vconf.security)); } + if (want && has && !rconf.enabled) { + LOGI("%s: disabling because radio %s is disabled too", vconf.if_name, rconf.if_name); + SCHEMA_SET_INT(vconf.enabled, false); + } + + if (want && !vconf.enabled && (!has || !vstate.enabled)) + return; + if (!wm2_vconf_changed(&vconf, &vstate, &vchanged) && !force) return; @@ -1043,6 +1051,8 @@ wm2_rconf_recalc_fixup_tx_chainmask(struct schema_Wifi_Radio_Config *rconf) return; if (!rconf->thermal_tx_chainmask_exists) return; + if (rconf->tx_chainmask_exists && bitcount(rconf->tx_chainmask) < bitcount(rconf->thermal_tx_chainmask)) + return; rconf->tx_chainmask = rconf->thermal_tx_chainmask; rconf->tx_chainmask_exists = true; @@ -1095,6 +1105,9 @@ wm2_rconf_recalc(const char *ifname, bool force) wm2_rconf_recalc_fixup_tx_chainmask(&rconf); } + if (want && !rconf.enabled && (!has || !rstate.enabled)) + return; + if (!wm2_rconf_changed(&rconf, &rstate, &changed) && !force) goto recalc; @@ -1170,6 +1183,8 @@ wm2_vstate_security_fixup(const struct schema_Wifi_VIF_Config *vconf, struct schema_Wifi_VIF_State *vstate) { struct schema_Wifi_VIF_State orig; + const char *key; + const char *val; bool want_mode; bool has_mixed; int i; @@ -1182,9 +1197,26 @@ wm2_vstate_security_fixup(const struct schema_Wifi_VIF_Config *vconf, memset(vstate->security_keys, 0, sizeof(vstate->security_keys)); vstate->security_len = 0; - for (i = 0; i < orig.security_len; i++) - if (strcmp(orig.security_keys[i], "mode") || want_mode || !has_mixed) - SCHEMA_KEY_VAL_APPEND(vstate->security, orig.security_keys[i], orig.security[i]); + for (i = 0; i < orig.security_len; i++) { + key = orig.security_keys[i]; + val = orig.security[i]; + + if (strstr(key, "oftag") == key) + continue; + + if (!strcmp(key, "mode") && !want_mode && has_mixed) + continue; + + SCHEMA_KEY_VAL_APPEND(vstate->security, key, val); + } + + for (i = 0; i < vconf->security_len; i++) { + key = vconf->security_keys[i]; + val = vconf->security[i]; + + if (strstr(key, "oftag") == key) + SCHEMA_KEY_VAL_APPEND(vstate->security, key, val); + } } static void @@ -1449,30 +1481,20 @@ static void callback_Wifi_Radio_Config( ovsdb_update_monitor_t *mon, struct schema_Wifi_Radio_Config *old_rec, - struct schema_Wifi_Radio_Config *rconf, - ovsdb_cache_row_t *row) + struct schema_Wifi_Radio_Config *rconf) { - if (wm2_api2) { - LOGD("%s: ovsdb updated", rconf->if_name); - wm2_rconf_recalc(rconf->if_name, false); - } else { - callback_Wifi_Radio_Config_v1(mon, old_rec, rconf, row); - } + LOGD("%s: ovsdb updated", rconf->if_name); + wm2_rconf_recalc(rconf->if_name, false); } static void callback_Wifi_VIF_Config( ovsdb_update_monitor_t *mon, struct schema_Wifi_VIF_Config *old_rec, - struct schema_Wifi_VIF_Config *vconf, - ovsdb_cache_row_t *row) + struct schema_Wifi_VIF_Config *vconf) { - if (wm2_api2) { - LOGD("%s: ovsdb updated", vconf->if_name); - wm2_vconf_recalc(vconf->if_name, false); - } else { - callback_Wifi_VIF_Config_v1(mon, old_rec, vconf, row); - } + LOGD("%s: ovsdb updated", vconf->if_name); + wm2_vconf_recalc(vconf->if_name, false); } static void @@ -1506,7 +1528,7 @@ wm2_radio_config_bump(void) * PUBLIC API definitions *****************************************************************************/ int -wm2_radio_init_v2(void) +wm2_radio_init_kickoff(void) { ovsdb_table_delete_where(&table_Wifi_Associated_Clients, json_array()); @@ -1551,17 +1573,14 @@ wm2_radio_init(void) OVSDB_TABLE_INIT(Wifi_Master_State, if_name); OVSDB_TABLE_INIT(Openflow_Tag, name); - if ((wm2_api2 = target_radio_init(&rops))) { - LOGI("Using new API v2"); - wm2_radio_init_v2(); - } else { - LOGW("Using old deprecated API v1"); - wm2_radio_config_init_v1(); - } + if (WARN_ON(!target_radio_init(&rops))) + return -1; + + wm2_radio_init_kickoff(); // Initialize OVSDB monitor callbacks - OVSDB_CACHE_MONITOR(Wifi_Radio_Config, true); - OVSDB_CACHE_MONITOR(Wifi_VIF_Config, true); + OVSDB_TABLE_MONITOR(Wifi_Radio_Config, true); + OVSDB_TABLE_MONITOR(Wifi_VIF_Config, true); return 0; } diff --git a/src/wm2/src/wm2_radio1.c b/src/wm2/src/wm2_radio1.c deleted file mode 100644 index 699f273a..00000000 --- a/src/wm2/src/wm2_radio1.c +++ /dev/null @@ -1,1196 +0,0 @@ -/* -Copyright (c) 2015, Plume Design Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the Plume Design Inc. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL Plume Design Inc. BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/****************************************************************************** - * WM2 radio v1 api - *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "os.h" -#include "util.h" -#include "ovsdb.h" -#include "ovsdb_update.h" -#include "ovsdb_sync.h" -#include "ovsdb_table.h" -#include "ovsdb_cache.h" -#include "schema.h" -#include "log.h" -#include "ds.h" -#include "json_util.h" -#include "wm2.h" - -#include "target.h" - -#define MODULE_ID LOG_MODULE_ID_MAIN - -#define WM2_FLAG_RADIO_CONFIGURED 1 -#define WM2_FLAG_VIF_POSTPONED 1 -#define WM2_FLAG_VIF_CONFIGURED 2 - -#define BLACKLIST(SCHEMA, FILTER, TABLE, COLUMN) \ - do { \ - schema_filter_blacklist(filter, SCHEMA_COLUMN(TABLE, COLUMN)); \ - SCHEMA->COLUMN ## _present = false; \ - } while (0) - -/****************************************************************************** - * PROTECTED definitions - *****************************************************************************/ - -static void -wm2_radio_init_clear( - ds_dlist_t *init_cfg) -{ - ds_dlist_iter_t radio_iter; - ds_dlist_iter_t vif_iter; - target_radio_cfg_t *radio; - target_vif_cfg_t *vif; - - for ( radio = ds_dlist_ifirst(&radio_iter, init_cfg); - radio != NULL; - radio = ds_dlist_inext(&radio_iter)) { - - for ( vif = ds_dlist_ifirst(&vif_iter, &radio->vifs_cfg); - vif != NULL; - vif = ds_dlist_inext(&vif_iter)) { - ds_dlist_iremove(&vif_iter); - free(vif); - vif = NULL; - } - ds_dlist_iremove(&radio_iter); - free(radio); - radio = NULL; - } -} - - -static bool -wm2_radio_update_VIF_state( - struct schema_Wifi_Radio_State *rstate_new, - schema_filter_t *rfilter) -{ - struct schema_Wifi_Radio_State rstate_old; - struct schema_Wifi_VIF_State vstate; - schema_filter_t vfilter; - int i; - bool ret; - char msg[64] = {0}; - - memset(&rstate_old, 0, sizeof(rstate_old)); - memset(&vstate, 0, sizeof(vstate)); - schema_filter_init(&vfilter, "+"); - - for(i=0; inum; i++) - { - if (!strcmp(rfilter->columns[i],SCHEMA_COLUMN(Wifi_Radio_State, channel)) ){ - SCHEMA_FF_SET_INT(&vfilter, &vstate, channel, rstate_new->channel); - char channel[10]; - snprintf(channel, sizeof(channel), "%d", rstate_new->channel); - strcat(msg, " channel: "); - strcat(msg, channel); - } - } - - if (vfilter.num < 2){ - LOGD("Updating VIF for radio %s (skipped)", - rstate_new->if_name); - return true; - } - - // Fetch VIF uuid's from radio state - ret = ovsdb_table_select_one(&table_Wifi_Radio_State, - SCHEMA_COLUMN(Wifi_Radio_State, if_name), - rstate_new->if_name, - &rstate_old); - if (!ret) { - LOGE("Updating VIF for radio %s (Failed to get radio from OVSDB)", - rstate_new->if_name); - return false; - } - - for (i=0; i < rstate_old.vif_states_len; i++) { - ret = - ovsdb_table_update_where_f( - &table_Wifi_VIF_State, - ovsdb_where_uuid("_uuid", rstate_old.vif_states[i].uuid), - &vstate, - vfilter.columns); - - if (!ret){ - LOGE("Updating VIF uuid %s for radio %s (Failed to update OVSDB)", - (char *)&rstate_old.vif_states[i], - rstate_old.if_name); - } - } - - LOGD("Updated VIF's with%s for radio %s", - msg, - rstate_new->if_name); - - return true; -} - -// Warning: if_name must be populated -static void -wm2_radio_state_update_cb( - struct schema_Wifi_Radio_State *rstate, schema_filter_t *filter) -{ - schema_filter_t rfilter; - bool ret; - char msg[64] = {0}; - - tsnprintf(msg, sizeof(msg), "Updating radio state %s", rstate->if_name); - LOGD("%s", msg); - - if (!*rstate->if_name) { - LOGW("%s: if_name missing", msg); - return; - } - - if (rstate->_partial_update) { - // if partial update ignore filter - filter = NULL; - goto do_update; - } - - if (filter && filter->num <= 1) { - LOGW("%s: no field selected", msg); - return; - } - - if (filter) { - ret = wm2_radio_update_VIF_state(rstate, filter); - if (!ret) { - LOGE("Updating radio %s (Failed to update VIF state)", rstate->if_name); - } - } - - if (!filter) { - filter = &rfilter; - schema_filter_init(filter, "-"); - } - -do_update: - - BLACKLIST(rstate, filter, Wifi_Radio_State, radio_config); - BLACKLIST(rstate, filter, Wifi_Radio_State, vif_states); - - ret = ovsdb_table_update_f(&table_Wifi_Radio_State, rstate, filter ? filter->columns : NULL); - - if (ret) { - LOGT("%s: Done", msg); - } else { - LOGE("%s: Error", msg); - } -} - -// Warning: if_name must be populated -void wm2_radio_config_update_cb( - struct schema_Wifi_Radio_Config *rconf, schema_filter_t *filter) -{ - schema_filter_t s_filter; - char **fcolumns = NULL; - char msg[64]; - bool ret; - int i; - - tsnprintf(msg, sizeof(msg), "Updating ovsdb radio conf %s", rconf->if_name); - LOGI("%s", msg); - - if (!*rconf->if_name) { - LOGW("%s: if_name missing", msg); - return; - } - - if (rconf->_partial_update) { - // if partial update ignore filter - filter = NULL; - goto do_update; - } - - if (filter && filter->num <= 1) { - LOGW("%s: no field selected", msg); - return; - } - - if (!filter) { - // Auto-generate filter - filter = &s_filter; - schema_filter_init(&s_filter, "+"); - i = s_filter.num; - -#define UPDATE_FILTER(x) if (rconf->x##_exists && (i < SCHEMA_FILTER_LEN)) \ - s_filter.columns[i++] = SCHEMA_COLUMN(Wifi_Radio_Config, x) -#define UPDATE_OBJ_FILTER(x) if (rconf->x##_len > 0 && (i < SCHEMA_FILTER_LEN)) \ - s_filter.columns[i++] = SCHEMA_COLUMN(Wifi_Radio_Config, x) - - UPDATE_FILTER(enabled); - UPDATE_FILTER(hw_type); - UPDATE_OBJ_FILTER(hw_config); - UPDATE_FILTER(country); - UPDATE_FILTER(channel); - UPDATE_FILTER(channel_sync); - UPDATE_FILTER(channel_mode); - UPDATE_FILTER(hw_mode); - UPDATE_FILTER(ht_mode); - UPDATE_FILTER(thermal_shutdown); - UPDATE_OBJ_FILTER(temperature_control); - UPDATE_FILTER(tx_power); - -#undef UPDATE_FILTER -#undef UPDATE_OBJ_FILTER - - if (i >= SCHEMA_FILTER_LEN) { - LOGE("Radio config update callback %s (filter too large)", - rconf->if_name); - return; - } - else if (i <= 1) { - LOGE("Radio config update callback %s (filter empty)", - rconf->if_name); - return; - } - } - if (filter) { - fcolumns = filter->columns; - } - -do_update: - - BLACKLIST(rconf, filter, Wifi_Radio_Config, vif_configs); - - ret = ovsdb_table_update_f(&table_Wifi_Radio_Config, rconf, fcolumns); - if (ret) { - LOGT("%s: Done", msg); - } - else { - LOGE("%s: Error", msg); - } -} - -static void -wm2_radio_configure_postponed_vifs( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_Radio_Config *radio_conf) -{ - ovsdb_cache_row_t *vconf_row; - ovsdb_update_type_t orig_type; - struct schema_Wifi_VIF_Config *vconf; - char *uuid; - int i; - - for (i=0; i < radio_conf->vif_configs_len; i++) { - uuid = radio_conf->vif_configs[i].uuid; - vconf_row = ovsdb_cache_find_row_by_uuid(&table_Wifi_VIF_Config, uuid); - if (!vconf_row || !vconf_row->user_flags) { - continue; - } - vconf = (void*)vconf_row->record; - if (vconf_row->user_flags == WM2_FLAG_VIF_POSTPONED) { - /* FIXME: The `mon` here will belong to Radio - * update and it may contain NEW or - * MODIFY. However VIF can be postponed - * only during NEW. It must be re-tried - * with NEW as well becuase it's the only - * way to insert the initial VIF_State - * entry for the VIF. - * - * There are other mon-> fields that can - * be touched and still contain Radio - * table specific bits. Fortunately for - * NEW case they aren't touched. This - * should be fixed though. - */ - orig_type = mon->mon_type; - mon->mon_type = OVSDB_UPDATE_NEW; - callback_Wifi_VIF_Config_v1(mon, NULL, vconf, vconf_row); - mon->mon_type = orig_type; - } - } -} - -static bool -wm2_radio_equal( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_Radio_Config *rconf, - struct schema_Wifi_Radio_Config *rconf_set) -{ - struct schema_Wifi_Radio_State rstate; - int index = 0; - bool is_equal = true; - - memset(&rstate, 0, sizeof(rstate)); - bool ret = ovsdb_table_select_one(&table_Wifi_Radio_State, - SCHEMA_COLUMN(Wifi_Radio_State, if_name), - rconf->if_name, - &rstate); - - if (!ret){ - LOGW("Sync check (radio state missing)"); - memmove (rconf_set, rconf, sizeof(*rconf_set)); - return false; - } - -#define RADIO_EQUAL(equal) if (!equal) is_equal = false - - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, channel))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, channel)); - if (!is_equal) { - rconf_set->channel = rconf->channel; - rconf_set->channel_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, channel_mode))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_STR(rconf, &rstate, channel_mode)); - if (!is_equal) { - STRSCPY(rconf_set->channel_mode, rconf->channel_mode); - rconf_set->channel_mode_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, channel_sync))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, channel_sync)); - if (!is_equal) { - rconf_set->channel_sync = rconf->channel_sync; - rconf_set->channel_sync_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, country))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_STR(rconf, &rstate, country)); - if (!is_equal) { - STRSCPY(rconf_set->country, rconf->country); - rconf_set->country_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, enabled))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, enabled)); - if (!is_equal) { - rconf_set->enabled = rconf->enabled; - rconf_set->enabled_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, freq_band))){ - if (strcmp(rconf->freq_band, rstate.freq_band)) { - is_equal = false; - STRSCPY(rconf_set->freq_band, rconf->freq_band); - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, ht_mode))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_STR(rconf, &rstate, ht_mode)); - if (!is_equal) { - STRSCPY(rconf_set->ht_mode, rconf->ht_mode); - rconf_set->ht_mode_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, hw_config))) { - if (rconf->hw_config_len == rstate.hw_config_len) { - for (index = 0; index < rconf->hw_config_len; index++) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_MAP_STR(rconf, &rstate, hw_config, index)); - } - } else { - is_equal = false; - } - if (!is_equal) { - for (index = 0; index < rconf->hw_config_len; index++) { - STRSCPY(rconf_set->hw_config[index], rconf->hw_config[index]); - STRSCPY(rconf_set->hw_config_keys[index], rconf->hw_config_keys[index]); - } - rconf_set->hw_config_len = rconf->hw_config_len; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, hw_mode))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_STR(rconf, &rstate, hw_mode)); - if (!is_equal) { - STRSCPY(rconf_set->hw_mode, rconf->hw_mode); - rconf_set->hw_mode_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, thermal_shutdown))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, thermal_shutdown)); - if (!is_equal) { - rconf_set->thermal_shutdown = rconf->thermal_shutdown; - rconf_set->thermal_shutdown_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, thermal_integration))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, thermal_integration)); - if (!is_equal) { - rconf_set->thermal_integration = rconf->thermal_integration; - rconf_set->thermal_integration_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, thermal_downgrade_temp))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, thermal_downgrade_temp)); - if (!is_equal) { - rconf_set->thermal_downgrade_temp = rconf->thermal_downgrade_temp; - rconf_set->thermal_downgrade_temp_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, thermal_upgrade_temp))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, thermal_upgrade_temp)); - if (!is_equal) { - rconf_set->thermal_upgrade_temp = rconf->thermal_upgrade_temp; - rconf_set->thermal_upgrade_temp_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, tx_chainmask))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, tx_chainmask)); - if (!is_equal) { - rconf_set->tx_chainmask = rconf->tx_chainmask; - rconf_set->tx_chainmask_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, temperature_control))){ - if (rconf->temperature_control_len == rstate.temperature_control_len) { - for (index = 0; index < rconf->temperature_control_len; index++) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_MAP_INT_STR(rconf, &rstate, temperature_control, index)); - } - } else { - is_equal = false; - } - if (!is_equal) { - for (index = 0; index < rconf->hw_config_len; index++) { - STRSCPY(rconf_set->temperature_control[index], rconf->temperature_control[index]); - rconf_set->temperature_control_keys[index] = rconf->temperature_control_keys[index]; - } - rconf_set->temperature_control_len = rconf->temperature_control_len; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_Radio_Config, tx_power))) { - RADIO_EQUAL(SCHEMA_FIELD_CMP_INT(rconf, &rstate, tx_power)); - if (!is_equal) { - rconf_set->tx_power = rconf->tx_power; - rconf_set->tx_power_exists = true; - } - } - -#undef RADIO_EQUAL - - return is_equal; -} - -void callback_Wifi_Radio_Config_v1( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_Radio_Config *old_rec, - struct schema_Wifi_Radio_Config *rconf, - ovsdb_cache_row_t *row) -{ - bool ret; - struct schema_Wifi_Radio_State rstate; - struct schema_Wifi_Radio_Config rconf_set; - - // configure - switch (mon->mon_type) { - default: - case OVSDB_UPDATE_ERROR: - LOGW("Radio config: mon upd error: %d", mon->mon_type); - return; - - case OVSDB_UPDATE_DEL: - // disable on delete - rconf->enabled = false; - // falls through - - case OVSDB_UPDATE_NEW: - case OVSDB_UPDATE_MODIFY: - - memset(&rconf_set, 0, sizeof(rconf_set)); - if (!wm2_radio_equal(mon, rconf, &rconf_set)) { - LOGD("Configuring radio %s through %s", rconf->if_name, - ovsdb_update_type_to_str(mon->mon_type)); - - /* Set radio with new data */ - ret = target_radio_config_set (rconf->if_name, &rconf_set); - if (true != ret) { - return; - } - - LOGN("Configured radio %s band %s chan %d mode %s status %s", - rconf->if_name, - rconf->freq_band, - rconf->channel, - rconf->channel_mode, - rconf->enabled ? "enabled":"disabled"); - } - else { - LOGN("Configuring Radio %s (skipped)", rconf->if_name); - } - - if (mon->mon_type == OVSDB_UPDATE_NEW) { - // register callback for external (non-ovsdb) radio config update - ret = target_radio_config_register(rconf->if_name, wm2_radio_config_update_cb); - if (true != ret) { - LOGE("Updating radio %s (Failed to register callback)", rconf->if_name); - return; - } - } - break; - } - - // update state and register state callback - switch (mon->mon_type) { - case OVSDB_UPDATE_DEL: - { - // Cannot select on Wifi_Radio_State.rconfig == rconf->_uuid - // because uuid references get removed automatically by ovsdb - // immediately when the config record is removed, event before we get a - // monitor update. So at this time Wifi_Radio_State.rconfig is empty. - // Therefore we use if_name to identify the matching radio state. - ovsdb_table_delete_simple(&table_Wifi_Radio_State, - SCHEMA_COLUMN(Wifi_Radio_State, if_name), - rconf->if_name); - - LOGD("Removed radio %s from state", - rconf->if_name); - } - break; - case OVSDB_UPDATE_NEW: - { - memset(&rstate, 0, sizeof(rstate)); - ret = target_radio_state_get(rconf->if_name, &rstate); - if (true != ret) { - LOGE("Updating radio %s (Failed to fetch state data)", - rconf->if_name); - return; - } - - STRSCPY(rstate.radio_config.uuid, rconf->_uuid.uuid); - rstate.radio_config_exists = true; - - char *filter[] = { "-", SCHEMA_COLUMN(Wifi_Radio_State, vif_states), NULL }; - ret = ovsdb_table_upsert_f(&table_Wifi_Radio_State, &rstate, false, filter); - if (true != ret) { - LOGE("Updating radio %s (Failed to insert state)", - rstate.if_name); - return; - } - LOGD("Added radio %s to state", rstate.if_name); - - // NEW Radio mark Configured - row->user_flags = WM2_FLAG_RADIO_CONFIGURED; - wm2_radio_configure_postponed_vifs(mon, rconf); - - ret = - target_radio_state_register( - rconf->if_name, - wm2_radio_state_update_cb); - if (true != ret) { - LOGE("Updating radio %s (Failed to register state data)", - rconf->if_name); - return; - } - } - break; - case OVSDB_UPDATE_MODIFY: - { - // state is updated by registered callbacks - // LOGD("Updated radio %s to state", rconf->if_name); - wm2_radio_configure_postponed_vifs(mon, rconf); - } - break; - default: - return; - } -} - -static ovsdb_cache_row_t* -wm2_radio_find_Radio_Config_by_vif_config( - char *vconf_uuid) -{ - struct schema_Wifi_Radio_Config *conf; - ovsdb_table_t *table = &table_Wifi_Radio_Config; - ovsdb_cache_row_t *row; - int i; - - ds_tree_foreach(&table->rows, row) { - conf = (void*)row->record; - for (i=0; i < conf->vif_configs_len; i++) { - if (strcmp(conf->vif_configs[i].uuid, vconf_uuid) == 0) { // match - return row; - } - } - } - return NULL; -} - -void wm2_vif_config_update_cb( - struct schema_Wifi_VIF_Config *vconf, schema_filter_t *filter) -{ - schema_filter_t s_filter; - char **fcolumns = NULL; - char msg[64]; - bool ret; - int i; - - tsnprintf(msg, sizeof(msg), "Updating VIF conf %s", vconf->if_name); - - if (!*vconf->if_name) { - LOGW("%s: if_name missing", msg); - return; - } - - if (vconf->_partial_update) { - // if partial update ignore filter - filter = NULL; - goto do_update; - } - - if (filter && filter->num <= 1) { - LOGW("%s: no field selected", msg); - return; - } - - if (!filter) { - // Auto-generate filter - filter = &s_filter; - schema_filter_init(&s_filter, "+"); - i = s_filter.num; -#define UPDATE_FILTER(x) if (vconf->x##_exists && (i < SCHEMA_FILTER_LEN)) \ - s_filter.columns[i++] = SCHEMA_COLUMN(Wifi_VIF_Config, x) -#define UPDATE_OBJ_FILTER(x) if (vconf->x##_len > 0 && (i < SCHEMA_FILTER_LEN)) \ - s_filter.columns[i++] = SCHEMA_COLUMN(Wifi_VIF_Config, x) - - UPDATE_FILTER(bridge); - UPDATE_FILTER(enabled); - UPDATE_FILTER(mode); - UPDATE_FILTER(parent); - UPDATE_FILTER(vif_dbg_lvl); - UPDATE_FILTER(vif_radio_idx); - UPDATE_FILTER(wds); - UPDATE_FILTER(ssid); - UPDATE_FILTER(ssid_broadcast); - UPDATE_OBJ_FILTER(security); - UPDATE_FILTER(mac_list_type); - UPDATE_OBJ_FILTER(mac_list); - -#undef UPDATE_FILTER -#undef UPDATE_OBJ_FILTER - - if (i >= SCHEMA_FILTER_LEN) { - LOGE("Radio VIF config update callback %s (filter too large)", - vconf->if_name); - return; - } - else if (i <= 1) { - LOGE("Radio VIF config update callback %s (filter empty)", - vconf->if_name); - return; - } - } - if (filter) { - fcolumns = filter->columns; - } - -do_update: - - ret = ovsdb_table_update_f(&table_Wifi_VIF_Config, vconf, fcolumns); - if (ret) { - LOGT("%s: Done", msg); - } - else { - LOGE("%s: Error", msg); - } -} - -// Warning: if_name must be populated -static void -wm2_radio_vif_state_update_cb( - struct schema_Wifi_VIF_State *vstate, schema_filter_t *filter) -{ - schema_filter_t vfilter; - bool ret; - char msg[64] = {0}; - - - tsnprintf(msg, sizeof(msg), "Updating VIF state %s", vstate->if_name); - LOGD("%s", msg); - - if (!*vstate->if_name) { - LOGW("%s: if_name missing", msg); - return; - } - - if (vstate->_partial_update) { - // if partial update ignore filter - filter = NULL; - goto do_update; - } - - if (filter && filter->num <= 1) { - LOGW("%s: no field selected", msg); - return; - } - - if (!filter) { - filter = &vfilter; - schema_filter_init(filter, "-"); - } - -do_update: - - BLACKLIST(vstate, filter, Wifi_VIF_State, associated_clients); - BLACKLIST(vstate, filter, Wifi_VIF_State, vif_config); - - ret = ovsdb_table_update_f(&table_Wifi_VIF_State, vstate, filter ? filter->columns : NULL); - - wm2_radio_update_port_state(vstate->if_name); - - if (ret){ - LOGT("%s: Done", msg); - } - else { - LOGE("%s: Error", msg); - } -} - -static bool -wm2_vif_equal( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_VIF_Config *vconf, - struct schema_Wifi_VIF_Config *vconf_set) -{ - struct schema_Wifi_VIF_State vstate; - int index = 0; - bool is_equal = true; - - - memset(&vstate, 0, sizeof(vstate)); - bool ret = ovsdb_table_select_one(&table_Wifi_VIF_State, - SCHEMA_COLUMN(Wifi_VIF_State, if_name), - vconf->if_name, - &vstate); - if (!ret){ - LOGW("Sync check (vif state missing)"); - memmove (vconf_set, vconf, sizeof(*vconf_set)); - return false; - } - -#define VIF_EQUAL(equal) if (!equal) is_equal = false - - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, bridge))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_STR(vconf, &vstate, bridge)); - if (!is_equal) { - STRSCPY(vconf_set->bridge, vconf->bridge); - vconf_set->bridge_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, enabled))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, enabled)); - if (!is_equal) { - vconf_set->enabled = vconf->enabled; - vconf_set->enabled_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, ap_bridge))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, ap_bridge)); - if (!is_equal) { - vconf_set->ap_bridge = vconf->ap_bridge; - vconf_set->ap_bridge_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, mac_list))){ - if (vconf->mac_list_len == vstate.mac_list_len) { - for (index = 0; index < vconf->mac_list_len; index++) { - VIF_EQUAL(SCHEMA_FIELD_CMP_LIST_STR(vconf, &vstate, mac_list, index)); - } - } else { - is_equal = false; - } - if (!is_equal) { - for (index = 0; index < vconf->mac_list_len; index++) { - STRSCPY(vconf_set->mac_list[index], vconf->mac_list[index]); - } - vconf_set->mac_list_len = vconf->mac_list_len; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, mac_list_type))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_STR(vconf, &vstate, mac_list_type)); - if (!is_equal) { - STRSCPY(vconf_set->mac_list_type, vconf->mac_list_type); - vconf_set->mac_list_type_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, mode))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_STR(vconf, &vstate, mode)); - if (!is_equal) { - STRSCPY(vconf_set->mode, vconf->mode); - vconf_set->mode_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, parent))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_STR(vconf, &vstate, parent)); - if (!is_equal) { - STRSCPY(vconf_set->parent, vconf->parent); - vconf_set->parent_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, security))){ - if (vconf->security_len == vstate.security_len) { - for (index = 0; index < vconf->security_len; index++) { - VIF_EQUAL(SCHEMA_FIELD_CMP_MAP_STR(vconf, &vstate, security, index)); - } - } else { - is_equal = false; - } - if (!is_equal) { - for (index = 0; index < vconf->security_len; index++) { - STRSCPY(vconf_set->security[index], vconf->security[index]); - STRSCPY(vconf_set->security_keys[index], vconf->security_keys[index]); - } - vconf_set->security_len = vconf->security_len; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, ssid))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_STR(vconf, &vstate, ssid)); - if (!is_equal) { - STRSCPY(vconf_set->ssid, vconf->ssid); - vconf_set->ssid_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, ssid_broadcast))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_STR(vconf, &vstate, ssid_broadcast)); - if (!is_equal) { - STRSCPY(vconf_set->ssid_broadcast, vconf->ssid_broadcast); - vconf_set->ssid_broadcast_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, vif_radio_idx))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, vif_radio_idx)); - if (!is_equal) { - vconf_set->vif_radio_idx = vconf->vif_radio_idx; - vconf_set->vif_radio_idx_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, uapsd_enable))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, uapsd_enable)); - if (!is_equal) { - vconf_set->uapsd_enable = vconf->uapsd_enable; - vconf_set->uapsd_enable_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, group_rekey))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, group_rekey)); - if (!is_equal) { - vconf_set->group_rekey = vconf->group_rekey; - vconf_set->group_rekey_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, ft_psk))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, ft_psk)); - if (!is_equal) { - vconf_set->ft_psk = vconf->ft_psk; - vconf_set->ft_psk_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, ft_mobility_domain))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, ft_mobility_domain)); - if (!is_equal) { - vconf_set->ft_mobility_domain = vconf->ft_mobility_domain; - vconf_set->ft_mobility_domain_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, vlan_id))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, vlan_id)); - if (!is_equal) { - vconf_set->vlan_id = vconf->vlan_id; - vconf_set->vlan_id_exists = true; - } - } - if (ovsdb_update_changed(mon, SCHEMA_COLUMN(Wifi_VIF_Config, wds))) { - VIF_EQUAL(SCHEMA_FIELD_CMP_INT(vconf, &vstate, wds)); - if (!is_equal) { - vconf_set->wds = vconf->wds; - vconf_set->wds_exists = true; - } - } - -#undef VIF_EQUAL - - return is_equal; -} - -void callback_Wifi_VIF_Config_v1( - ovsdb_update_monitor_t *mon, - struct schema_Wifi_VIF_Config *old_rec, - struct schema_Wifi_VIF_Config *vconf, - ovsdb_cache_row_t *row) -{ - bool ret; - ovsdb_cache_row_t *radio_conf_row = NULL; - struct schema_Wifi_VIF_State vstate; - struct schema_Wifi_VIF_Config vconf_set; - - if (mon->mon_type == OVSDB_UPDATE_NEW) { - /* Only configure VIF if associated Radio has - * been configured first because Radio_State has - * to exist so that vif_states reference can be - * updated. - * - * Moreover currently libtarget may not be able - * to tell which radio newly created vif - * interface should descend from. - * - * Therefore config must be deferred until after - * there's a Radio_Config entry that contains - * this VIF_Config entry's uuid in vif_config. - */ - radio_conf_row = wm2_radio_find_Radio_Config_by_vif_config(vconf->_uuid.uuid); - if (!radio_conf_row || radio_conf_row->user_flags != WM2_FLAG_RADIO_CONFIGURED) { - LOGW("Skip configuring VIF %s (Radio not %s)", - vconf->if_name, - radio_conf_row ? "configured" : "found"); - row->user_flags = WM2_FLAG_VIF_POSTPONED; - return; - } - } - - // configure - switch (mon->mon_type) { - default: - case OVSDB_UPDATE_ERROR: - LOGW("VIF config: mon upd error: %d", mon->mon_type); - return; - - case OVSDB_UPDATE_DEL: - /* The schema contains value before delete, therefore - disable the interfaces status */ - vconf->enabled = false; - vconf->enabled_exists = true; - vconf->mac_list_len = 0; - // falls through - - case OVSDB_UPDATE_NEW: - case OVSDB_UPDATE_MODIFY: - - memset(&vconf_set, 0, sizeof(vconf_set)); - STRSCPY(vconf_set.if_name, vconf->if_name); - if (!wm2_vif_equal(mon, vconf, &vconf_set)){ - LOGD("Configuring VIF %s through %s", vconf->if_name, - ovsdb_update_type_to_str(mon->mon_type)); - ret = target_vif_config_set(vconf->if_name, &vconf_set); - if (true != ret) { - return; - } - LOGN("Configured VIF %s ssid %s status %s", - vconf->if_name, - vconf->ssid, - vconf->enabled ? "enabled":"disabled"); - } - else { - LOGN("Configuring VIF %s (skipped)", vconf->if_name); - } - - if (mon->mon_type == OVSDB_UPDATE_NEW) { - // register callback for external (non-ovsdb) VIF config update - ret = target_vif_config_register(vconf->if_name, wm2_vif_config_update_cb); - if (true != ret) { - LOGE("Updating VIF %s (Failed to register callback)", vconf->if_name); - return; - } - } - break; - } - - // update status - switch (mon->mon_type) { - case OVSDB_UPDATE_DEL: - { - // can't select on vconf._uuid because reference to - // it was already removed by ovsdb automatically - ovsdb_table_delete_simple(&table_Wifi_VIF_State, - SCHEMA_COLUMN(Wifi_VIF_State, if_name), - vconf->if_name); - - wm2_radio_update_port_state(vconf->if_name); - - // delete_with_parent for Radio_State.vif_states - // is not necessary because ovsdb removes - // references automatically upon their deletion. - LOGD("Removed VIF %s to state", vconf->if_name); - } - break; - case OVSDB_UPDATE_NEW: - { - if (!radio_conf_row) { - LOGE("Skipping VIF %s state update (radio conf row is NULL)", vconf->if_name); - return; - } - - memset(&vstate, 0, sizeof(vstate)); - ret = target_vif_state_get(vconf->if_name, &vstate); - if (true != ret) { - LOGE("Updating VIF %s (Failed to fetch state data)", vconf->if_name); - return; - } - - struct schema_Wifi_Radio_Config *radio_conf = (void*)radio_conf_row->record; - // upsert to ovsdb and insert reference into Radio_State.vif_states - STRSCPY(vstate.vif_config.uuid, vconf->_uuid.uuid); - vstate.vif_config_exists = true; - char *filter[] = { "-", SCHEMA_COLUMN(Wifi_VIF_State, associated_clients), NULL }; - json_t *parent_where = ovsdb_where_uuid( - SCHEMA_COLUMN(Wifi_Radio_State, radio_config), - radio_conf->_uuid.uuid); - ret = ovsdb_table_upsert_with_parent( - &table_Wifi_VIF_State, - &vstate, - false, // uuid not needed - filter, - // parent: - SCHEMA_TABLE(Wifi_Radio_State), - parent_where, - SCHEMA_COLUMN(Wifi_Radio_State, vif_states)); - if (true != ret) { - LOGE("Updating VIF %s (Failed to insert state)", vstate.if_name); - return; - } - - LOGD("Added VIF %s to state", vstate.if_name); - - // Set associated clients once VIF state is set up - wm2_clients_init(vconf->if_name); - - ret = target_vif_state_register(vconf->if_name, wm2_radio_vif_state_update_cb); - if (true != ret) { - LOGE("Updating VIF %s (Failed to register state data)", vconf->if_name); - return; - } - - wm2_radio_update_port_state(vconf->if_name); - - // mark VIF configured - row->user_flags = WM2_FLAG_VIF_CONFIGURED; - } - break; - case OVSDB_UPDATE_MODIFY: - { - // state is updated by registered callbacks - // LOGD("Updated VIF %s to state", vconf->if_name); - wm2_radio_update_port_state(vconf->if_name); - } - break; - default: - return; - } -} - -void wm2_radio_config_init_v1() -{ - bool ret; - ds_dlist_t init_cfg; - target_radio_cfg_t *radio; - target_vif_cfg_t *vif; - - /* Update state at init */ - struct schema_Wifi_Radio_State rstate; - struct schema_Wifi_VIF_State vstate; - - if (!target_radio_config_init(&init_cfg)) { - LOGW("Initializing radios/vifs config (not found)"); - return; - } - - ds_dlist_foreach(&init_cfg, radio) { - /* Add device config to Wifi_Radio_Config */ - char *rconf_filter[] = { "-", SCHEMA_COLUMN(Wifi_Radio_Config, vif_configs), NULL }; - ret = ovsdb_table_upsert_f(&table_Wifi_Radio_Config, &radio->rconf, false, rconf_filter); - if (true != ret) { - continue; - } - - LOGD("Added %s radio %s to config", - radio->rconf.freq_band, - radio->rconf.if_name); - - /* Add device config to Wifi_Radio_State */ - memset(&rstate, 0, sizeof(rstate)); - ret = target_radio_state_get(radio->rconf.if_name, &rstate); - if (true != ret) { - LOGE("Initializing %s radio %s (Failed to fetch state data)", - radio->rconf.freq_band, - radio->rconf.if_name); - continue; - } - - char *rstate_filter[] = { "-", SCHEMA_COLUMN(Wifi_Radio_State, vif_states), NULL }; - ret = ovsdb_table_upsert_f(&table_Wifi_Radio_State, &rstate, false, rstate_filter); - if (true != ret) { - LOGE("Initializing %s radio %s (Failed to insert state)", - rstate.freq_band, - rstate.if_name); - return; - } - LOGD("Added %s radio %s to state", - rstate.freq_band, - rstate.if_name); - - ds_dlist_foreach(&radio->vifs_cfg, vif) { - /* Add device vif config to Wifi_VIF_Config */ - ret = ovsdb_table_upsert_with_parent(&table_Wifi_VIF_Config, - &vif->vconf, false, NULL, - SCHEMA_TABLE(Wifi_Radio_Config), - ovsdb_where_simple( - SCHEMA_COLUMN(Wifi_Radio_Config, if_name), radio->rconf.if_name), - SCHEMA_COLUMN(Wifi_Radio_Config, vif_configs)); - if (true != ret) { - continue; - } - - LOGD("Added VIF %s to config", - vif->vconf.if_name); - - memset(&vstate, 0, sizeof(vstate)); - ret = target_vif_state_get(vif->vconf.if_name, &vstate); - if (true != ret) { - LOGE("Initializing VIF %s (Failed to fetch state data)", vif->vconf.if_name); - return; - } - ret = ovsdb_table_upsert_with_parent(&table_Wifi_VIF_State, - &vstate, false, NULL, - SCHEMA_TABLE(Wifi_Radio_State), - ovsdb_where_simple( - SCHEMA_COLUMN(Wifi_Radio_State, if_name), rstate.if_name), - SCHEMA_COLUMN(Wifi_Radio_State, vif_states)); - if (true != ret) { - continue; - } - - LOGD("Added VIF %s to state", vstate.if_name); - } - } - - wm2_radio_init_clear(&init_cfg); - - return; -} - diff --git a/src/wm2/tests/unit.mk b/src/wm2/tests/unit.mk index e98529d0..54f77df3 100644 --- a/src/wm2/tests/unit.mk +++ b/src/wm2/tests/unit.mk @@ -26,7 +26,6 @@ UNIT_TYPE := TEST_BIN UNIT_NAME := test_wm2 UNIT_SRC := test.c UNIT_SRC += ../src/wm2_radio.c -UNIT_SRC += ../src/wm2_radio1.c UNIT_SRC += ../src/wm2_clients.c UNIT_CFLAGS += -I$(UNIT_PATH)/../src/ UNIT_DEPS := src/lib/common diff --git a/src/wm2/unit.mk b/src/wm2/unit.mk index 2b882b1c..1f432206 100644 --- a/src/wm2/unit.mk +++ b/src/wm2/unit.mk @@ -36,7 +36,6 @@ UNIT_TYPE := BIN UNIT_SRC := src/wm2_main.c UNIT_SRC += src/wm2_radio.c -UNIT_SRC += src/wm2_radio1.c UNIT_SRC += src/wm2_clients.c UNIT_CFLAGS += -I$(TOP_DIR)/src/lib/common/inc/