/* * Copyright (C) 1999 * Sony Computer Science Laboratories Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: tc_altq.c,v 1.2 1999/11/03 06:48:27 kjc Exp $ */ /************************ tc_altq.c ********************************* * * * Adaptation Module: Converts RSVP's TC interface into the ALTQ * * interface. * * * *********************************************************************/ #include #include #include "rsvp_daemon.h" #include "rapi_lib.h" /* Define flowspec formats */ #include "rsvp_specs.h" /* Flowspec descriptor format */ #include "rsvp_TCif.h" /* Adaptation interface */ #include #include "altq_qop.h" #include "qop_cbq.h" #include "qop_hfsc.h" typedef struct { int in_if; /* interface to which resv applies */ int TC_kflags; struct ifinfo *ifinfo; /* interface info */ struct classinfo *clinfo; /* class info */ SENDER_TSPEC *s_tspec; /* ptr to SENDER_TSPEC object */ FLOWSPEC *spec; /* ptr to FLOWSPEC object */ FILTER_SPEC *filter; /* ptr to FILTER_SPEC object */ } tc_t; /* external declarations */ extern Object_header *copy_object(Object_header *); /* internal declarations */ static int tc_addflow(tc_t *tch); static int tc_modifyflow(tc_t *tch, tc_t *otch); static int tc_deleteflow(tc_t *tch); static int cbq_addflow(tc_t *tch); static int cbq_modifyflow(tc_t *tch, tc_t *otch); static int cbq_deleteflow(tc_t *tch); static int hfsc_addflow(tc_t *tch); static int hfsc_modifyflow(tc_t *tch, tc_t *otch); static int hfsc_deleteflow(tc_t *tch); static int rsvp2altq_filter(FilterSpec *filtp, Session *dest, struct flow_filter *fl); static int rsvp2altq_label(RSB *rp, Session *dest, struct flow_filter *flp); /* static int qop_add_label(struct fltrinfo **rp, struct classinfo *clinfo, const char *flname, const struct flow_filter *fltr, struct fltrinfo **conflict); */ /************************************************************************ * * Interface routines to call the ALTQ kernel functions * ************************************************************************/ /* Note: these calls use the address of the tc_t block as a parameter * to carry the interface number. This block actually contains the * the other parameters too, but we leave the parameters explicit to * make the code exactly parallel the Functional Specification. */ void TC_init(int OIf) { int i; static once = FALSE; if (once) return; once = TRUE; if(qcmd_init() != 0) { log(LOG_ERR, 0, "Can't initialize ALTQ!\n"); exit(-1); } for (i = 0; i < if_num; i++) { struct ifinfo *ifinfo; if (IsNumAPI(i)) continue; if_vec[i].if_up = 0; if ((ifinfo = ifname2ifinfo(if_vec[i].if_name)) != NULL) { if (ifinfo->resv_class != NULL) { if_vec[i].if_up = 1; } else log(LOG_WARNING, 0, "%s: No Class defined for RSVP\n", ifinfo->ifname); } } } /* * TC_AddFlowspec(): Call the kernel to make reservation for a flow. * It checks admission control, and returns a handle for the * reservation, or -1 if an error. It may also set *fwd_specpp * to point to a modified flowspec to be forwarded. */ u_long TC_AddFlowspec(int OIf, FLOWSPEC *spec, SENDER_TSPEC *stspec, ADSPEC *adspp, int flags, FLOWSPEC **fwd_specpp) { tc_t *tc_handle = NULL; int error; rsvp_errno = 0; *fwd_specpp = NULL; if(IsNumAPI(OIf)) return((u_long)NULL); /* Handle outgoing flow */ rsvp_errno = 0; if (!if_vec[OIf].if_up) { rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, 0); return(TC_ERROR); } /* Create reservation control block and init */ if((tc_handle = (tc_t*)malloc(sizeof(tc_t))) == NULL) { rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, 0); return(TC_ERROR); } tc_handle->in_if = OIf; tc_handle->TC_kflags = flags; tc_handle->ifinfo = ifname2ifinfo(if_vec[OIf].if_name); tc_handle->clinfo = NULL; tc_handle->spec = copy_spec(spec); tc_handle->s_tspec = stspec ? copy_tspec(stspec) : NULL; /* Can we admit send flow? */ error = tc_addflow(tc_handle); switch (error) { case 0: return((u_long)tc_handle); case QOPERR_ADMISSION_NOSVC: rsvp_errno = Set_Errno(RSVP_Err_TC_ERROR, RSVP_Erv_No_Serv); break; case QOPERR_ADMISSION_NOBW: rsvp_errno = Set_Errno(RSVP_Err_ADMISSION, RSVP_Erv_Bandwidth); break; case QOPERR_ADMISSION_DELAY: rsvp_errno = Set_Errno(RSVP_Err_ADMISSION, RSVP_Erv_DelayBnd); break; default: rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, error); break; } if (tc_handle) { if (tc_handle->spec) free(tc_handle->spec); if (tc_handle->s_tspec) free(tc_handle->s_tspec); free(tc_handle); } return (TC_ERROR); } /* * TC_DelFlowspec(): This routine deletes flow for specified handle */ int TC_DelFlowspec(int OIf, u_long rhandle) { tc_t *tch; int error; if (rhandle == TC_ERROR) return (TC_ERROR); if ((tch = (tc_t*)rhandle) == NULL || IsNumAPI(OIf)) return(TC_OK); /* Handle outgoing flow */ if ((error = tc_deleteflow(tch)) != 0) { if (!rsvp_errno) rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, error); return (TC_ERROR); } if (tch->spec) free(tch->spec); if (tch->s_tspec) free(tch->s_tspec); free(tch); return (TC_OK); } /* * TC_ModFlowspec(): Modifies a flowspec of a given flow. * * It may also set *fwd_specpp to point to a modified flowspec to * be forwarded. */ int TC_ModFlowspec(int OIf, u_long rhandle, FLOWSPEC *specp, SENDER_TSPEC *stspecp, ADSPEC *adspecp, int flags, FLOWSPEC **fwd_specpp) { tc_t *tc_handle; tc_t tc_ohandle; int error; rsvp_errno = 0; *fwd_specpp = NULL; if((tc_handle = (tc_t*)rhandle) == NULL || IsNumAPI(OIf)) return (TC_OK); /* Handle outgoing flow */ /* save old flowspec in case of admission failure. */ tc_ohandle = *tc_handle; tc_handle->TC_kflags = flags; tc_handle->spec = copy_spec(specp); tc_handle->s_tspec = stspecp ? copy_tspec(stspecp) : NULL; error = tc_modifyflow(tc_handle, &tc_ohandle); switch (error) { case 0: break; case QOPERR_ADMISSION_NOSVC: rsvp_errno = Set_Errno(RSVP_Err_TC_ERROR, RSVP_Erv_No_Serv); break; case QOPERR_ADMISSION_NOBW: rsvp_errno = Set_Errno(RSVP_Err_ADMISSION, RSVP_Erv_Bandwidth); break; case QOPERR_ADMISSION_DELAY: rsvp_errno = Set_Errno(RSVP_Err_ADMISSION, RSVP_Erv_DelayBnd); break; default: rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, error); break; } if (error) { /* couldn't update. restore the original flowspec */ if (tc_handle->spec) free(tc_handle->spec); if (tc_handle->s_tspec) free(tc_handle->s_tspec); tc_handle->TC_kflags = tc_ohandle.TC_kflags; tc_handle->spec = tc_ohandle.spec; tc_handle->s_tspec = tc_ohandle.s_tspec; return (TC_ERROR); } /* * successfully modified the class */ if (tc_ohandle.spec) free(tc_ohandle.spec); if (tc_ohandle.s_tspec) free(tc_ohandle.s_tspec); return (TC_OK); } #define In_Obj(x, y) ((Object_header *)(x) <= Next_Object((Object_header *)(y))) /* * TC_Advertise(): Given existing OPWA ADSPEC, return a new updated object. */ ADSPEC * TC_Advertise(int OIf, ADSPEC * old_asp, int flags) { ADSPEC *new_asp = copy_adspec(old_asp); /* We know we will not expand the ADSPEC, so start by * just making a straight copy. */ IS_main_hdr_t *mhp = (IS_main_hdr_t *) Obj_data(new_asp); genparm_parms_t *gpp = (genparm_parms_t *)(mhp +1); IS_serv_hdr_t *shp, *lastshp; float32_t hop_bw; u_int32_t hop_latency, hop_mtu; if (if_vec[OIf].if_up == 0 || (flags & ADVERTF_NonRSVP)) Set_Break_Bit(&gpp->gen_parm_hdr); gpp->gen_parm_hopcnt++; hop_bw = (if_vec[OIf].if_path_bw)?if_vec[OIf].if_path_bw: (TC_DFLT_PATH_BW); gpp->gen_parm_path_bw = MIN(gpp->gen_parm_path_bw, hop_bw); hop_latency = (if_vec[OIf].if_min_latency)?if_vec[OIf].if_min_latency: TC_DFLT_MIN_LATENCY; gpp->gen_parm_min_latency = MIN(gpp->gen_parm_min_latency, hop_latency); hop_mtu = (if_vec[OIf].if_path_mtu)?if_vec[OIf].if_path_mtu: TC_DFLT_MTU; gpp->gen_parm_composed_MTU = MIN(gpp->gen_parm_composed_MTU, hop_mtu); /* If we are not capable of traffic control for a service, * set Break bit in the service. We DO NOT set the Break * bit in the generic parameters, because we DO understand * ADSPECs, unless previous hop was not RSVP-capable. */ shp = Next_Serv_Hdr((IS_serv_hdr_t *)gpp); lastshp = (IS_serv_hdr_t *) Next_Main_Hdr(mhp); if (!In_Obj(lastshp, new_asp)) { /* Internal length falls outside object... * Increment error counter */ free(new_asp); return(NULL); } while (shp < lastshp) { switch(shp->issh_service) { case GUARANTEED_SERV: case CONTROLLED_LOAD_SERV: if (if_vec[OIf].if_up) break; /* fall into... */ default: Set_Break_Bit(shp); break; } shp = Next_Serv_Hdr(shp); } return(new_asp); } /* * TC_AddFilter(): Adds a filter for an existing flow. * * Returns fhandle or TC_ERROR. */ u_long TC_AddFilter(int OIf, u_long rhandle, Session *dest, FILTER_SPEC *filtp) { tc_t *tch = (tc_t*)rhandle; struct fltrinfo *fltrinfo; struct flow_filter filter; int error; if (tch == NULL || IsNumAPI(tch->in_if) || !if_vec[tch->in_if].if_up) { /* ALTQ does not create kernel state for incoming flows */ return TC_OK; } rsvp_errno = 0; /* Add or modify the filter */ if (rsvp2altq_filter(filtp, dest, &filter) != 0) return (TC_ERROR); if ((error = qop_add_filter(&fltrinfo, tch->clinfo, NULL, &filter, NULL)) != 0) { rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, error); return (TC_ERROR); } return ((u_long)fltrinfo); } /* * TC_DelFilter(): Deletes existing filter. */ int TC_DelFilter(int OIf, u_long fhandle) { struct fltrinfo *fltrinfo = (struct fltrinfo *)fhandle; int error; if (fltrinfo == NULL || IsNumAPI(OIf) || !if_vec[OIf].if_up) return TC_OK; rsvp_errno = 0; if((error = qop_delete_filter(fltrinfo)) != 0) { rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, error); return (TC_ERROR); } return (TC_OK); } static int tc_addflow(tc_t *tch) { int error; switch (tch->ifinfo->qdisc->qdisc_type) { case ALTQT_CBQ: error = cbq_addflow(tch); break; case ALTQT_HFSC: error = hfsc_addflow(tch); break; default: error = QOPERR_ADMISSION_NOSVC; } return (error); } static int tc_modifyflow(tc_t *tch, tc_t *otch) { int error; switch (tch->ifinfo->qdisc->qdisc_type) { case ALTQT_CBQ: error = cbq_modifyflow(tch, otch); break; case ALTQT_HFSC: error = hfsc_modifyflow(tch, otch); break; default: error = QOPERR_ADMISSION_NOSVC; } return (error); } static int tc_deleteflow(tc_t *tch) { int error; switch (tch->ifinfo->qdisc->qdisc_type) { case ALTQT_CBQ: error = cbq_deleteflow(tch); break; case ALTQT_HFSC: error = hfsc_deleteflow(tch); break; default: error = QOPERR_ADMISSION_NOSVC; } return (error); } #ifndef filt4_srcaddr /* for isi rsvp rel4.1 compatibility */ #define filt4 filt_u.filt_ipv4 #define filt4_srcaddr filt4.filt_ipaddr #define filt4_srcport filt4.filt_port #endif static int rsvp2altq_filter(FilterSpec *filtp, Session *dest, struct flow_filter *flp) { #ifdef USE_IPV6 struct flow_filter6 *fl6p; #endif memset(flp, 0, sizeof(struct flow_filter)); switch (Obj_CType(dest->d_session)) { case ctype_SESSION_ipv4: case ctype_SESSION_ipv4GPI: flp->ff_flow.fi_family = AF_INET; flp->ff_flow.fi_dst = dest->d_session->sess4_addr; flp->ff_mask.mask_dst.s_addr = 0xffffffff; flp->ff_flow.fi_dport = dest->d_session->sess4_port; flp->ff_flow.fi_proto = dest->d_session->sess4_prot; if (filtp == NULL) { /* IPv4 wildcard filter */ flp->ff_flow.fi_src.s_addr = 0; flp->ff_flow.fi_sport = 0; } else switch (Obj_CType(filtp)) { case ctype_FILTER_SPEC_ipv4: /* IPv4 FILTER_SPEC */ flp->ff_flow.fi_src = filtp->filt4_srcaddr; flp->ff_mask.mask_src.s_addr = 0xffffffff; flp->ff_flow.fi_sport = filtp->filt4_srcport; break; case ctype_FILTER_SPEC_ipv4GPI: /* IPv4/GPI FILTER_SPEC */ flp->ff_flow.fi_dport = 0;/* we don't need dst port */ flp->ff_flow.fi_src = filtp->filtgpi4_srcaddr; flp->ff_mask.mask_src.s_addr = 0xffffffff; flp->ff_flow.fi_gpi = filtp->filtgpi4_srcgpi; break; default: rsvp_errno = Set_Errno(RSVP_Err_UNKNOWN_CTYPE, Obj_CType(filtp)); return (-1); } break; #ifdef USE_IPV6 case ctype_SESSION_ipv6: case ctype_SESSION_ipv6GPI: fl6p = (struct flow_filter6 *)flp; fl6p->ff_flow6.fi6_family = AF_INET6; fl6p->ff_flow6.fi6_dst = dest->d_session->sess6_addr; memset(&fl6p->ff_mask6.mask6_dst, 0xff, sizeof(struct in6_addr)); fl6p->ff_flow6.fi6_dport = dest->d_session->sess6_port; fl6p->ff_flow6.fi6_proto = dest->d_session->sess6_prot; if (filtp == NULL) { /* IPv6 wildcard */ memset(&fl6p->ff_flow6.fi6_src, 0, sizeof(struct in6_addr)); fl6p->ff_flow6.fi6_sport = 0; } else switch (Obj_CType(filtp)) { case ctype_FILTER_SPEC_ipv6: /* IP6 FILTER_SPEC */ fl6p->ff_flow6.fi6_src = filtp->filt6_srcaddr; memset(&fl6p->ff_mask6.mask6_src, 0xff, sizeof(struct in6_addr)); fl6p->ff_flow6.fi6_sport = filtp->filt6_srcport; break; #ifdef filtfl6_srcaddr case ctype_FILTER_SPEC_ipv6FL: /* IP6 Flow-label FILTER_SPEC */ fl6p->ff_flow6.fi6_dport = 0; /* we don't need this */ fl6p->ff_flow6.fi6_src = filtp->filtfl6_srcaddr; memset(&fl6p->ff_mask6.mask6_src, 0xff, sizeof(struct in6_addr)); fl6p->ff_flow6.fi6_flowlabel = filtp->filtfl6_srcfl & htonl(0x000fffff); break; #endif case ctype_FILTER_SPEC_ipv6GPI: /* IPv6/GPI FILTER_SPEC */ fl6p->ff_flow6.fi6_dport = 0; /* we don't need this */ fl6p->ff_flow6.fi6_src = filtp->filtgpi6_srcaddr; memset(&fl6p->ff_mask6.mask6_src, 0xff, sizeof(struct in6_addr)); fl6p->ff_flow6.fi6_gpi = filtp->filtgpi6_srcgpi; break; default: rsvp_errno = Set_Errno(RSVP_Err_UNKNOWN_CTYPE, Obj_CType(filtp)); return (-1); } break; #endif /* USE_IPV6 */ default: rsvp_errno = Set_Errno(RSVP_Err_UNKNOWN_CTYPE, Obj_CType(dest->d_session)); return (-1); break; } return (0); } /* * discipline specific routines */ static int cbq_addflow(tc_t *tch) { IS_specbody_t *z_specp; IS_serv_hdr_t *sp; struct cbq_classinfo *cbq_clinfo; u_int bandwidth; int error; if (Obj_CType(tch->spec) != ctype_FLOWSPEC_Intserv0) return (QOPERR_ADMISSION_NOSVC); z_specp = &(tch->spec->flow_body); sp = (IS_serv_hdr_t *) &z_specp->spec_u; switch(sp->issh_service) { case GUARANTEED_SERV: if(!Allow_Guaranteed) return (QOPERR_ADMISSION_NOSVC); bandwidth = z_specp->spec_u.G_spec.Gspec_r * 8; break; case CONTROLLED_LOAD_SERV: bandwidth = z_specp->spec_u.CL_spec.CLspec_r * 8; break; default: return (QOPERR_ADMISSION_NOSVC); } /* create a leaf class */ if (tch->ifinfo->resv_class == NULL) return (QOPERR_CLASS_INVAL); cbq_clinfo = tch->ifinfo->resv_class->private; error = qop_cbq_add_class(&tch->clinfo, NULL, tch->ifinfo, tch->ifinfo->resv_class, NULL, cbq_clinfo->class_spec.priority, bandwidth, cbq_clinfo->maxdelay, cbq_clinfo->maxburst, cbq_clinfo->minburst, cbq_clinfo->av_pkt_size, cbq_clinfo->max_pkt_size, CBQ_QOS_NONE, /* XXX */ cbq_clinfo->class_spec.flags); return (error); } static int cbq_modifyflow(tc_t *tch, tc_t *otch) { IS_specbody_t *z_specp; IS_serv_hdr_t *sp; struct cbq_classinfo *cbq_clinfo; u_int bandwidth; int error; if (Obj_CType(tch->spec) != ctype_FLOWSPEC_Intserv0) return (QOPERR_ADMISSION_NOSVC); z_specp = &(tch->spec->flow_body); sp = (IS_serv_hdr_t *) &z_specp->spec_u; switch(sp->issh_service) { case GUARANTEED_SERV: if(!Allow_Guaranteed) return (QOPERR_ADMISSION_NOSVC); bandwidth = z_specp->spec_u.G_spec.Gspec_r * 8; break; case CONTROLLED_LOAD_SERV: bandwidth = z_specp->spec_u.CL_spec.CLspec_r * 8; break; default: return (QOPERR_ADMISSION_NOSVC); } error = qop_cbq_modify_class(tch->clinfo, cbq_clinfo->class_spec.priority, bandwidth, cbq_clinfo->maxdelay, cbq_clinfo->maxburst, cbq_clinfo->minburst, cbq_clinfo->av_pkt_size, cbq_clinfo->max_pkt_size, cbq_clinfo->class_spec.flags); return (error); } static int cbq_deleteflow(tc_t *tch) { int error; error = qop_delete_class(tch->clinfo); return (error); } static int hfsc_addflow(tc_t *tch) { IS_specbody_t *z_specp; IS_serv_hdr_t *sp; struct hfsc_classinfo *hfsc_clinfo; u_int bandwidth, rate, bucket_depth; struct service_curve service_curve; int error; if (Obj_CType(tch->spec) != ctype_FLOWSPEC_Intserv0) return (QOPERR_ADMISSION_NOSVC); z_specp = &(tch->spec->flow_body); sp = (IS_serv_hdr_t *) &z_specp->spec_u; switch(sp->issh_service) { case GUARANTEED_SERV: /* * convert flowspec to service curve: * m1 <- R * d <- b/R * m2 <- r * (todo: delay calculation and range checking) */ rate = z_specp->spec_u.G_spec.Gspec_r * 8; bucket_depth = z_specp->spec_u.G_spec.Gspec_b; bandwidth = z_specp->spec_u.G_spec.Gspec_R * 8; if (bandwidth < rate) bandwidth = rate; /* R should be larger than r */ service_curve.m1 = bandwidth; service_curve.d = (u_int)((double)bucket_depth * 8 / bandwidth * 1000); service_curve.m2 = rate; break; case CONTROLLED_LOAD_SERV: /* * assigned a linear service curve to controlled-load service */ rate = z_specp->spec_u.CL_spec.CLspec_r * 8; service_curve.m1 = rate; service_curve.d = 0; service_curve.m2 = rate; break; default: return (QOPERR_ADMISSION_NOSVC); } /* create a leaf class */ if (tch->ifinfo->resv_class == NULL) return (QOPERR_CLASS_INVAL); hfsc_clinfo = tch->ifinfo->resv_class->private; error = qop_hfsc_add_class(&tch->clinfo, NULL, tch->ifinfo, tch->ifinfo->resv_class, &service_curve, hfsc_clinfo->qlimit, hfsc_clinfo->flags); return (error); } static int hfsc_modifyflow(tc_t *tch, tc_t *otch) { IS_specbody_t *z_specp; IS_serv_hdr_t *sp; struct hfsc_classinfo *hfsc_clinfo; u_int bandwidth, rate, bucket_depth; struct service_curve service_curve; int error; if (Obj_CType(tch->spec) != ctype_FLOWSPEC_Intserv0) return (QOPERR_ADMISSION_NOSVC); z_specp = &(tch->spec->flow_body); sp = (IS_serv_hdr_t *) &z_specp->spec_u; switch(sp->issh_service) { case GUARANTEED_SERV: /* * convert flowspec to service curve */ rate = z_specp->spec_u.G_spec.Gspec_r * 8; bucket_depth = z_specp->spec_u.G_spec.Gspec_b; bandwidth = z_specp->spec_u.G_spec.Gspec_R * 8; if (bandwidth < rate) bandwidth = rate; /* R should be larger than r */ service_curve.m1 = bandwidth; service_curve.d = (u_int)((double)bucket_depth * 8 / bandwidth * 1000); service_curve.m2 = rate; break; case CONTROLLED_LOAD_SERV: /* * assigned a linear service curve to controlled-load service */ rate = z_specp->spec_u.CL_spec.CLspec_r * 8; service_curve.m1 = rate; service_curve.d = 0; service_curve.m2 = rate; break; default: return (QOPERR_ADMISSION_NOSVC); } hfsc_clinfo = tch->ifinfo->resv_class->private; error = qop_hfsc_modify_class(tch->clinfo, &service_curve, (HFSC_REALTIMESC|HFSC_LINKSHARINGSC)); return (error); } static int hfsc_deleteflow(tc_t *tch) { int error; error = qop_delete_class(tch->clinfo); return (error); } #ifdef LABEL u_long TC_AddLabel(int OIf, u_long rhandle, Session *dest, RSB *rp) { tc_t *tch = (tc_t*)rhandle; struct fltrinfo *fltrinfo; struct flow_filter filter; int error; /* CBQ does not create kernel state for incoming flows */ if(tch == NULL || IsNumAPI(tch->in_if) || !if_vec[tch->in_if].if_up) { return TC_OK; } rsvp_errno = 0; if (rsvp2altq_label(rp , dest , &filter) != 0) return(TC_ERROR); if ((error = qop_add_label(&fltrinfo, tch->clinfo, NULL, &filter, NULL)) != 0) { rsvp_errno = Set_Errno(RSVP_Err_TC_SYS_ERROR, error); return (TC_ERROR); } return ((u_long)fltrinfo); } static int rsvp2altq_label(RSB *rp, Session *dest, struct flow_filter *flp) { memset(flp, 0, sizeof(struct flow_filter)); switch (Obj_CType(dest->d_session)) { case ctype_SESSION_ipv4: case ctype_SESSION_ipv4GPI: flp->ff_flow.fi_family = AF_INET; flp->ff_flow.fi_dst = dest->d_session->sess4_addr; flp->ff_mask.mask_dst.s_addr = 0xffffffff; flp->ff_flow.fi_dport = dest->d_session->sess4_port; flp->ff_flow.fi_proto = dest->d_session->sess4_prot; flp->ff_flow.fi_src = rp->rs_filtstar->fst_p->fst_filtp->filt4_srcaddr; flp->ff_mask.mask_src.s_addr = 0xffffffff; flp->ff_flow.fi_sport = rp->rs_filtstar->fst_p->fst_filtp->filt4_srcport; flp->ff_flow.fi_label = rp->rs_labelout; break; case ctype_SESSION_lsp_tunv4: flp->ff_flow.fi_family = AF_INET; flp->ff_flow.fi_dst = dest->d_session->sesslsp_addr; flp->ff_mask.mask_dst.s_addr = 0xffffffff; flp->ff_flow.fi_dport = 0; flp->ff_flow.fi_proto = 0; flp->ff_flow.fi_src.s_addr = 0; flp->ff_mask.mask_src.s_addr = 0; flp->ff_flow.fi_sport = 0; flp->ff_flow.fi_label = rp->rs_labelout; break; default: rsvp_errno = Set_Errno(RSVP_Err_UNKNOWN_CTYPE, Obj_CType(dest->d_session)); return (-1); break; } return (0); } #endif