monitube2-mgmt_config.c

Go to the documentation of this file.
00001 /*
00002  * $Id: monitube2-mgmt_config.c 347265 2009-11-19 13:55:39Z kdickman $
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) 2009, Juniper Networks, Inc.
00011  * All rights reserved.
00012  */
00013 
00021 #include <sync/common.h>
00022 #include <ddl/dax.h>
00023 #include <jnx/pconn.h>
00024 #include <jnx/parse_interface.h>
00025 #include <jnx/patricia.h>
00026 #include <jnx/junos_kcom_pub_blob.h>
00027 #include <jnx/ssrb_parse.h>
00028 #include "monitube2-mgmt_config.h"
00029 #include "monitube2-mgmt_conn.h"
00030 #include "monitube2-mgmt_logging.h"
00031 
00032 #include MONITUBE2_OUT_H
00033 
00034 /*** Constants ***/
00035 
00036 #define MAX_FLOW_AGE 300  
00037 
00038 /*** Data Structures ***/
00039 
00040 static patroot   rules;               
00041 static patroot   ssets;               
00042 static patroot   flow_stats;          
00043 static rule_t *  current_rule = NULL; 
00044 static evContext m_ctx;               
00045 
00046 /*** STATIC/INTERNAL Functions ***/
00047 
00052 PATNODE_TO_STRUCT(ss_entry, ss_info_t, node)
00053 
00054 
00058 PATNODE_TO_STRUCT(rule_entry, rule_t, node)
00059 
00060 
00065 PATNODE_TO_STRUCT(address_entry, address_t, node)
00066 
00067 
00072 PATNODE_TO_STRUCT(fs_entry, flowstat_t, node)
00073 
00074 
00079 PATNODE_TO_STRUCT(fss_entry, flowstat_ss_t, node)
00080 
00081 
00088 static void
00089 delete_list(list_t * list)
00090 {
00091     list_item_t * item;
00092 
00093     while((item = TAILQ_FIRST(list)) != NULL) {
00094        TAILQ_REMOVE(list, item, entries);
00095        free(item);
00096     }
00097 }
00098 
00099 
00106 static void
00107 delete_serviceset(ss_info_t * ssi)
00108 {
00109     rule_t * rule;
00110     list_item_t * item, * item2;
00111     
00112     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
00113 
00114     if(!patricia_delete(&ssets, &ssi->node)) {
00115         LOG(LOG_ERR, "%s: Deleting sset failed", __func__);
00116         return;
00117     }
00118     
00119     if(evTestID(ssi->timer)) {
00120         evClearTimer(m_ctx, ssi->timer);
00121         evInitID(&ssi->timer);
00122     }
00123     
00124     notify_delete_serviceset(ssi->id, ssi->gen_num, ssi->svc_id,
00125                 ssi->fpc_slot, ssi->pic_slot);
00126     
00127     // Go through the all rules for this service set, and
00128     // for each rule remove the reference to this particular service set
00129     
00130     item = TAILQ_FIRST(&ssi->rules);
00131     while(item != NULL) {
00132         rule = (rule_t *)item->item;
00133         
00134         // find this particular service set reference in the rule
00135         item2 = TAILQ_FIRST(&rule->ssets);
00136         while(item2 != NULL) {
00137             if(item2->item == ssi) {
00138                 // found it, remove it
00139                 TAILQ_REMOVE(&rule->ssets, item2, entries);
00140                 free(item2);
00141                 break;
00142             }
00143             item2 = TAILQ_NEXT(item2, entries);
00144         }
00145         
00146         item = TAILQ_NEXT(item, entries);
00147     }
00148 
00149     delete_list(&ssi->rules);
00150 
00151     free(ssi);
00152 }
00153 
00154 
00158 static void
00159 delete_all_servicesets(void)
00160 {
00161     ss_info_t * ssi;
00162     rule_t * rule;
00163     list_item_t * item;
00164 
00165     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
00166     
00167     notify_delete_all_policy();
00168 
00169     while(NULL != (ssi = ss_entry(patricia_find_next(&ssets, NULL)))) {
00170         
00171         if(!patricia_delete(&ssets, &ssi->node)) {
00172             LOG(LOG_ERR, "%s: Deleting sset failed", __func__);
00173             continue;
00174         }
00175         
00176         // Go through the all rules for this service set, 
00177         // delete the entire rule's ssets list
00178         
00179         while((item = TAILQ_FIRST(&ssi->rules)) != NULL) {
00180             rule = (rule_t *)item->item;
00181             delete_list(&rule->ssets);
00182             TAILQ_REMOVE(&ssi->rules, item, entries);
00183             free(item);
00184         }
00185         free(ssi);
00186     }
00187 }
00188 
00189 
00202 static void
00203 delete_address(rule_t * rule, in_addr_t addr)
00204 {
00205     address_t * address = NULL;
00206 
00207     address = address_entry(patricia_get(rule->addresses,
00208                     sizeof(in_addr_t), &addr));
00209 
00210     if(address == NULL) {
00211         LOG(LOG_ERR, "%s: Could not find address to delete",__func__);
00212         return;
00213     }
00214 
00215     if(!patricia_delete(rule->addresses, &address->node)) {
00216         LOG(LOG_ERR, "%s: Deleting address failed", __func__);
00217         return;
00218     }
00219 
00220     free(address);
00221 }
00222 
00223 
00230 static void
00231 delete_all_addresses(void)
00232 {
00233     address_t * add = NULL;
00234 
00235     INSIST_ERR(current_rule != NULL);
00236 
00237     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
00238 
00239     while(NULL != (add =
00240         address_entry(patricia_find_next(current_rule->addresses, NULL)))) {
00241 
00242         if(!patricia_delete(current_rule->addresses, &add->node)) {
00243             LOG(LOG_ERR, "%s: Deleting address failed", __func__);
00244             continue;
00245         }
00246 
00247         free(add);
00248     }
00249 }
00250 
00251 
00258 static void
00259 delete_rule(rule_t * rule)
00260 {
00261     ss_info_t * ssi;
00262     list_item_t * item, * item2;
00263     
00264     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
00265 
00266     if(!patricia_delete(&rules, &rule->node)) {
00267         LOG(LOG_ERR, "%s: Deleting rule failed", __func__);
00268         return;
00269     }
00270     
00271     current_rule = rule;
00272     delete_all_addresses();
00273     patricia_root_delete(rule->addresses);
00274     current_rule = NULL;
00275     
00276     // Go through the all service sets using this rule, and
00277     // for any that do, remove the reference to this particular rule
00278     
00279     item = TAILQ_FIRST(&rule->ssets);
00280     while(item != NULL) {
00281         ssi = (ss_info_t *)item->item;
00282         
00283         // find this particular rule
00284         item2 = TAILQ_FIRST(&ssi->rules);
00285         while(item2 != NULL) {
00286             if(item2->item == rule) {
00287                 // found it, remove it
00288                 TAILQ_REMOVE(&ssi->rules, item2, entries);
00289                 free(item2);
00290                 
00291                 // notify PIC with this service set to delete rule
00292                 notify_delete_rule(rule->name, ssi->fpc_slot, ssi->pic_slot);
00293                 break;
00294             }
00295             item2 = TAILQ_NEXT(item2, entries);
00296         }
00297         
00298         item = TAILQ_NEXT(item, entries);
00299     }
00300 
00301     delete_list(&rule->ssets);
00302 
00303     free(rule);
00304 }
00305 
00306 
00312 static void
00313 delete_all_rules(void)
00314 {
00315     rule_t * rule;
00316 
00317     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
00318     
00319     // we delete all service sets too since none we care about could refer 
00320     // to any rules anyway, delete_rule will be faster after calling this too
00321     delete_all_servicesets();
00322 
00323     while(NULL != (rule = rule_entry(patricia_find_next(&rules, NULL)))) {
00324         delete_rule(rule);
00325     }
00326 }
00327 
00328 
00344 static void
00345 ss_change(evContext ctx UNUSED,
00346           void * uap,
00347           struct timespec due UNUSED,
00348           struct timespec inter UNUSED)
00349 {
00350     ss_info_t * ssi = (ss_info_t *)uap;
00351     rule_t * rule;
00352     list_item_t * item;
00353     
00354     junos_trace(MONITUBE_TRACEFLAG_SSRB, "%s: %s", __func__, ssi->name);
00355     
00356     item = TAILQ_FIRST(&ssi->rules);
00357     while(item != NULL) {
00358         rule = (rule_t *)item->item;
00359         
00360         notify_apply_rule(rule->name, ssi->id, ssi->gen_num, ssi->svc_id,
00361                 ssi->fpc_slot, ssi->pic_slot);
00362         
00363         item = TAILQ_NEXT(item, entries);
00364     }
00365 }
00366 
00367 
00383 static void
00384 notify_ssrb_change(junos_kcom_pub_ssrb_t * ssrb,
00385                    void ** data UNUSED,
00386                    size_t *datalen UNUSED,
00387                    junos_kcom_pub_blob_msg_opcode_t operation)
00388 {
00389     ss_info_t * ssi;
00390 
00391     switch(operation) {
00392     
00393     case JUNOS_KCOM_PUB_BLOB_MSG_ADD:
00394         junos_trace(MONITUBE_TRACEFLAG_SSRB, "%s: add %s", __func__,
00395                 ssrb->svc_set_name);
00396 
00397         // Get service set
00398 
00399         ssi = ss_entry(patricia_get(&ssets,
00400                 strlen(ssrb->svc_set_name) + 1, ssrb->svc_set_name));
00401         
00402         if(ssi != NULL) {
00403             // save some info
00404             ssi->id = ssrb->svc_set_id;
00405             ssi->gen_num = ssrb->gen_num;
00406             ssi->svc_id = ssrb->svc_id;
00407             
00408             // Notify change with 2s delay...
00409             // This delay is not needed, but in practice if there's a 
00410             // "catastropic" service set change causing the delete+add here,
00411             // then we will usually be notified via config too.
00412             // If this is before the 
00413             // config-read this short buffer usually makes time for the config
00414             // read to happen first causing one less delete+add on the PIC b/c
00415             // we don't do it now and just do it after at config-read time
00416             
00417             if(evTestID(ssi->timer)) {
00418                 evClearTimer(m_ctx, ssi->timer);
00419                 evInitID(&ssi->timer);
00420             }
00421             
00422             if(evSetTimer(m_ctx, ss_change, ssi, evAddTime(evNowTime(), 
00423                     evConsTime(2, 0)), evConsTime(0, 0), &ssi->timer)) {
00424                 LOG(LOG_EMERG, "%s: Failed to initialize a timer (Error: %m)",
00425                         __func__);
00426             }
00427         }
00428         // else we will get the info later when reading the configuration
00429         
00430         break;
00431         
00432     case JUNOS_KCOM_PUB_BLOB_MSG_DEL:
00433         junos_trace(MONITUBE_TRACEFLAG_SSRB, "%s: delete %s", __func__,
00434                 ssrb->svc_set_name);
00435         
00436         // we will handle the rest later when we get the configuration delete
00437         
00438         break;
00439         
00440     case JUNOS_KCOM_PUB_BLOB_MSG_CHANGE:
00441         junos_trace(MONITUBE_TRACEFLAG_SSRB, "%s: change %s", __func__,
00442                 ssrb->svc_set_name);
00443         
00444         // a service order change (do nothing)
00445         // or a next-hop change (handled in the configuration read)
00446         
00447         break;
00448         
00449     default:
00450         LOG(LOG_ERR, "%s: Received an unexpected/unhandled event", __func__);
00451     }
00452 }
00453 
00454 
00474 static int
00475 verify_service_interfaces(dax_walk_data_t * dwd,
00476                           ddl_handle_t * dop,
00477                           int action,
00478                           void * data)
00479 {
00480     int check = *((int *)data);
00481     char ss_name[MONITUBE2_MGMT_STRLEN]; // service set name
00482     char int_name[MONITUBE2_MGMT_STRLEN]; // service interface name
00483     ss_info_t * ssi;
00484     rule_t * rule;
00485     address_t * a;
00486     intf_parm_t int_info;
00487     list_item_t * item;
00488     
00489     if (action == DAX_ITEM_CHANGED) {
00490 
00491         if (!dax_get_stringr_by_dwd_ident(dwd, "$ss", 0, ss_name,
00492                 sizeof(ss_name))) {
00493             dax_error(dop, "Failed to parse service-set name");
00494             return DAX_WALK_ABORT;
00495         }
00496         
00497         if (!dax_get_stringr_by_name(dop, "service-interface", int_name,
00498                 sizeof(int_name))) {
00499             dax_error(dop, "Failed to retrieve service interface name");
00500             return DAX_WALK_ABORT;
00501         }
00502         
00503         if (parse_interface(int_name, 0, 0, &int_info, NULL, 0)) {
00504             dax_error(dop,"Failed to parse retrieved service interface name %s",
00505                     int_name);
00506             return DAX_WALK_ABORT;
00507         }
00508         
00509         if (!check) {
00510             // Get service set            
00511             ssi = ss_entry(patricia_get(&ssets, strlen(ss_name) + 1, ss_name));
00512             
00513             if (ssi != NULL && (ssi->fpc_slot != int_info.ipi_fpc || 
00514                         ssi->pic_slot != int_info.ipi_pic)) {
00515                     
00516                 junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: change: %s : %s",
00517                         __func__, ss_name, int_name);
00518                 
00519                 if (strstr(int_info.ipi_name_prefix, "ms") == NULL) {
00520                     dax_error(dop, "Failed to parse service interface name %s. "
00521                             "Not an ms interface (%s)", int_name,
00522                             int_info.ipi_name_prefix);
00523                     return DAX_WALK_ABORT;
00524                 }
00525                 
00526                 // Tell old PIC to delete policies for this service set
00527                 notify_delete_serviceset(ssi->id, ssi->gen_num, ssi->svc_id, 
00528                                 ssi->fpc_slot, ssi->pic_slot);
00529                 
00530                 // Set new PIC info so info will get sent there
00531                 ssi->fpc_slot = int_info.ipi_fpc;
00532                 ssi->pic_slot = int_info.ipi_pic;
00533                 
00534                 // Send info to the new PIC
00535                 item = TAILQ_FIRST(&ssi->rules);
00536                 while(item != NULL) {
00537                     rule = (rule_t *)item->item;
00538                     
00539                     notify_config_rule(rule->name, rule->rate,
00540                             rule->redirect, ssi->fpc_slot, ssi->pic_slot);
00541                     
00542                     a = next_address(rule, NULL);
00543                     while(a != NULL) {
00544                         notify_config_rule_prefix(rule->name, a->address,
00545                             a->mask, false, ssi->fpc_slot, ssi->pic_slot);
00546                         a = next_address(rule, a);
00547                     }
00548                     
00549                     notify_apply_rule(rule->name, ssi->id, ssi->gen_num, 
00550                             ssi->svc_id, ssi->fpc_slot, ssi->pic_slot);
00551                     
00552                     item = TAILQ_NEXT(item, entries);
00553                 }
00554             }
00555         }
00556     }
00557     
00558     return DAX_WALK_OK;
00559 }
00560 
00561 
00583 static int
00584 apply_rules(dax_walk_data_t * dwd,
00585             ddl_handle_t * dop,
00586             int action,
00587             void * data)
00588 {
00589     int check = *((int *)data);
00590     ddl_handle_t * tmp_dop = NULL;
00591     char ss_name[MONITUBE2_MGMT_STRLEN]; // service set name
00592     char es_name[MONITUBE2_MGMT_STRLEN]; // extension service name within ss
00593     char rule_name[MONITUBE2_MGMT_STRLEN]; // monitube2 rule
00594     char int_name[MONITUBE2_MGMT_STRLEN]; // service interface name
00595     intf_parm_t int_info;
00596     ss_info_t * ssi, * ssi2;
00597     rule_t * rule;
00598     ssrb_node_t * ssrb;
00599     list_item_t * item;
00600     address_t * a;
00601     
00602     if (action == DAX_ITEM_DELETE_ALL) { // only happens when !check
00603         
00604         junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete all",  __func__);
00605         
00606         if (!dax_get_stringr_by_dwd_ident(dwd, "$ss", 0, ss_name,
00607                 sizeof(ss_name))) {
00608             
00609             junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete all service sets",
00610                     __func__);
00611             
00612             delete_all_servicesets();
00613             return DAX_WALK_OK;
00614         }
00615         
00616         ssi = ss_entry(patricia_get(&ssets, strlen(ss_name) + 1, ss_name));
00617         
00618         if (ssi == NULL) {
00619                 junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: ignore",  __func__);
00620             return DAX_WALK_OK; // ignore, we have nothing stored for it
00621             
00622             // it is a new service set and we are getting a delete-all
00623             // because it's new before we get a change for the stuff under it
00624         }
00625         
00626         // $rule would never be retrievable b/c it is the outmost container
00627         // $es could be retrievable if all under it was deleted
00628         
00629         if (dax_get_stringr_by_dwd_ident(dwd, "$es", 0, es_name,
00630                 sizeof(es_name))) {
00631             if(strcmp(ssi->es, es_name) == 0) {
00632                 junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete all under "
00633                         "extension-service %s of service-set %s", __func__,
00634                         es_name, ss_name);
00635                 
00636                 delete_serviceset(ssi);
00637                 
00638             } // else not our es
00639         } else {
00640             // all ext-svcs gone
00641             junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete all under service-"
00642                     "set %s", __func__, ss_name);
00643             
00644             delete_serviceset(ssi);
00645         }
00646         
00647         return DAX_WALK_OK;
00648     }
00649     
00650     switch (action) {
00651 
00652     case DAX_ITEM_DELETE: // only happens when !check
00653         
00654         if (!dax_get_stringr_by_dwd_ident(dwd, "$ss", 0, ss_name,
00655                 sizeof(ss_name))) {
00656             dax_error(dop, "Failed to parse service-set name");
00657             return DAX_WALK_ABORT;
00658         }
00659         
00660         if (!dax_get_stringr_by_dwd_ident(dwd, "$es", 0, es_name,
00661                 sizeof(es_name))) {
00662             // Can't get the es, so all ext-svcs/rules were deleted from this 
00663             // service set; since it has no MoniTube rules delete it
00664             
00665             ssi = ss_entry(patricia_get(&ssets, strlen(ss_name) + 1, ss_name));
00666             
00667             if (ssi != NULL) {
00668                 junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete service set "
00669                         "%s", __func__, ss_name);
00670                 delete_serviceset(ssi);
00671             }
00672             return DAX_WALK_OK;
00673         }
00674         
00675         if (!dax_get_stringr_by_dwd_ident(dwd, "$rule", 0, rule_name,
00676                 sizeof(rule_name))) {
00677             
00678             // The entire extension-service object was deleted
00679             
00680             // we don't support more than one monitube es per ss however,
00681             // so we can delete the service set and assume the new es will be a
00682             // DAX_ITEM_CHANGED
00683             
00684             ssi = ss_entry(patricia_get(&ssets, strlen(ss_name) + 1, ss_name));
00685             
00686             if (ssi != NULL) {
00687                 
00688                 if (strcmp(ssi->es, es_name) != 0) {
00689                     return DAX_WALK_OK; // it is not monitube related, ignore
00690                 }
00691                 
00692                 junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete extension-"
00693                         "service %s resulted in a delete of the service set %s "
00694                         "because only one MoniTube extension-service per "
00695                         "service-set", __func__, es_name, ss_name);
00696                 
00697                 delete_serviceset(ssi);
00698                 return DAX_WALK_OK;
00699             }
00700             // else this was an extension-service without monitube rules
00701             return DAX_WALK_OK;
00702         }
00703         
00704         // delete of a single rule:
00705         
00706         junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: delete: %s : %s : %s",
00707                 __func__, ss_name, es_name, rule_name);
00708         
00709         // Get rule
00710         rule = rule_entry(patricia_get(&rules, strlen(rule_name) + 1,
00711                 rule_name));
00712         
00713         if (rule == NULL) {
00714             // Rule was deleted too previously
00715             break; // should have been taken care of already
00716         }
00717         
00718         // Get service set
00719 
00720         ssi = ss_entry(patricia_get(&ssets, strlen(ss_name) + 1,
00721                 ss_name));
00722         
00723         if (ssi == NULL) {
00724             LOG(LOG_ERR, "%s: Cannot find saved service set %s for %s",
00725                     __func__, ss_name, rule_name);
00726             return DAX_WALK_ABORT;
00727         }
00728 
00729         // Remove this rule from the service set
00730         
00731         // find this particular rule
00732         item = TAILQ_FIRST(&ssi->rules);
00733         while(item != NULL) {
00734             if(item->item == rule) {
00735                 // found it, remove it
00736                 TAILQ_REMOVE(&ssi->rules, item, entries);
00737                 break;
00738             }
00739             item = TAILQ_NEXT(item, entries);
00740         }
00741         
00742         if(item == NULL) {
00743             LOG(LOG_ERR, "%s: Cannot find saved reference of rule %s in "
00744                     "service set %s", __func__, rule_name, ss_name);
00745             return DAX_WALK_ABORT;
00746         }
00747         free(item);
00748         
00749         // Remove this service-set from the rule
00750         item = TAILQ_FIRST(&rule->ssets);
00751         while(item != NULL) {
00752             if(item->item == ssi) {
00753                 // found it, remove it
00754                 TAILQ_REMOVE(&rule->ssets, item, entries);
00755                 break;
00756             }
00757             item = TAILQ_NEXT(item, entries);
00758         }
00759         
00760         if(item == NULL) {
00761             LOG(LOG_ERR, "%s: Cannot find saved reference of rule %s in "
00762                     "service set %s", __func__, rule_name, ss_name);
00763             return DAX_WALK_ABORT;
00764         }
00765         free(item);
00766         
00767         if (ssi->id) { // if not set yet we haven't applied it
00768             notify_remove_rule(rule->name, ssi->id, ssi->gen_num, ssi->svc_id,
00769                     ssi->fpc_slot, ssi->pic_slot);
00770         }
00771         
00772         break;
00773 
00774     case DAX_ITEM_CHANGED:
00775 
00776         if (!dax_get_stringr_by_dwd_ident(dwd, "$ss", 0, ss_name,
00777                 sizeof(ss_name))) {
00778             dax_error(dop, "Failed to parse service-set name");
00779             return DAX_WALK_ABORT;
00780         }
00781         
00782         if (!dax_get_stringr_by_dwd_ident(dwd, "$es", 0, es_name,
00783                 sizeof(es_name))) {
00784             dax_error(dop, "Failed to parse extension-service name");
00785             return DAX_WALK_ABORT;
00786         }
00787         
00788         if (!dax_get_stringr_by_dwd_ident(dwd, "$rule", 0, rule_name,
00789                 sizeof(rule_name))) {
00790             dax_error(dop, "Failed to parse applied rule's name");
00791             return DAX_WALK_ABORT;
00792         }
00793         
00794         if (!dax_get_object_by_dwd(dwd, "$ss", "sampling-service", &tmp_dop, 0)) {
00795             dax_error(dop, "Failed to parse sampling-service");
00796             return DAX_WALK_ABORT;
00797         }
00798         
00799         if (!dax_get_stringr_by_name(tmp_dop, "service-interface",
00800                 int_name, sizeof(int_name))) {
00801             dax_error(dop, "Failed to retrieve service interface name");
00802             return DAX_WALK_ABORT;
00803         }
00804         
00805         if(parse_interface(int_name, 0, 0, &int_info, NULL, 0)) {
00806             dax_error(dop, "Failed to parse retrieved service interface name %s",
00807                     int_name);
00808             return DAX_WALK_ABORT;
00809         }
00810         
00811         if(strstr(int_info.ipi_name_prefix, "ms") == NULL) {
00812             dax_error(dop, "Failed to parse service interface name %s. Not "
00813                     "an ms interface (%s)", int_name, int_info.ipi_name_prefix);
00814             return DAX_WALK_ABORT;
00815         }
00816         
00817         junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: change: %s : %s : %s : %s",
00818                 __func__, ss_name, es_name, rule_name, int_name);
00819        
00820         if (!check) {
00821             
00822             // Get rule
00823             rule = rule_entry(patricia_get(&rules, strlen(rule_name) + 1,
00824                     rule_name));
00825             
00826             if (rule == NULL) {
00827                 // Shouldn't happen due to DDL must dependencies
00828                 LOG(LOG_ERR, "%s: Cannot find rule configuration for %s",
00829                         __func__, rule_name);
00830                 return DAX_WALK_ABORT;
00831             }
00832             
00833             // Get or create service set
00834             
00835             ssi = ss_entry(patricia_get(&ssets, strlen(ss_name) + 1, ss_name));
00836             
00837             if (ssi == NULL) {
00838                 ssi = calloc(1, sizeof(ss_info_t));
00839                 INSIST(ssi != NULL);
00840 
00841                 strlcpy(ssi->name, ss_name, sizeof(ssi->name));
00842                 strlcpy(ssi->es, es_name, sizeof(ssi->es));
00843                 
00844                 TAILQ_INIT(&ssi->rules);
00845 
00846                 // Add to patricia tree
00847                 patricia_node_init_length(&ssi->node, strlen(ss_name) + 1);
00848 
00849                 if (!patricia_add(&ssets, &ssi->node)) {
00850                     LOG(LOG_ERR, "%s: Cannot add service set info for %s to "
00851                         "corresponding rule %s", __func__, ss_name, rule_name);
00852                     free(ssi);
00853                     return DAX_WALK_ABORT;
00854                 }
00855                 ssi->fpc_slot = int_info.ipi_fpc;
00856                 ssi->pic_slot = int_info.ipi_pic;
00857             } else {
00858                 if (ssi->fpc_slot != int_info.ipi_fpc || 
00859                         ssi->pic_slot != int_info.ipi_pic) {
00860                     
00861                     // Tell old PIC to delete policies for this service set
00862                     notify_delete_serviceset(ssi->id, ssi->gen_num, ssi->svc_id,
00863                                 ssi->fpc_slot, ssi->pic_slot);
00864                     
00865                     // Set new PIC info so info will get sent there
00866                     ssi->fpc_slot = int_info.ipi_fpc;
00867                     ssi->pic_slot = int_info.ipi_pic;
00868                 }
00869             }
00870 
00871             // Check rules list in ssi
00872 
00873             item = TAILQ_FIRST(&ssi->rules);
00874             while(item != NULL) {
00875                 if (item->item == rule) {
00876                     // already in list
00877                     break;
00878                 }
00879                  item = TAILQ_NEXT(item, entries);
00880             }
00881             
00882             if (item == NULL) { // it wasn't found so add it
00883                 item = calloc(1, sizeof(list_item_t));
00884                 item->item = rule;
00885                 TAILQ_INSERT_TAIL(&ssi->rules, item, entries);
00886             }
00887             
00888             // Check ssets list in rule
00889             
00890             item = TAILQ_FIRST(&rule->ssets);
00891             while(item != NULL) {
00892                 if (item->item == ssi) {
00893                     // already in list
00894                     break;
00895                 }
00896                  item = TAILQ_NEXT(item, entries);
00897             }
00898             
00899             if (item == NULL) { // it wasn't found so add it
00900                 item = calloc(1, sizeof(list_item_t));
00901                 item->item = ssi;
00902                 TAILQ_INSERT_TAIL(&rule->ssets, item, entries);
00903             }
00904             
00905             // Extract any SSRB info we can if possible
00906 
00907             ssrb = ssrb_get_node_by_name(ss_name);
00908             if (ssrb != NULL) {
00909                 ssi->id = ssrb->sset_id;
00910                 ssi->gen_num = ssrb->gen_num;
00911                 ssi->svc_id = ssrb->ssrb->svc_id;
00912             } else {
00913                 // we will get the ssrb info sometime later probably
00914             }
00915             
00916             // Notify PIC that it will need the rule's config (action+addresses)
00917             // but if another service set on the same PIC uses this rule, then
00918             // don't bother sending the rule again, because it could be a lot
00919             ssi2 = next_serviceset(NULL);
00920             while(ssi2 != NULL) {
00921                 if (ssi2 == ssi) {
00922                     ssi2 = next_serviceset(ssi2);
00923                     continue;
00924                 }
00925                 
00926                 if (ssi2->fpc_slot == ssi->fpc_slot && 
00927                         ssi2->pic_slot == ssi->pic_slot) {
00928                     // service set is running on the same PIC
00929                     // check if it uses the same rule
00930                     
00931                     item = TAILQ_FIRST(&ssi2->rules);
00932                     while(item != NULL) {
00933                         if (item->item == rule) {
00934                             // This service set has a reference to that rule;
00935                             // thus, rule's config should have already been sent 
00936                             break;
00937                         }
00938                         item = TAILQ_NEXT(item, entries);
00939                     }
00940                     if (item != NULL) { // found it 
00941                         break;
00942                     }
00943                 }
00944                 ssi2 = next_serviceset(ssi2);
00945             }
00946             
00947             if (ssi2 == NULL) { // no luck finding rule in another service set
00948                 // Send PIC the rule's config (action+addresses)
00949                 notify_config_rule(rule->name, rule->rate, rule->redirect,
00950                                         ssi->fpc_slot, ssi->pic_slot);
00951                 
00952                 a = next_address(rule, NULL);
00953                 while(a != NULL) {
00954                     notify_config_rule_prefix(rule->name, a->address, a->mask,
00955                                            false, ssi->fpc_slot, ssi->pic_slot);
00956                     a = next_address(rule, a);
00957                 }
00958             }
00959             
00960             if (ssi->id) { // if still 0 we haven't got ssrb info
00961                 notify_apply_rule(rule->name, ssi->id, ssi->gen_num,ssi->svc_id,
00962                         ssi->fpc_slot, ssi->pic_slot);
00963             }
00964         }
00965 
00966         break;
00967 
00968     case DAX_ITEM_UNCHANGED:
00969         junos_trace(MONITUBE_TRACEFLAG_CONF,
00970                 "%s: DAX_ITEM_UNCHANGED observed", __func__);
00971         break;
00972 
00973     default:
00974         break;
00975     }
00976 
00977     return DAX_WALK_OK;
00978 }
00979 
00980     
01000 static int
01001 parse_addresses(dax_walk_data_t * dwd,
01002                 ddl_handle_t * dop,
01003                 int action,
01004                 void * data)
01005 {
01006     char ip_str[32], * tmpstr, *tmpip;
01007     struct in_addr tmp;
01008     in_addr_t addr, prefix;
01009     int check = *((int *)data), mask;
01010     address_t * address = NULL;
01011     ss_info_t * ssi;
01012     list_item_t * item;
01013 
01014     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
01015 
01016     if(action == DAX_ITEM_DELETE_ALL) {
01017         // All addresses were deleted
01018         delete_all_addresses();
01019         
01020         // We shouldn't get this if the rule was deleted or often, but we may be
01021         // out-of-sync with config db (or starting up) and then multiple CHANGE
01022         // events would come for all configured addresses
01023         
01024         // Rather than deleting each prefix, we delete the rule and re-add it 
01025         // with no prefixes. If this is happening at startup, then rule would be
01026         // new, then rule's ssets will be empty anyway
01027         
01028         item = TAILQ_FIRST(&current_rule->ssets);
01029         while(item != NULL) {
01030             ssi = (ss_info_t *)item->item;
01031             
01032             notify_delete_rule(current_rule->name, ssi->fpc_slot,ssi->pic_slot);
01033             notify_config_rule(current_rule->name, current_rule->rate,
01034                     current_rule->redirect, ssi->fpc_slot, ssi->pic_slot);
01035             
01036             item = TAILQ_NEXT(item, entries);
01037         }
01038         
01039         return DAX_WALK_OK;
01040     }
01041 
01042     switch(action) {
01043 
01044     case DAX_ITEM_DELETE:
01045         // an address was deleted
01046 
01047         // get the (deleted) address
01048         // for deleted items we can only get a string form:
01049         if(!dax_get_stringr_by_dwd_ident(dwd, NULL, 0, ip_str, sizeof(ip_str))){
01050             dax_error(dop, "Failed to parse IP address and prefix on delete");
01051             return DAX_WALK_ABORT;
01052         }
01053 
01054         // break off prefix
01055         tmpip = strdup(ip_str);
01056         tmpstr = strtok(tmpip, "/");
01057 
01058         if(inet_aton(tmpstr, &tmp) != 1) { // if failed
01059             dax_error(dop, "Failed to parse prefix address portion: %s",
01060                     ip_str);
01061             return DAX_WALK_ABORT;
01062         }
01063         addr = tmp.s_addr;
01064 
01065         // parse prefix
01066         tmpstr = strtok(NULL, "/");
01067 
01068         errno = 0;
01069         mask = (int)strtol(tmpstr, (char **)NULL, 10);
01070         if(errno) {
01071             dax_error(dop, "Failed to parse prefix mask portion: %s", ip_str);
01072             return DAX_WALK_ABORT;
01073         }
01074         if(mask < 0 || mask > 32) {
01075             dax_error(dop, "Mask bits must be in range of 0-32: %s", ip_str);
01076             return DAX_WALK_ABORT;
01077         }
01078 
01079         if(mask == 32) {
01080             prefix = 0xFFFFFFFF;
01081         } else {
01082             prefix = (1 << mask) - 1;
01083             prefix = htonl(prefix);
01084         }
01085 
01086         free(tmpip);
01087 
01088         if(!check) {
01089             delete_address(current_rule, addr);
01090             
01091             // Rule's addresses have changed
01092             // If any ss is using the rule notify the PICs of the change
01093             
01094             item = TAILQ_FIRST(&current_rule->ssets);
01095             while(item != NULL) {
01096                 ssi = (ss_info_t *)item->item;
01097                 
01098                 notify_config_rule_prefix(current_rule->name, addr, prefix,
01099                         true, ssi->fpc_slot, ssi->pic_slot);
01100                 
01101                 item = TAILQ_NEXT(item, entries);
01102             }
01103         }
01104 
01105         break;
01106 
01107     case DAX_ITEM_CHANGED:
01108         // a server was added
01109 
01110         if(!dax_get_ipv4prefixmandatory_by_name(dop,
01111                 DDLNAME_ADDRESSES_ADDRESS, &addr, &prefix)) {
01112             dax_error(dop, "Failed to parse IP address and prefix");
01113             return DAX_WALK_ABORT;
01114         }
01115 
01116         if(((~prefix) & addr) != 0) {
01117             dax_error(dop, "Host bits in address must be zero");
01118             return DAX_WALK_ABORT;
01119         }
01120 
01121         if(!check) {
01122             address = calloc(1, sizeof(address_t));
01123             INSIST(address != NULL);
01124 
01125             address->address = addr;
01126             address->mask = prefix;
01127 
01128             // Add to patricia tree
01129             
01130             patricia_node_init(&address->node);
01131 
01132             if(!patricia_add(current_rule->addresses, &address->node)) {
01133                 tmp.s_addr = addr;
01134                 tmpstr = strdup(inet_ntoa(tmp));
01135                 tmp.s_addr = prefix;
01136                 LOG(LOG_ERR, "%s: Cannot add address %s/%s as it conflicts with"
01137                     " another address in the same group (%s)", __func__, tmpstr,
01138                     inet_ntoa(tmp), current_rule->name);
01139                 free(tmpstr);
01140                 free(address);
01141             }
01142 
01143             // Rule's addresses have changed
01144             // If any ss is using the rule notify the PICs of the change
01145             // If this is a new rule, then rule's ssets will be empty anyway
01146             
01147             item = TAILQ_FIRST(&current_rule->ssets);
01148             while(item != NULL) {
01149                 ssi = (ss_info_t *)item->item;
01150                 
01151                 notify_config_rule_prefix(current_rule->name, addr, prefix,
01152                         false, ssi->fpc_slot, ssi->pic_slot);
01153                 
01154                 item = TAILQ_NEXT(item, entries);
01155             }
01156         }
01157 
01158         break;
01159 
01160     case DAX_ITEM_UNCHANGED:
01161         junos_trace(MONITUBE_TRACEFLAG_CONF,
01162                 "%s: DAX_ITEM_UNCHANGED observed", __func__);
01163         break;
01164 
01165     default:
01166         break;
01167     }
01168 
01169     return DAX_WALK_OK;
01170 }
01171 
01172 
01191 static int
01192 parse_rules(dax_walk_data_t * dwd,
01193             ddl_handle_t * dop,
01194             int action,
01195             void * data)
01196 {
01197     ddl_handle_t * addresses_dop, * tmp_dop;
01198     int check = *((int *)data);
01199     char rule_name[MONITUBE2_MGMT_STRLEN];
01200     uint32_t rate = 0;
01201     in_addr_t mirror_to = 0;
01202     int addr_fam;
01203     rule_t * rule = NULL;
01204     bool is_rule_new = false;
01205     ss_info_t * ssi;
01206     list_item_t * item;
01207 
01208     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s", __func__);
01209 
01210     switch (action) {
01211 
01212     case DAX_ITEM_DELETE_ALL:
01213 
01214         // All rules were deleted
01215         delete_all_rules();
01216         return DAX_WALK_OK;
01217 
01218         break;
01219 
01220     case DAX_ITEM_DELETE:
01221 
01222         // get the (deleted) rule name
01223         if (!dax_get_stringr_by_dwd_ident(dwd, NULL, 0,
01224                 rule_name, sizeof(rule_name))) {
01225             dax_error(dop, "Failed to parse a deleted rule's name");
01226             return DAX_WALK_ABORT;
01227         }
01228 
01229         if(check) {
01230             break; // nothing to do
01231         }
01232 
01233         rule = rule_entry(patricia_get(&rules, strlen(rule_name) + 1,
01234                 rule_name));
01235         if(rule != NULL) {
01236             delete_rule(rule);
01237         }
01238 
01239         break;
01240 
01241     case DAX_ITEM_CHANGED:
01242 
01243         // get the rule name
01244 
01245         if (!dax_get_stringr_by_name(dop, DDLNAME_RULE_RULE_NAME,
01246                 rule_name, sizeof(rule_name))) {
01247             dax_error(dop, "Failed to parse rule name");
01248             return DAX_WALK_ABORT;
01249         }
01250 
01251         // create rule if necessary
01252         
01253         if(!check) {
01254             rule = rule_entry(patricia_get(
01255                     &rules, strlen(rule_name) + 1, rule_name));
01256             
01257             if(rule == NULL) {
01258                 rule = calloc(1, sizeof(rule_t));
01259                 INSIST(rule != NULL);
01260                 strlcpy(rule->name, rule_name, sizeof(rule->name));
01261 
01262                 // Add to patricia tree
01263                 patricia_node_init_length(&rule->node, strlen(rule->name) + 1);
01264 
01265                 if(!patricia_add(&rules, &rule->node)) {
01266                     LOG(LOG_ERR, "%s: Failed to add rule to "
01267                             "configuration", __func__);
01268                     free(rule);
01269                     return DAX_WALK_ABORT;
01270                 }
01271 
01272                 // init addresses
01273                 rule->addresses = patricia_root_init(
01274                         NULL, FALSE, sizeof(in_addr_t), 0);
01275                 
01276                 // init ssets
01277                 TAILQ_INIT(&rule->ssets);
01278                 
01279                 is_rule_new = true;
01280                 // Because the rule is new, we don't notify any PICs of the rule
01281                 // If any service sets refer to this rule, then only there do we 
01282                 // send the rule's info (done in apply_rules)
01283             }
01284             
01285             // save so that when parsing addresses
01286             // we know to which rule to associate them
01287             current_rule = rule;
01288         }
01289         
01290 
01291         // Get "from" params:
01292         
01293         if(!dax_get_object_by_name(dop, DDLNAME_RULE_FROM,
01294                 &tmp_dop, FALSE)) {
01295 
01296             dax_error(dop, "Failed to parse from (required)");
01297             return DAX_WALK_ABORT;
01298         }
01299         
01300         if(!dax_get_object_by_name(tmp_dop, DDLNAME_ADDRESSES,
01301                 &addresses_dop, FALSE)) {
01302 
01303             dax_error(dop, "Failed to parse destination-addresses (required)");
01304             dax_release_object(&tmp_dop);
01305             return DAX_WALK_ABORT;
01306         }
01307 
01308         // parse the destination addresses
01309         if(dax_is_changed(addresses_dop) &&
01310             dax_walk_list(addresses_dop, DAX_WALK_DELTA, parse_addresses, data)
01311                     != DAX_WALK_OK) {
01312 
01313             dax_release_object(&addresses_dop);
01314             dax_release_object(&tmp_dop);
01315             return DAX_WALK_ABORT;
01316         }
01317         
01318         dax_release_object(&tmp_dop);
01319         dax_release_object(&addresses_dop);
01320         current_rule = NULL;
01321         
01322         // Get "then" params:
01323         
01324         if(!dax_get_object_by_name(dop, DDLNAME_RULE_THEN,
01325                 &tmp_dop, FALSE)) {
01326 
01327             dax_error(dop, "Failed to parse then (required)");
01328             return DAX_WALK_ABORT;
01329         }
01330         
01331         if(!dax_is_changed(tmp_dop)) {
01332             dax_release_object(&tmp_dop);
01333             break;
01334         }
01335         
01336         // read in some of the "then" attributes
01337         dax_get_uint_by_name(tmp_dop,
01338                 DDLNAME_RULE_THEN_MONITORING_RATE, &rate);
01339         
01340         if(dax_get_ipaddr_by_name(tmp_dop, DDLNAME_RULE_THEN_MIRROR_TO,
01341             &addr_fam, &mirror_to, sizeof(mirror_to)) && addr_fam != AF_INET) {
01342             
01343             dax_error(dop, "Failed to parse mirror destination IPv4 address");
01344             dax_release_object(&tmp_dop);
01345             return DAX_WALK_ABORT;
01346         }
01347         
01348         // check one or the other and INET below
01349         if(!(rate || mirror_to)) {
01350             dax_error(dop, "Either a %s or %s must be configured", 
01351                     DDLNAME_RULE_THEN_MONITORING_RATE, 
01352                     DDLNAME_RULE_THEN_MIRROR_TO);
01353             dax_release_object(&tmp_dop);
01354             return DAX_WALK_ABORT;
01355         } else if (!check) {
01356             
01357             if(is_rule_new) {
01358                 rule->rate = rate;
01359                 rule->redirect = mirror_to;
01360             } else {
01361                 if(rule->rate != rate || rule->redirect != mirror_to) {
01362                     
01363                     // Existing rule's actions have changed
01364                     // If any ss is using the rule notify the PICs of the change
01365                     
01366                     item = TAILQ_FIRST(&rule->ssets);
01367                     while(item != NULL) {
01368                         ssi = (ss_info_t *)item->item;
01369                         notify_config_rule(rule->name, rate, mirror_to,
01370                                 ssi->fpc_slot, ssi->pic_slot);
01371                         item = TAILQ_NEXT(item, entries);
01372                     }
01373                 }
01374                 rule->rate = rate;
01375                 rule->redirect = mirror_to;
01376             }
01377         }
01378         
01379         dax_release_object(&tmp_dop);
01380         break;
01381 
01382     case DAX_ITEM_UNCHANGED:
01383         junos_trace(MONITUBE_TRACEFLAG_CONF,
01384                 "%s: DAX_ITEM_UNCHANGED observed", __func__);
01385         break;
01386 
01387     default:
01388         break;
01389     }
01390 
01391     return DAX_WALK_OK;
01392 }
01393 
01394 
01410 static void
01411 age_out_flow_stat(evContext ctx UNUSED,
01412                           void * uap,
01413                           struct timespec due UNUSED,
01414                           struct timespec inter UNUSED)
01415 {
01416     flowstat_t * fs = (flowstat_t *)uap;
01417 
01418     INSIST_ERR(fs != NULL);
01419 
01420     if(evTestID(fs->timer_id)) {
01421        evClearTimer(m_ctx, fs->timer_id);
01422        evInitID(&fs->timer_id);
01423     }
01424 
01425     patricia_delete(fs->ssi->stats, &fs->node);
01426     
01427     if(patricia_isempty(fs->ssi->stats)) { // clean if sset tree is empty
01428         patricia_root_delete(fs->ssi->stats);
01429         patricia_delete(&flow_stats, &fs->ssi->node);
01430         free(fs->ssi);
01431     }
01432 
01433     free(fs);
01434 }
01435 
01448 static void
01449 syncup(junos_kcom_pub_ssrb_t * s, void ** d UNUSED, size_t * l UNUSED)
01450 {
01451     LOG(LOG_INFO, "%s: SSRB sync for %s (%d, %d, %d)", __func__,
01452             s->svc_set_name, s->svc_set_id, s->svc_id, s->gen_num);
01453 }
01454 
01455 
01456 /*** GLOBAL/EXTERNAL Functions ***/
01457 
01458 
01462 void
01463 init_config(evContext ctx)
01464 {
01465     m_ctx = ctx;
01466 
01467     patricia_root_init(&rules, FALSE, MONITUBE2_MGMT_STRLEN, 0);
01468     patricia_root_init(&ssets, FALSE, MONITUBE2_MGMT_STRLEN, 0);
01469     patricia_root_init(&flow_stats, FALSE, sizeof(uint16_t), 0);
01470 
01471     if (ssrb_config_init()) {
01472         LOG(LOG_EMERG,"%s: service management initialization failed", __func__);
01473     }
01474     
01475     if (svcset_ssrb_async(notify_ssrb_change, NULL)) {
01476         LOG(LOG_EMERG, "%s: Cannot register for SSRB notifications", __func__);
01477     }
01478    
01479     if (svcset_ssrb_sync(syncup, NULL)) {
01480         LOG(LOG_ERR, "%s: Error syncing up SSRB database", __func__);
01481     }
01482 }
01483 
01484 
01488 void
01489 clear_config(void)
01490 {
01491     delete_all_rules();
01492     process_notifications();
01493     clear_stats();
01494 }
01495 
01496 
01505 rule_t *
01506 next_rule(rule_t * data)
01507 {
01508     return rule_entry(patricia_find_next(&rules,(data ? &(data->node) : NULL)));
01509 }
01510 
01511 
01524 address_t *
01525 next_address(rule_t * rule, address_t * data)
01526 {
01527     return address_entry(patricia_find_next(rule->addresses,
01528                                     (data ? &(data->node) : NULL)));
01529 }
01530 
01531 
01540 ss_info_t *
01541 next_serviceset(ss_info_t * data)
01542 {
01543     return ss_entry(patricia_find_next(&ssets, (data ? &(data->node) : NULL)));
01544 }
01545 
01546 
01556 flowstat_ss_t *
01557 next_flowstat_ss(flowstat_ss_t * data)
01558 {
01559     return fss_entry(patricia_find_next(&flow_stats,
01560                                     (data ? &(data->node) : NULL)));
01561 }
01562 
01575 flowstat_t *
01576 next_flowstat(flowstat_ss_t * fss, flowstat_t * data)
01577 {
01578     return fs_entry(patricia_find_next(fss->stats,
01579                                     (data ? &(data->node) : NULL)));
01580 }
01581 
01585 void
01586 clear_stats(void)
01587 {
01588         flowstat_ss_t * fss;
01589         flowstat_t * fs;
01590         
01591     // delete all statistics data
01592     
01593     while((fss = fss_entry(patricia_find_next(&flow_stats, NULL))) != NULL) {
01594         
01595         while((fs = fs_entry(patricia_find_next(fss->stats, NULL))) != NULL) {
01596                 
01597             if(evTestID(fs->timer_id)) {
01598                evClearTimer(m_ctx, fs->timer_id);
01599             }
01600                 
01601                 patricia_delete(fss->stats, &fs->node);
01602                 free(fs);
01603         }
01604         
01605         patricia_root_delete(fss->stats);
01606         patricia_delete(&flow_stats, &fss->node);
01607         free(fss);
01608     }
01609 }
01610 
01611 
01636 void
01637 set_flow_stat(uint16_t fpc_slot,
01638               uint16_t pic_slot,
01639               uint16_t ssid,
01640               in_addr_t flow_addr,
01641               uint16_t flow_port,
01642               double mdi_df,
01643               uint32_t mdi_mlr)
01644 {
01645         flowstat_ss_t * fss;
01646     flowstat_t * fs;
01647     bool isnew = false;
01648     
01649     struct key_s {
01650         uint16_t  fpc;
01651         uint16_t  pic;
01652         in_addr_t address;
01653         uint16_t  port;
01654     } key;
01655     
01656     int key_size = sizeof(in_addr_t) + (3 * sizeof(uint16_t));
01657 
01658     // get monitor
01659     fss = fss_entry(patricia_get(&flow_stats, sizeof(ssid), &ssid));
01660 
01661     if(fss == NULL) {
01662 
01663         fss = calloc(1, sizeof(flowstat_ss_t));
01664         INSIST(fss != NULL);
01665         
01666         fss->ssid = ssid;
01667         fss->stats = patricia_root_init(NULL, FALSE, key_size, 0);
01668         
01669         // Add to patricia tree
01670         
01671         patricia_node_init(&fss->node);
01672 
01673         if(!patricia_add(&flow_stats, &fss->node)) {
01674             LOG(LOG_ERR, "%s: Failed to add a flow stat service set entry for "
01675                         "%d", __func__, ssid);
01676             free(fss);
01677             return;
01678         }
01679         isnew = true;
01680     }
01681     
01682     // get flow stat
01683 
01684     key.fpc = fpc_slot;
01685     key.pic = pic_slot;
01686     key.address = flow_addr;
01687     key.port = flow_port;
01688 
01689     fs = fs_entry(patricia_get(fss->stats, key_size, &key));
01690 
01691     if(fs == NULL) { // gotta create it
01692         fs = calloc(1, sizeof(flowstat_t));
01693         INSIST(fs != NULL);
01694         fs->fpc_slot = fpc_slot;
01695         fs->pic_slot = pic_slot;
01696         fs->flow_addr = flow_addr;
01697         fs->flow_port = flow_port;
01698         evInitID(&fs->timer_id);
01699         fs->ssi = fss;
01700 
01701         if(!patricia_add(fss->stats, &fs->node)) {
01702             LOG(LOG_ERR, "%s: Failed to add a flow stat to configuration",
01703                     __func__);
01704             free(fs);
01705             
01706             if(isnew) { // more clean up
01707                 patricia_delete(&flow_stats, &fss->node);
01708                 patricia_root_delete(fss->stats);
01709                 free(fss);
01710             }
01711             return;
01712         }
01713 
01714     } else { // it already exists
01715         if(evTestID(fs->timer_id)) {
01716            evClearTimer(m_ctx, fs->timer_id);
01717            evInitID(&fs->timer_id);
01718         }
01719     }
01720 
01721     fs->last_mdi_df[fs->window_position] = mdi_df;
01722     fs->last_mdi_mlr[fs->window_position] = mdi_mlr;
01723     fs->reports++;
01724     fs->window_position++;
01725     if(fs->window_position == STATS_BASE_WINDOW) {
01726         fs->window_position = 0;
01727     }
01728 
01729     // reset age timer
01730 
01731     if(evSetTimer(m_ctx, age_out_flow_stat, fs,
01732             evAddTime(evNowTime(), evConsTime(MAX_FLOW_AGE, 0)),
01733             evConsTime(0, 0), &fs->timer_id)) {
01734 
01735         LOG(LOG_EMERG, "%s: evSetTimer() failed! Will not be "
01736                 "able to age out flow statistics", __func__);
01737     }
01738 }
01739 
01740 
01751 int
01752 monitube_config_read(int check)
01753 {
01754     const char * monitube_rules_config[] =
01755         {DDLNAME_SERVICES, DDLNAME_SYNC, DDLNAME_MONITUBE, DDLNAME_RULE, NULL};
01756 
01757     ddl_handle_t * top = NULL;
01758 
01759     junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: Starting monitube "
01760             "configuration load", __func__);
01761 
01762     // Load the main configuration under sync monitube (if changed)...
01763 
01764     if (!dax_get_object_by_path(NULL, monitube_rules_config, &top, FALSE))  {
01765 
01766         junos_trace(MONITUBE_TRACEFLAG_CONF,
01767                 "%s: Cleared monitube configuration", __func__);
01768 
01769         clear_config(); // No rules
01770         return SUCCESS;
01771     }
01772     
01773     if(dax_is_changed(top)) { // a rule change happened
01774         if(dax_walk_list(top, DAX_WALK_DELTA, parse_rules, &check)
01775                 != DAX_WALK_OK) {
01776 
01777             junos_trace(MONITUBE_TRACEFLAG_CONF, "%s: walking rules "
01778                 "list failed", __func__);
01779             dax_release_object(&top);
01780             return EFAIL;
01781         }
01782     }
01783     
01784     dax_release_object(&top);
01785     
01786     // Apply rules/detect changes
01787     dax_query(NULL, "services service-set $ss extension-service $es "
01788         "monitube2-rules $rule", DAX_WALK_DELTA, apply_rules, &check);
01789     
01790     // Detect changes in the service interface
01791     dax_query(NULL, "services service-set $ss sampling-service",
01792             DAX_WALK_CHANGED, verify_service_interfaces, &check);
01793     
01794     // send to the PIC(s) if !check
01795     if (!check) {
01796         process_notifications();
01797     }
01798 
01799     junos_trace(MONITUBE_TRACEFLAG_CONF,
01800             "%s: Loaded monitube configuration", __func__);
01801 
01802     return SUCCESS;
01803 }

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:04 2010 for SDK Your Net Corporation Monitube2 IPTV Monitoring Example: monitube2-mgmt 1.0 by Doxygen 1.5.1