pfd_conn.c

Go to the documentation of this file.
00001 /*
00002  * $Id: pfd_conn.c 346460 2009-11-14 05:06:47Z ssiano $
00003  *
00004  * This code is provided as is by Juniper Networks SDK Developer Support.
00005  * It is provided with no warranties or guarantees, and Juniper Networks
00006  * will not provide support or maintenance of this code in any fashion.
00007  * The code is provided only to help a developer better understand how
00008  * the SDK can be used.
00009  *
00010  * Copyright (c) 2007-2008, Juniper Networks, Inc.
00011  * All rights reserved.
00012  */
00013 
00022 #include <string.h>
00023 #include <pthread.h>
00024 #include <jnx/aux_types.h>
00025 #include <jnx/trace.h>
00026 #include <netinet/in.h>
00027 #include <arpa/inet.h>
00028 #include <jnx/pconn.h>
00029 #include <sync/policy_ipc.h>
00030 #include "pfd_conn.h"
00031 #include "pfd_kcom.h"
00032 #include "pfd_packet.h"
00033 #include "pfd_main.h"
00034 #include "pfd_logging.h"
00035 #include "pfd_config.h"
00036 
00037 
00038 /*** Constants ***/
00039 
00043 #ifndef evInitID
00044 #define evInitID(id) ((id)->opaque = NULL)
00045 #endif
00046 
00050 #ifndef evTestID
00051 #define evTestID(id) ((id).opaque != NULL)
00052 #endif
00053 
00054 
00055 #define PED_CLIENT_CONNECT_RETRIES    1  
00056 #define CPD_CLIENT_CONNECT_RETRIES    1  
00057 
00058 
00061 #define RETRY_CONNECT 60
00062 
00063 /*** Data Structures ***/
00064 
00065 boolean            cpd_ready;     
00066 
00067 static pconn_client_t     * ped_client;  
00068 static pconn_client_t     * cpd_client;  
00069 
00070 
00071 static evTimerID  ped_timer_id;    
00072 static evTimerID  cpd_timer_id;    
00073 
00074 static pconn_peer_info_t cpd_info; 
00075 static evContext         main_ctx; 
00076 
00077 
00081 extern thread_message_t update_messages[MAX_CPUS];
00082 
00083 
00084 /*** STATIC/INTERNAL Functions ***/
00085 
00086 
00092 static void connect_ped(evContext ctx, void * uap,
00093     struct timespec due, struct timespec inter);
00094 
00098 static void connect_cpd(evContext ctx, void * uap,
00099     struct timespec due, struct timespec inter);
00100 
00101 
00114 static void
00115 cpd_client_connection(pconn_client_t * session,
00116                       pconn_event_t event,
00117                       void * cookie UNUSED)
00118 {
00119     int rc;
00120 
00121     INSIST_ERR(session == cpd_client);
00122 
00123     switch (event) {
00124 
00125         case PCONN_EVENT_ESTABLISHED:
00126             
00127             // clear the retry timer
00128             if(evTestID(cpd_timer_id)) {
00129                 evClearTimer(main_ctx, cpd_timer_id);
00130                 evInitID(&cpd_timer_id);
00131             }            
00132         
00133             rc = pconn_client_send(cpd_client, MSG_GET_AUTH_LIST, NULL, 0);
00134             if(rc != PCONN_OK) {
00135                 LOG(LOG_ERR, "%s: Failed to send MSG_GET_AUTH_LIST to the CPD."
00136                     " Error: %d", __func__, rc);
00137                 break;
00138             }
00139             
00140             cpd_ready = TRUE;
00141             if(get_cpd_address() && get_pfd_address() && vrf_ready) {
00142                 init_packet_loops();
00143             }
00144 
00145             break;
00146 
00147         case PCONN_EVENT_SHUTDOWN:
00148 
00149             cpd_client = NULL;
00150             cpd_ready = FALSE;
00151             clear_config();
00152             
00153             // Reconnect to the CPD if timer not going
00154             if(!evTestID(cpd_timer_id) &&
00155                evSetTimer(main_ctx, connect_cpd, NULL,
00156                    evNowTime(), evConsTime(RETRY_CONNECT, 0), &cpd_timer_id)) {
00157                 
00158                 LOG(LOG_ALERT, "%s: Failed to initialize a connect timer to "
00159                     "connect to the CPD", __func__);
00160                 pfd_shutdown();
00161             }
00162             
00163             break;
00164 
00165         default:
00166             LOG(LOG_ERR, "%s: Received an unknown or PCONN_EVENT_FAILED event",
00167                  __func__);
00168             
00169             cpd_client = NULL;
00170             cpd_ready = FALSE;
00171             clear_config();
00172             
00173             // Reconnect to the CPD if timer not going
00174             if(!evTestID(cpd_timer_id) &&
00175                evSetTimer(main_ctx, connect_cpd, NULL,
00176                    evNowTime(), evConsTime(RETRY_CONNECT, 0), &cpd_timer_id)) {
00177                 
00178                 LOG(LOG_ALERT, "%s: Failed to initialize a connect timer to "
00179                     "connect to the CPD", __func__);
00180                 pfd_shutdown();
00181             }
00182             
00183             break;
00184     }
00185 }
00186 
00187 
00204 static status_t
00205 cpd_client_message(pconn_client_t * session,
00206                    ipc_msg_t * msg,
00207                    void * cookie UNUSED)
00208 {
00209     INSIST_ERR(session == cpd_client);
00210     INSIST_ERR(msg != NULL);
00211 
00212     switch(msg->subtype) {
00213         
00214         case MSG_AUTH_ENTRY_ADD:
00215         
00216             INSIST_ERR(msg->length == sizeof(in_addr_t));
00217             
00218             // Don't put it in host byte-order form
00219             add_auth_user_addr(*(in_addr_t *)msg->data);
00220             
00221             break;
00222 
00223         case MSG_AUTH_ENTRY_DEL:
00224             
00225             INSIST_ERR(msg->length == sizeof(in_addr_t));
00226             
00227             // Don't put it in host byte-order form
00228             delete_auth_user_addr(*(in_addr_t *)msg->data);            
00229             
00230             break;
00231             
00232         default:
00233         
00234             LOG(LOG_ERR, "%s: Received an unknown message type (%d) from the "
00235                 "CPD", __func__, msg->subtype);
00236             return EFAIL;
00237     }
00238     
00239     return SUCCESS;
00240 }
00241 
00242 
00255 static void
00256 ped_client_connection(pconn_client_t * session,
00257                       pconn_event_t event,
00258                       void * cookie UNUSED)
00259 {
00260     int rc;
00261     component_id_e id;
00262 
00263     INSIST_ERR(session == ped_client);
00264 
00265     switch (event) {
00266 
00267         case PCONN_EVENT_ESTABLISHED:
00268             
00269             // clear the retry timer
00270             if(evTestID(ped_timer_id)) {
00271                 evClearTimer(main_ctx, ped_timer_id);
00272                 evInitID(&ped_timer_id);
00273             }
00274             
00275             id = htonl(ID_PFD);
00276             
00277             rc = pconn_client_send(ped_client, MSG_ID, &id, sizeof(id));
00278             if(rc != PCONN_OK) {
00279                 LOG(LOG_ERR, "%s: Failed to send MSG_ID to the PED. Error: %d",
00280                     __func__, rc);
00281                 break;
00282             }
00283             
00284             break;
00285 
00286         case PCONN_EVENT_SHUTDOWN:
00287             
00288             ped_client = NULL; // connection will be closed
00289             
00290             // Reconnect to the PED if timer not going
00291             if(!evTestID(ped_timer_id) &&
00292                evSetTimer(main_ctx, connect_ped, NULL, evNowTime(),
00293                    evConsTime(RETRY_CONNECT, 0), &ped_timer_id)) {
00294 
00295                 LOG(LOG_ERR, "%s: Failed to initialize a re-connect timer to "
00296                     "reconnect to the PED", __func__);
00297                 pfd_shutdown();
00298             }
00299             
00300             break;
00301 
00302         default:
00303             LOG(LOG_ERR, "%s: Received an unknown or PCONN_EVENT_FAILED event",
00304                  __func__);
00305             
00306             ped_client = NULL; // connection will be closed
00307             
00308             // Reconnect to the PED if timer not going
00309             if(!evTestID(ped_timer_id) &&
00310                evSetTimer(main_ctx, connect_ped, NULL, evNowTime(),
00311                    evConsTime(RETRY_CONNECT, 0), &ped_timer_id)) {
00312 
00313                 LOG(LOG_ERR, "%s: Failed to initialize a re-connect timer to "
00314                     "reconnect to the PED", __func__);
00315                 pfd_shutdown();
00316             }
00317             
00318             break;
00319     }
00320 }
00321 
00322 
00339 static status_t
00340 ped_client_message(pconn_client_t * session,
00341                    ipc_msg_t * msg,
00342                    void * cookie UNUSED)
00343 {
00344     pconn_peer_info_t * info;
00345     in_addr_t * addr;
00346     struct in_addr cpd_addr, pfd_addr;
00347     int i;
00348     
00349     INSIST_ERR(session == ped_client);
00350     INSIST_ERR(msg != NULL);
00351 
00352     switch(msg->subtype) {
00353         
00354         case MSG_ADDRESSES:
00355             
00356             INSIST_ERR(msg->length == sizeof(in_addr_t) * 2);
00357             addr = (in_addr_t *)msg->data;
00358             cpd_addr.s_addr = *addr;
00359             ++addr;
00360             pfd_addr.s_addr = *addr;
00361 
00362             LOG(LOG_INFO, "%s: Received PFD and CPD addresses.", __func__);
00363 
00364             LOG(LOG_INFO, "%s: CPD address: %s",
00365                 __func__, inet_ntoa(cpd_addr));
00366             
00367             LOG(LOG_INFO, "%s: PFD address: %s",
00368                 __func__, inet_ntoa(pfd_addr));
00369             
00370             set_cpd_address(cpd_addr.s_addr);
00371             set_pfd_address(pfd_addr.s_addr);
00372 
00373             // Tell all threads to load new CPD and PFD address
00374             
00375             for(i = 0; i < MAX_CPUS; ++i) {
00376                 pthread_mutex_lock(&update_messages[i].lock);
00377                 update_messages[i].update = TRUE;
00378                 update_messages[i].addresses.pfd_addr = pfd_addr.s_addr;
00379                 update_messages[i].addresses.cpd_addr = cpd_addr.s_addr;
00380                 pthread_mutex_unlock(&update_messages[i].lock);
00381             }
00382             
00383             if(cpd_ready && cpd_addr.s_addr && pfd_addr.s_addr && vrf_ready) {
00384                 init_packet_loops();
00385             }
00386 
00387             break;
00388         
00389         case MSG_PEER:
00390             
00391             INSIST_ERR(msg->length == sizeof(pconn_peer_info_t));
00392             info = (pconn_peer_info_t *)msg->data; // the CPD's peer info
00393             
00394             if(cpd_client == NULL) {
00395                 
00396                 // save this info
00397                 cpd_info.ppi_fpc_slot = ntohl(info->ppi_fpc_slot);
00398                 cpd_info.ppi_pic_slot = ntohl(info->ppi_pic_slot);
00399                 
00400                 // Connect to the CPD
00401                 if(evTestID(cpd_timer_id)) {
00402                     evClearTimer(main_ctx, cpd_timer_id);
00403                     evInitID(&cpd_timer_id);
00404                 }
00405                 
00406                 if(evSetTimer(main_ctx, connect_cpd, NULL,
00407                         evNowTime(), evConsTime(RETRY_CONNECT, 0),
00408                         &cpd_timer_id)) {
00409                     
00410                     LOG(LOG_ERR, "%s: Failed to initialize a connect timer to "
00411                         "connect to the CPD", __func__);
00412                     pfd_shutdown();
00413                 }
00414             } else if(cpd_info.ppi_fpc_slot != ntohl(info->ppi_fpc_slot) || 
00415                 cpd_info.ppi_pic_slot != ntohl(info->ppi_pic_slot)) {
00416 
00417                 /*
00418                  * Check that it's the same as where we're already connected
00419                  * this would only happen if the PED went down, but the CPD
00420                  * did not
00421                  * 
00422                  * ** Don't think this should happen in practise **
00423                  */
00424                 
00425                 LOG(LOG_WARNING, "%s: Connected to CPD on wrong PIC. "
00426                     "Reconnecting with info sent by the PED", __func__);
00427                 
00428                 pconn_client_close(cpd_client); // disconnect from CPD
00429                 cpd_client = NULL;
00430                 
00431                 // save this info
00432                 cpd_info.ppi_fpc_slot = ntohl(info->ppi_fpc_slot);
00433                 cpd_info.ppi_pic_slot = ntohl(info->ppi_pic_slot);
00434                 
00435                 // Reconnect to the CPD
00436                 if(evTestID(cpd_timer_id)) {
00437                     evClearTimer(main_ctx, cpd_timer_id);
00438                     evInitID(&cpd_timer_id);
00439                 }
00440                 
00441                 if(evSetTimer(main_ctx, connect_cpd, NULL,
00442                     evNowTime(), evConsTime(RETRY_CONNECT, 0), &cpd_timer_id)) {
00443                     
00444                     LOG(LOG_ERR, "%s: Failed to initialize a connect timer"
00445                         " to connect to the CPD", __func__);
00446                     pfd_shutdown();
00447                 }
00448             }
00449             // else we're already connected to the CPD correctly
00450             
00451             break;
00452         
00453         default:
00454             LOG(LOG_ERR, "%s: Received an unknown message type (%d) from the "
00455                 "PED", __func__, msg->subtype);
00456             return EFAIL;
00457     }
00458     
00459     return SUCCESS;
00460 }
00461 
00462 
00478 static void
00479 connect_cpd(evContext ctx,
00480             void * uap  UNUSED,
00481             struct timespec due UNUSED,
00482             struct timespec inter UNUSED)
00483 {
00484     pconn_client_params_t params;
00485     
00486     bzero(&params, sizeof(pconn_client_params_t));
00487     
00488     // setup the client args
00489     params.pconn_peer_info.ppi_peer_type = PCONN_PEER_TYPE_PIC;
00490     params.pconn_peer_info.ppi_fpc_slot = cpd_info.ppi_fpc_slot;
00491     params.pconn_peer_info.ppi_pic_slot = cpd_info.ppi_pic_slot;
00492     
00493     params.pconn_port          = CPD_PORT_NUM;
00494     params.pconn_num_retries   = CPD_CLIENT_CONNECT_RETRIES;
00495     params.pconn_event_handler = cpd_client_connection;
00496     
00497     if(cpd_client) {
00498         // Then this is the second time in a row this is called even though it
00499         // didn't fail. We haven't received an event like ESTABLISHED yet.
00500         pconn_client_close(cpd_client);
00501     }
00502     
00503     // connect
00504     cpd_client = pconn_client_connect_async(
00505                     &params, ctx, cpd_client_message, NULL);
00506     
00507     if(cpd_client == NULL) {
00508         LOG(LOG_ERR, "%s: Failed to initialize the pconn client "
00509             "connection to the CPD", __func__);
00510         return;
00511     }
00512 }
00513 
00514 
00530 static void
00531 connect_ped(evContext ctx,
00532             void * uap  UNUSED,
00533             struct timespec due UNUSED,
00534             struct timespec inter UNUSED)
00535 {
00536     pconn_client_params_t params;
00537     
00538     bzero(&params, sizeof(pconn_client_params_t));
00539     
00540     // setup the client args
00541     params.pconn_peer_info.ppi_peer_type = PCONN_PEER_TYPE_RE;
00542     params.pconn_port                    = PED_PORT_NUM;
00543     params.pconn_num_retries             = PED_CLIENT_CONNECT_RETRIES;
00544     params.pconn_event_handler           = ped_client_connection;
00545     
00546     if(ped_client) {
00547         // Then this is the second time in a row this is called even though it
00548         // didn't fail. We haven't received an event like ESTABLISHED yet.
00549         pconn_client_close(ped_client);
00550     }
00551     
00552     // connect
00553     ped_client = pconn_client_connect_async(
00554                     &params, ctx, ped_client_message, NULL);
00555     
00556     if(ped_client == NULL) {
00557         LOG(LOG_ERR, "%s: Failed to initialize the pconn client connection "
00558             "to the PED", __func__);
00559     }
00560 }
00561 
00562 
00563 /*** GLOBAL/EXTERNAL Functions ***/
00564 
00565 
00575 status_t
00576 init_connections(evContext ctx)
00577 {
00578     main_ctx = ctx;
00579     
00580     cpd_ready = FALSE;
00581     cpd_client = NULL;
00582     ped_client = NULL;
00583     
00584     evInitID(&ped_timer_id);
00585     
00586     // Connect to the PED
00587     if(evSetTimer(ctx, connect_ped, NULL, evNowTime(),
00588         evConsTime(RETRY_CONNECT, 0), &ped_timer_id)) {
00589 
00590         LOG(LOG_ERR, "%s: Failed to initialize a connect timer to connect "
00591             "to the PED", __func__);
00592         return EFAIL;
00593     }
00594 
00595     return SUCCESS;
00596 }
00597 
00598 
00602 void
00603 close_connections(void)
00604 {
00605     if(cpd_client) {
00606         pconn_client_close(cpd_client);
00607         cpd_client = NULL;
00608     }
00609 
00610     if(ped_client) {
00611         pconn_client_close(ped_client);
00612         ped_client = NULL;
00613     }
00614 }

2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:27:07 2010 for SDK Your Net Corporation Policy Manager Example: Packet Filtering Daemon (pfd) 1.0 by Doxygen 1.5.1