ped_services.c

Go to the documentation of this file.
00001 /*
00002  * This code is provided as is by Juniper Networks SDK Developer Support.
00003  * It is provided with no warranties or guarantees, and Juniper Networks
00004  * will not provide support or maintenance of this code in any fashion.
00005  * The code is provided only to help a developer better understand how
00006  * the SDK can be used.
00007  *
00008  * $Id: ped_services.c 366303 2010-03-05 13:14:01Z taoliu $
00009  *
00010  * Copyright (c) 2007-2008, Juniper Networks, Inc.
00011  * All rights reserved.
00012  */
00013 
00022 #include <sync/common.h>
00023 #include <sync/psd_ipc.h>
00024 #include "ped_config.h"
00025 #include "ped_services.h"
00026 #include "ped_schedule.h"
00027 #include "ped_logging.h"
00028 #include "ped_ssd.h"
00029 #include "ped_kcom.h"
00030 #include "ped_policy_table.h"
00031 #include "ped_ssd.h"
00032 #include "ped_snmp.h"
00033 #include "ped_script.h"
00034 
00035 #include PE_OUT_H
00036 #include PE_SEQUENCE_H
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 
00058 #define BUFFER_SIZE         1024
00059 
00060 
00061 /*** Data Structures ***/
00062 
00063 static int psd_sock = -1;                   
00064 static ipc_pipe_t * psd_pipe = NULL;        
00065 static evFileID psd_read_id;                
00066 static boolean psd_hb = FALSE;              
00067 static boolean psd_conn = FALSE;            
00068 static boolean need_policy_update = FALSE;  
00069 static struct timespec psd_conn_time;       
00070 extern evContext ped_ctx;                   
00071 
00072 
00073 /*** STATIC/INTERNAL Functions ***/
00074 
00075 
00089 static void
00090 send_psd_req(msg_type_e req_type, char * ifname, uint8_t af)
00091 {
00092     ipc_msg_t req;
00093     policy_req_msg_t req_data;
00094 
00095     // Check connection.
00096     if(!psd_pipe) {
00097         ERRMSG(PED, TRACE_LOG_ERR,
00098                 "%s: No pipe!", __func__);
00099         return;
00100     }
00101 
00102     bzero(&req, sizeof(ipc_msg_t));
00103     req.type = IPC_MSG_TYPE_PSD;  // we're talking with the  PSD
00104     req.subtype = req_type;
00105     req.opcode = 0;                   // unused
00106     req.error = 0;
00107 
00108     switch(req_type) {
00109         
00110         case MSG_HB:
00111         
00112             junos_trace(PED_TRACEFLAG_NORMAL,
00113                     "%s: Sending request MSG_HB to psd.", __func__); 
00114             req.length = 0;
00115             break;
00116             
00117         case MSG_POLICY_REQ:
00118         
00119             junos_trace(PED_TRACEFLAG_NORMAL,
00120                     "%s: Sending request MSG_POLICY_REQ to psd.", __func__);
00121         
00122             // ifname should have already been checked
00123             strcpy(req_data.ifname, ifname);
00124             req_data.af = af;
00125             req.length = sizeof(policy_req_msg_t);
00126             
00127             junos_trace(PED_TRACEFLAG_NORMAL,
00128                     "%s: Sending policy request for ifname=%s family=%d.",
00129                     __func__, ifname, af);  
00130             break;
00131             
00132         case MSG_UPDATE_DONE:
00133         
00134             junos_trace(PED_TRACEFLAG_NORMAL,
00135                     "%s: Sending request MSG_UPDATE_DONE to psd.",
00136                     __func__);
00137                     
00138             req.length = 0;
00139             break;
00140             
00141         default:
00142         
00143             ERRMSG(PED, TRACE_LOG_ERR,
00144                     "%s: Unknown request type %d.", __func__, req_type);
00145             return;
00146     }
00147 
00148     // write the message to the pipe
00149     if(ipc_msg_write(psd_pipe, &req, &req_data) != SUCCESS) {
00150         ERRMSG(PED, TRACE_LOG_ERR,
00151                 "%s: Write message FAILED!", __func__);
00152     } else if(ipc_pipe_write(psd_pipe, 0) != SUCCESS) {
00153         // write out everything in the pipe (send the message)
00154         ERRMSG(PED, TRACE_LOG_ERR,
00155                 "%s: Write pipe FAILED!", __func__);
00156     }
00157     
00158     ipc_pipe_write_clean(psd_pipe);
00159 }
00160 
00161 
00165 static void
00166 psd_ipc_read(evContext ctx __unused, void *param __unused,
00167               int fd __unused, int evmask __unused)
00168 {
00169     static boolean dont_clean = FALSE;
00170     ipc_msg_t *reply;
00171     policy_req_msg_t *req;
00172 
00173     if(ipc_pipe_read(psd_pipe) < 0) { // different errno
00174         
00175         /*
00176          * When errno is EAGAIN don't shutdown the connection.
00177          * EAGAIN is received when only partial msg is read.
00178          * So bail out and try later.
00179          */
00180         if(errno == EAGAIN || errno == EINTR) //ignore
00181             return;
00182             
00183         if(errno != 0) { // problem
00184             ERRMSG(PED, TRACE_LOG_ERR,
00185                 "%s: Null ipc read causing connection shutdown due to: %m",
00186                 __func__);
00187 
00188             // if cannot read anything, shutdown the connection
00189             disconnect_psd();
00190         } else {
00191             ERRMSG(PED, TRACE_LOG_ERR,
00192                 "%s: Remote side of pipe was closed!", __func__);
00193             ipc_pipe_read_clean(psd_pipe);
00194             disconnect_psd();
00195         }
00196         return;
00197     }
00198     
00199     // get the message back out of the pipe
00200     while((reply = ipc_msg_read(psd_pipe)) != NULL) {
00201 
00202         // Examine at the reply message:
00203         // if we got a null message, then complain 
00204         if(reply->type == 0 && reply->subtype == 0 && reply->length == 0 &&
00205                 reply->opcode == 0 && reply->error == 0) {
00206 
00207             ERRMSG(PED, TRACE_LOG_ERR,
00208                     "%s: Null message!", __func__);
00209 
00210             ipc_pipe_read_clean(psd_pipe);
00211             return;
00212         }
00213 
00214         // sanity checks: we complain, but still handle the message
00215         INSIST(reply->type == IPC_MSG_TYPE_PSD); 
00216 
00217         switch(reply->subtype) {
00218             
00219             case MSG_POLICY_NA: // no match on policy server
00220                 
00221                 req = (policy_req_msg_t *)reply->data; //psd echo'd request
00222                 junos_trace(PED_TRACEFLAG_NORMAL,
00223                         "%s: Got Message, no policy for %s.",
00224                         __func__, req->ifname);
00225                 // clear the policy or create an empty one 
00226                 policy_table_clear_policy(req->ifname, req->af);
00227                 break;
00228                 
00229             case MSG_ROUTE:
00230                 
00231                 INSIST(reply->length == sizeof(policy_route_msg_t));
00232                 junos_trace(PED_TRACEFLAG_NORMAL,
00233                         "%s: Got Message, route.", __func__);
00234                 policy_table_add_route((policy_route_msg_t *)(reply->data));
00235                 break;
00236                 
00237             case MSG_FILTER:
00238                 
00239                 INSIST(reply->length == sizeof(policy_filter_msg_t));
00240                 junos_trace(PED_TRACEFLAG_NORMAL,
00241                         "%s: Got Message, filter.", __func__);
00242                 policy_table_add_filter((policy_filter_msg_t *)(reply->data));
00243                 break;
00244                 
00245             case MSG_HB:
00246                 
00247                 junos_trace(PED_TRACEFLAG_HB,
00248                         "%s: Got Message, heartbeat.", __func__);
00249                 
00250                 psd_hb = TRUE;
00251                 
00252                 if(!psd_conn) {
00253                     psd_conn = TRUE;
00254                     ped_notify_psd_state(psd_conn);
00255                 }
00256                 
00257                 if(!dont_clean) {
00258                     policy_table_clean();
00259                 }
00260                 
00261                 if(need_policy_update &&
00262                    get_ssd_ready() && get_ssd_idle() &&
00263                    policy_table_unverify_all()) {
00264 
00265                     // call update_interface on all interfaces w/ REFRESH
00266                     update_all_interfaces();
00267                     send_psd_req(MSG_UPDATE_DONE, NULL, 0);
00268                     // stop cleaning until we get MSG_UPDATE_DONE back 
00269                     dont_clean = TRUE;
00270                     need_policy_update = FALSE;
00271                 }
00272                 
00273                 break;
00274                 
00275             case MSG_UPDATE_DONE:
00276                 
00277                 junos_trace(PED_TRACEFLAG_NORMAL,
00278                         "%s: Got Message, update done.", __func__);
00279 
00280                 // should be the last thing we get back from the PSD after a
00281                 // whole update to all policies (because we sent this echo 
00282                 // request last)
00283                 
00284                 dont_clean = FALSE; // resume cleaning
00285                 policy_table_clean();
00286                 
00287                 break;
00288                 
00289             case MSG_POLICY_UPDATE:
00290                 
00291                 junos_trace(PED_TRACEFLAG_NORMAL,
00292                         "%s: Message, update all interfaces.", __func__);
00293                 
00294                 // we need to update all policies because of changes on server 
00295                 need_policy_update = TRUE; // will do this upon receiving HB
00296 
00297                 break;
00298                 
00299             default:
00300                 
00301                 ERRMSG(PED, TRACE_LOG_ERR,
00302                         "%s: Unknown message from policy server!", __func__);
00303                 break;
00304         }
00305     }
00306     ipc_pipe_read_clean(psd_pipe);
00307 }
00308 
00309 
00316 static boolean
00317 connect_psd(void)
00318 {
00319     struct sockaddr_in saddr;
00320 
00321     // options
00322     const int sndbuf = BUFFER_SIZE;           // send buffer
00323     const int on = 1;                         // to turn an option on
00324 
00325     if(psd_sock > -1) // socket and connection already exists
00326         return TRUE;
00327 
00328     junos_trace(PED_TRACEFLAG_NORMAL,
00329             "%s: Connecting to psd...", __func__);
00330 
00331     psd_sock = socket(AF_INET, SOCK_STREAM, 0);
00332     INSIST(psd_sock >= 0);
00333 
00334     /*
00335      * Set some socket options
00336      *  ... if any fail we should eventually call disconnect_psd()
00337      */
00338     if(setsockopt(psd_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) {
00339         close(psd_sock);
00340         ERRMSG(PED, TRACE_LOG_ERR,
00341                 "%s: setsockopt SO_REUSEADDR FAILED!", __func__);
00342         return FALSE;
00343     }
00344     if(setsockopt(psd_sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
00345         close(psd_sock);
00346         ERRMSG(PED, TRACE_LOG_ERR,
00347                 "%s: setsockopt SO_SNDBUF FAILED!", __func__);
00348         return FALSE;
00349     }
00350     if(vrf_setsocketbyvrfname(psd_sock, JUNOS_SDK_IRS_TABLE_NAME, NULL)) {
00351         close(psd_sock);
00352         ERRMSG(PED, TRACE_LOG_ERR,
00353                 "%s: Set socket to VRF FAILED!", __func__);
00354         return FALSE;
00355     }
00356 
00357     bzero(&saddr, sizeof(saddr));
00358     saddr.sin_family = AF_INET;
00359     saddr.sin_port = htons(PSD_PORT_NUM);
00360     saddr.sin_len = sizeof(saddr);
00361     saddr.sin_addr.s_addr = INADDR_ANY;
00362 
00363     // set IP address
00364     if(!inet_aton(PSD_CONNECT_ADDRESS, &(saddr.sin_addr)) ||
00365             !(saddr.sin_addr.s_addr)) {
00366 
00367         saddr.sin_addr.s_addr = INADDR_ANY;
00368         // won't work to connect, but at least it's valid
00369         
00370         ERRMSG(PED, TRACE_LOG_ERR,
00371                 "%s: Set address %s FAILED! Default 0.0.0.0", __func__,
00372                 PSD_CONNECT_ADDRESS);
00373     }
00374 
00375     // try to connect
00376     if(connect(psd_sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
00377         ERRMSG(PED, TRACE_LOG_ERR,
00378                 "%s: Connect to PSD FAILED!", __func__);
00379         disconnect_psd();
00380         return FALSE;
00381     }
00382 
00383     psd_pipe = ipc_pipe_create(BUFFER_SIZE);
00384     if(psd_pipe == NULL) {
00385         ERRMSG(PED, TRACE_LOG_ERR,
00386                 "%s: Create pipe FAILED!", __func__);
00387         disconnect_psd();
00388         return FALSE;
00389     }
00390     
00391     if(ipc_pipe_attach_socket(psd_pipe, psd_sock) < 0) {
00392         ERRMSG(PED, TRACE_LOG_ERR,
00393                 "%s: Attach pipe to socket FAILED!", __func__);
00394         disconnect_psd();
00395         return FALSE;
00396     }
00397     
00398     evInitID(&psd_read_id);
00399     
00400     if(evSelectFD(ped_ctx, psd_sock, EV_READ, psd_ipc_read, 
00401             NULL, &psd_read_id) < 0) {
00402         ERRMSG(PED, TRACE_LOG_ERR,
00403                 "%s: evSelectFD FAILED!", __func__);
00404         disconnect_psd();
00405         return FALSE;
00406     }
00407     
00408     need_policy_update = TRUE;
00409 
00410     junos_trace(PED_TRACEFLAG_NORMAL, "%s: Connected to psd", __func__);
00411     clock_gettime(CLOCK_REALTIME, &psd_conn_time);
00412     return TRUE;
00413 }
00414 
00415 
00416 /*** GLOBAL/EXTERNAL Functions ***/
00417 
00418 
00437 void
00438 update_interface(char * ifname, uint32_t unit, uint8_t af, interface_op_e op)
00439 {
00440     char full_ifname[MAX_IF_NAME_LEN + 1]; 
00441 
00442     INSIST(strlen(ifname) <= MAX_IF_NAME_LEN - 6); // upto 5 digits & a dot too
00443     INSIST(unit < 100000); // only have space for 5 digits in string
00444     
00445     sprintf(full_ifname, "%s.%d", ifname, unit);
00446     
00447     // does this interface match a condition? (is it valid?)
00448     if(find_matching_condition(full_ifname, af)) {
00449         
00450         junos_trace(PED_TRACEFLAG_NORMAL, 
00451                 "%s: Match %s, op %d", __func__, full_ifname, op);
00452 
00453         switch(op) {
00454             case INTERFACE_ADD:
00455             case INTERFACE_REFRESH:
00456                 send_psd_req(MSG_POLICY_REQ, full_ifname, af); // get policy
00457                 break;
00458                 
00459             case INTERFACE_DELETE:
00460                 policy_table_delete_policy(full_ifname, af, TRUE);
00461                 break;
00462                 
00463             default:
00464                 ERRMSG(PED, TRACE_LOG_ERR, "%s: Unknown operation %d.",
00465                     __func__, op);
00466                 return;
00467         }
00468     } else { // didn't match a condition
00469         if(op == INTERFACE_DELETE) {
00470             policy_table_delete_policy(full_ifname, af, TRUE);
00471         } else {
00472             policy_table_delete_policy(full_ifname, af, FALSE);
00473         }
00474     }
00475 }
00476 
00477 
00486 boolean
00487 check_psd_hb(void)
00488 {
00489     if(psd_hb) {
00490         junos_trace(PED_TRACEFLAG_HB, "%s: Connection is alive.", __func__);
00491         psd_hb = FALSE;
00492     } else {
00493         junos_trace(PED_TRACEFLAG_NORMAL, "%s: Connection is down, reconnect.",
00494             __func__);
00495         disconnect_psd();
00496         if(!connect_psd()) {
00497             return FALSE; // if connect fails no point in sending
00498         }
00499     }
00500     
00501     junos_trace(PED_TRACEFLAG_HB, "%s: Send message to PSD, heartbeat.",
00502         __func__);
00503     
00504     send_psd_req(MSG_HB, NULL, 0);
00505     
00506     return TRUE;
00507 }
00508 
00509 
00513 void
00514 update_policies(void)
00515 {
00516     need_policy_update = TRUE;
00517 }
00518 
00519 
00526 void
00527 disconnect_psd(void)
00528 {
00529     junos_trace(PED_TRACEFLAG_NORMAL, "%s", __func__);
00530 
00531     // Deattach event handler.
00532 
00533     // if select failed then don't deselect
00534     if(evTestID(psd_read_id)) {
00535         if(evDeselectFD(ped_ctx, psd_read_id) < 0) {  // Detach event.
00536             ERRMSG(PSD_LOG_TAG, TRACE_LOG_ERR,
00537                 "%s: evDeselect FAILED!", __func__);
00538         }
00539         evInitID(&psd_read_id); // need to call this after deselecting
00540     }
00541 
00542     // Clear attached pipe
00543     if(psd_pipe != NULL) {
00544         ipc_pipe_detach_socket(psd_pipe, psd_sock);
00545         ipc_pipe_destroy(psd_pipe);
00546         psd_pipe = NULL;
00547     }
00548 
00549     // Clear socket
00550     if(psd_sock != -1) {
00551         close(psd_sock);
00552         psd_sock = -1;
00553     }
00554 
00555     psd_hb = FALSE;
00556     if(psd_conn == TRUE) {
00557         psd_conn = FALSE;
00558         ped_notify_psd_state(psd_conn);
00559     }
00560 
00561     // Need to update all policies when we reconnect to PSD.
00562     need_policy_update = TRUE;
00563 }
00564 
00565 
00572 boolean
00573 psd_conn_state(void)
00574 {
00575     return psd_conn;
00576 }
00577 
00578 
00586 int
00587 get_psd_conn_time(void)
00588 {
00589     struct timespec psd_time;
00590 
00591     clock_gettime(CLOCK_REALTIME, &psd_time);
00592 
00593     junos_trace(PED_TRACEFLAG_NORMAL, "%s: cur: %d, start %d",
00594             __func__, psd_time.tv_sec, psd_conn_time.tv_sec);
00595     return(psd_time.tv_sec - psd_conn_time.tv_sec);
00596 }

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:06 2010 for SDK Your Net Corporation Policy Manager Example: Policy Enforcement Daemon 1.0 by Doxygen 1.5.1