Open Ethernet Networking (OpEN) API Guide and Reference Manual  3.6.0.3
vlan_status_example.c
/*********************************************************************
*
* Copyright 2016-2018 Broadcom.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************
*
* @filename vlan_status_example.c
*
* @purpose VLAN Event Notification Example.
*
* @component OPEN
*
* @note
*
* @create 10/16/2012
*
* @end
*
**********************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include "rpcclt_openapi.h"
#include "proc_util.h"
#include "openapi_common.h"
typedef struct
{
uint32_t vlan_exists; /* This VLAN is created on the switch */
uint32_t staticVlan; /* VLAN is static: 1 = static, 0 = dynamic */
} vlan_entry_t;
/* Local copy of the interface table.
*/
vlan_entry_t *vlan_table;
/* Print the list of all VLANs created on the switch and whether each
** is static or dynamic.
** The information is obtained from the local database.
*/
void vlan_status_show ()
{
uint32_t i;
printf ("\n\nThe following VLAN IDs are in the switch's VLAN databas:\n");
for (i = 0; i < 4096; i++)
{
if (!vlan_table[i].vlan_exists)
{
continue;
}
printf ("VLAN: %d is %s\n", i, vlan_table[i].staticVlan ? "Static":"Dynamic");
}
}
/* Populate the local VLAN table when this application starts running.
*/
void vlan_table_create (openapiClientHandle_t *client)
{
openapiEventList_t open_event;
uint32_t vlan_num;
vlan_table = malloc(sizeof(vlan_entry_t) * 4096);
printf ("Created VLAN Table.\n");
/* Register with FASTPATH to receive VLAN-change events.
** The registration must be done before populating the VLAN table
** in order not to miss any VLAN change events.
*/
openapiEventListClear (&open_event);
openapiEventSet (&open_event, OPEN_EVENT_VLAN);
if (OPEN_E_NONE != openapiEventRegister(client, &open_event))
{
printf ("Failed to register for OPEN_EVENT_VLAN events.\n");
abort ();
}
/* Populate the VLAN table to match the current VLAN state. */
for (vlan_num = 0; vlan_num < 4096; vlan_num++)
{
if (openapiVlanCreatedCheck(client, vlan_num) == OPEN_E_NONE)
{
vlan_table[vlan_num].vlan_exists = 1;
vlan_table[vlan_num].staticVlan = openapiVlanIsStatic(client, vlan_num);
}
else
{
vlan_table[vlan_num].vlan_exists = 0;
vlan_table[vlan_num].staticVlan = 0;
}
}
/* VLAN 0 does not exist, so we won't miss any VLANs by calling NextGet on VLAN 0. */
vlan_num = 0;
while (openapiVlanNextGet(client, vlan_num, &vlan_num) == OPEN_E_NONE)
{
vlan_table[vlan_num].vlan_exists = 1;
vlan_table[vlan_num].staticVlan = openapiVlanIsStatic(client, vlan_num);
}
}
void vlan_table_validate(openapiClientHandle_t *client)
{
uint32_t vlan_num;
/* Check entries in the VLAN table. */
for (vlan_num = 0; vlan_num < 4096; vlan_num++)
{
if (!vlan_table[vlan_num].vlan_exists)
{
continue;
}
/*
* Repopulate the VLAN record. The VLAN could have been deleted and recreated
* with different characteristics.
*/
if (openapiVlanCreatedCheck(client, vlan_num) == OPEN_E_NONE)
{
vlan_table[vlan_num].staticVlan = openapiVlanIsStatic(client, vlan_num);
}
else
{
vlan_table[vlan_num].vlan_exists = 0;
vlan_table[vlan_num].staticVlan = 0;
}
}
}
/* Wait for VLAN events for specified duration.
*/
void vlan_table_monitor(openapiClientHandle_t *client, uint32_t monitor_duration)
{
struct timespec start_time, current_time;
openapiEventList_t change_pending_event, purge_event;
uint32_t vlan_num, delete_pending;
int notify_fd;
struct timeval tv;
fd_set rcv_set;
int rc;
char buf[1];
if (clock_gettime (CLOCK_MONOTONIC, &start_time))
{
perror("Can't get start time.\n");
abort ();
}
notify_fd = openapiClientNotifySocketFDGet(client);
if (notify_fd == 0)
{
perror("Invalid notify_fd retrieved.\n");
abort();
}
do
{
/* Wait for events. Time out every 5 seconds. */
FD_ZERO (&rcv_set);
FD_SET (notify_fd, &rcv_set);
tv.tv_sec = 5;
tv.tv_usec = 0;
rc = select(notify_fd + 1, &rcv_set, 0, 0, &tv);
/* If data is detected on the socket then drain the socket. */
if (rc > 0)
{
do
{
rc = recvfrom (notify_fd, buf, sizeof(buf), MSG_DONTWAIT, 0, 0);
} while ((rc >= 0) || (EINTR == errno));
if (OPEN_E_NONE == openapiPendingEventsGet(client, &change_pending_event, &purge_event))
{
/*
** Sometimes FASTPATH deletes entries from the table without
** telling the application. This can happen if the table gets full
** before the application has a chance to acknowledge
** the delete-pending events.
** If an applicaton gets a purge notification then it must
** check all of its entries to see if they are still valid.
*/
if (openapiEventIsSet (&purge_event, OPEN_EVENT_VLAN))
{
printf ("Got Purge event for OPEN_EVENT_VLAN\n");
vlan_table_validate (client);
}
/* Debug code to confirm that we got an interface table event.
*/
if (openapiEventIsSet (&change_pending_event, OPEN_EVENT_VLAN))
{
printf ("Got Change Pending event for OPEN_EVENT_VLAN\n");
}
}
/* Walk through the changed entries in the VLAN table and
** update the local database.
*/
vlan_num = 0;
while (OPEN_E_NONE == openapiVlanNextChangedGet(client, vlan_num, &vlan_num, &delete_pending))
{
if (delete_pending)
{
/* VLAN is pending for deletion. Remove it from the local database.*/
printf ("Deleting VLAN ID: %d\n", vlan_num);
vlan_table[vlan_num].vlan_exists = 0;
vlan_table[vlan_num].staticVlan = 0;
}
else
{
printf ("Change event received for VLAN ID: %d\n", vlan_num);
if (openapiVlanCreatedCheck(client, vlan_num) == OPEN_E_NONE)
{
vlan_table[vlan_num].vlan_exists = 1;
vlan_table[vlan_num].staticVlan = openapiVlanIsStatic(client, vlan_num);
}
else
{
vlan_table[vlan_num].vlan_exists = 0;
vlan_table[vlan_num].staticVlan = 0;
}
}
}
}
if (clock_gettime (CLOCK_MONOTONIC, &current_time))
{
perror ("Can't get current time.\n");
abort ();
}
} while ((current_time.tv_sec - start_time.tv_sec) < monitor_duration);
}
int main(int argc, char **argv)
{
openapiClientHandle_t clientHandle;
open_error_t result;
open_buffdesc switch_os_revision;
char switch_os_revision_string[100];
uint32_t monitor_duration = 60;
if ((argc != 1) && (argc != 2))
{
printf("Usage: %s [monitor-duration-seconds]\n", argv[0]);
exit(1);
}
if (argc == 2)
{
monitor_duration = atoi(argv[1]);
}
printf ("Monitoring VLAN Status for %d seconds.\n", monitor_duration);
l7proc_crashlog_register();
/* Register with OpEN */
if ((result = openapiClientRegister("vlan_status_example", &clientHandle)) != OPEN_E_NONE)
{
printf("\nFailed to initialize RPC to OpEN. Exiting (result = %d)\n", result);
exit(2);
}
/* RPC call can fail until server starts. Keep trying */
while (openapiConnectivityCheck(&clientHandle) != OPEN_E_NONE)
{
sleep(1);
}
L7PROC_LOGF(L7PROC_LOG_SEVERITY_INFO, 0, "Starting VLAN Status Monitor example application");
printf("\n");
switch_os_revision.pstart = switch_os_revision_string;
switch_os_revision.size = sizeof(switch_os_revision_string);
if (openapiNetworkOSVersionGet(&clientHandle, &switch_os_revision) == OPEN_E_NONE)
printf("Network OS version = %s\n", switch_os_revision_string);
else
printf("Network OS version retrieve error\n");
printf("\n");
vlan_table_create(&clientHandle);
vlan_status_show();
vlan_table_monitor(&clientHandle, monitor_duration);
vlan_status_show();
/* Log goodbye message with OPEN */
L7PROC_LOGF(L7PROC_LOG_SEVERITY_INFO, 0, "Stopping VLAN Status example application");
(void) openapiClientTearDown(&clientHandle);
return 0;
}