PDA

View Full Version : Usare una variabile del kernel di linux


francowr
07-06-2006, 22:00
Ciao a tutti,
ho bisogno di modificare una variabile del kernel di linux (che si chiama tokens) tramite un mio programma c in questo modo:
"chiedo" al kernel il valore di tokens attuale;
quindi faccio tokens=min(tokens, costante);
infine "restituisco" al kernel la variabile tokens calcolata con min.
Ma come posso fare a far questo? Non so dove metter le mani per modificar il kernel di linux.
CIAO!

ilsensine
08-06-2006, 13:39
Dove sarebbe questa variabile? (in che file è dichiarata?)

Quello che puoi fare è crearti un modulo che modifica la variabile, solo che un modulo non ha a disposizione tutti gli oggetti del kernel, ma solo quelli "esportati".

francowr
09-06-2006, 01:10
Ciao, grazie per la risposta;
cmq la variabile è dichairata nel file tbf.c (che fa parte del kernel di linux);

ok posso crearmi un modulo, ho letto su internet utilizzando al funzione ioctl, ma non so come; qualcuno di voi sa dirmi con che "sintassi" usare questa ioctl; devo richiamare proprio il file tbf.c???
GRAZIE
CIAO

ilsensine
09-06-2006, 08:16
Non c'è nessun file tbf.c nel kernel linux...almeno, non in quelli che ho sottomano

francowr
09-06-2006, 10:15
No tbf.c non è un file del kernel, è il file c che verrà compilato con il kernel, dove si trova la variabile tokens; il tbf è una disciplina di coda usata dal traffic control di linux (comando tc); a me serve quella variabile;
CIAO!

jappilas
09-06-2006, 10:29
forse adesso ho male intepretato la domanda, o ricordo male quello che lessi un po' di tempo fa, o entrambe
ma mi pareva che il sysfs (http://www.linux.it/~rubini/docs/sysfs/sysfs.html) fosse stato aggiunto al kernel proprio per questo genere di cose... :stordita:

ilsensine
09-06-2006, 11:38
No tbf.c non è un file del kernel, è il file c che verrà compilato con il kernel, dove si trova la variabile tokens; il tbf è una disciplina di coda usata dal traffic control di linux (comando tc); a me serve quella variabile;
CIAO!
Ora che vedo, c'è il file net/sched/sch_tbf.c...ha qualcosa a che vedere con quella tecnica?

Comunque se il file tbf.c è tuo, puoi modificarlo per rendere quella variabile accessibile da userspace. Il sysfs potrebbe essere una soluzione, ma ce ne sono altre (miscdevice, procfs, debugfs, connector...)

francowr
09-06-2006, 12:42
si il file è quello;
devo modificarlo e ricompilare il kernel però vero? dovrei scaricare il kernel di linux modificare quel file e ricompilare... temo che impallo tutto, ma vedremo...

cmq sysfs è semplice come sintassi?

francowr
09-06-2006, 15:52
ok no il kernel sorgente già lo ho in usr/src /linux
mi manca la sintassi della funzione;
non esiste una specie di "printf.." che mi permette di tiarrae fuori la variabile dal kernel lavorarci e poi un altra printf che me la fa riporta dentro al kernel

francowr
09-06-2006, 16:08
Leggevo ora su internet che esiste una "printk" che mi permette di porta fuori variabile del kernel; mi resta da capire come...
Se qualcuno lo sa in breve...

ilsensine
12-06-2006, 08:00
La sintassi di printk è come printf. Il problema è un altro: la tua variabile "tokens" non è globale, ma fa parte della struttura tbf_sched_data, che da quello che vedo può benissimo non essere unica. Come puoi vedere, ai vari metodi del file viene passata una struct Qdisc *, dalla quale viene estratta la tbf_sched_data. Quindi ci sarà un "tokens" per ogni Qdisc che viene aperta.
Una qdisc viene aperta in net/sched/sch_generic.c, in qdisc_alloc, e distrutta in qdisc_destroy. Puoi modificare queste funzioni in modo da registrare e distruggere dei procfile o sysfsfile se ops->id è pari a "tbf". Non bello, ma abbastanza veloce a farsi.

francowr
14-06-2006, 11:15
Ti ringrazio molto per la risposta, l'idea a questo punto è quella di provare con un proc file. Sai dove posso trovare del codice "fac-simile" per quello che devo fare e soprattutto dove e come inserire il modulo (non so se è così che si dice, sono alle prime armi con la programmazione del kernel)
grazie
ciao

ilsensine
14-06-2006, 11:55
Se sei alle prime armi, non dovresti imbatterti in questa storia. Lo devi fare per studio o per lavoro?

Tieni conto che non te la cavi con un modulo, ma devi modificare esplicitamente le parti del kernel che gestiscono le qdisc.

francowr
15-06-2006, 01:14
Lo faccio per studio... purtroppo... sono a poco dalla tesi e è sorto questo problema...
Anche secondo me è ai limite dell'impossibile che sappia ste cose "di botto"

Io vorrei cercare di inserire nello stesso module_init del tbf anche il codice del module_init che crea un file proc, e passare al modulo "write" del file la struttura Qdisc; dovebdo aprire da programma (mio) una sola Qdisc alla volta magari così me la cavo...
Che ne pensi?

ilsensine
15-06-2006, 13:33
Ti do il la:

--- linux-2.6.17-rc4/net/sched/sch_tbf.c.org 2006-06-14 13:31:52.000000000 +0000
+++ linux-2.6.17-rc4/net/sched/sch_tbf.c 2006-06-15 14:32:39.000000000 +0000
@@ -135,6 +135,43 @@
#define L2T(q,L) ((q)->R_tab->data[(L)>>(q)->R_tab->rate.cell_log])
#define L2T_P(q,L) ((q)->P_tab->data[(L)>>(q)->P_tab->rate.cell_log])

+static ssize_t class_device_tokens_show(struct class_device *cdev, char *page)
+{
+ struct net_device *dev = container_of(cdev, struct net_device, class_dev);
+ struct tbf_sched_data *q;
+ long tokens;
+
+ spin_lock_bh(&dev->queue_lock);
+ q = qdisc_priv(dev->qdisc);
+ tokens = q->tokens;
+ spin_unlock_bh(&dev->queue_lock);
+ return sprintf(page, "%ld", tokens);
+}
+
+static ssize_t class_device_tokens_store(struct class_device *cdev, const char *page, size_t count)
+{
+#if 0
+ long tokens;
+ struct net_device *dev = container_of(cdev, struct net_device, class_dev);
+ struct Qdisc *sch;
+ struct tbf_sched_data *q;
+
+ if (count==0)
+ return -EINVAL;
+ if (page[count-1]!='\0' && page[count-1]!='\n')
+ return -EINVAL;
+
+ tokens = simple_strtol(page, NULL, 0);
+ spin_lock_bh(&dev->queue_lock);
+ q = qdisc_priv(dev->qdisc);
+ q->tokens = tokens;
+ spin_unlock_bh(&dev->queue_lock);
+#endif
+ return count;
+}
+
+static CLASS_DEVICE_ATTR(tokens, 0644, class_device_tokens_show, class_device_tokens_store);
+
static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
struct tbf_sched_data *q = qdisc_priv(sch);
@@ -265,6 +302,8 @@
{
struct tbf_sched_data *q = qdisc_priv(sch);

+ class_device_remove_file(&sch->dev->class_dev, &class_device_attr_tokens);
+
qdisc_reset(q->qdisc);
sch->q.qlen = 0;
PSCHED_GET_TIME(q->t_c);
@@ -370,6 +409,7 @@
static int tbf_init(struct Qdisc* sch, struct rtattr *opt)
{
struct tbf_sched_data *q = qdisc_priv(sch);
+ int fail;

if (opt == NULL)
return -EINVAL;
@@ -381,7 +421,11 @@

q->qdisc = &noop_qdisc;

- return tbf_change(sch, opt);
+ fail = tbf_change(sch, opt);
+ if (!fail)
+ class_device_create_file(&sch->dev->class_dev, &class_device_attr_tokens);
+
+ return fail;
}

static void tbf_destroy(struct Qdisc *sch)


nb la patch è scorretta per diversi motivi, ma ti da il via su dove mettere mano.
Non ho neanche potuto testarla in quanto non ho idea di come gestire e avviare queste qdisc...sono cose sconosciute per me :fagiano:

francowr
16-06-2006, 00:23
Ti ringrazio davvero molto, adesso compincio a studiarmela bene, anche perchè a dirti il vero a prima vista non ci ho capito nulla.
Come faccioa ricompilare un modulo del kernel? sai il comando che devo usare?
grazie ancora molto, mi hai dato davvero un grande aiuto!
CIAO!

francowr
16-06-2006, 00:26
Cmq complimenti davvero per la tua preparazione!
Sono curioso di conoscere dove hai imparato queste cose!

ilsensine
16-06-2006, 08:38
Se i sorgenti del tuo kernel corrente sono installati correttamente, basta un semplice
make modules
per ricompilare tutti i moduli, compreso quello che ti interessa che troverai in net/sched/sch_tbf.ko. Puoi inserirlo selettivamente con insmod, senza dover sovrascrivere il modulo originale.

Ti elenco i problemi che vanno risolti o tenuti presente. Visto che non conosco affatto qeuesta parte del kernel, sono solo ipotesi, ma credo siano fondate:
- class_device_create_file e class_device_remove_file vengono probabilmente eseguite sotto spinlock e BH disabilitate. Vietato. Se hai culo, non succede nulla. Visto che ti serve solo per dei test, se funziona lasciamole così come sono.
- Si hanno effetti impredicibili se vengono create due qdisc tbf sulla stessa interfaccia di rete. E' ammessa una tbf per interfaccia.
- Nelle class_device_tokens_show e class_device_tokens_store assumono che dev->qdisc (che presumo sia la qdisc "attiva") sia la tbf. In realtà ci sono altri campi che possono contenere qdisc, tra cui una lista di qdisc -- a quanto pare possono esserci più qdisc associate contemporaneamente a una interfaccia di rete. L'assunzione che dev->qdisc sia la tbf andrebbe verificata.
- I classfile sono creati in /sys/class/net/<nome interfaccia>/tokens. E' una violazione di layer, in quanto tocchiamo una regione che compete a un altro driver (di un altro sottosistema per giunta); non dovrebbe avere effetti collaterali di per se, a meno di non fare cose strane.

francowr
16-06-2006, 11:38
Non so davvero come rinraziarti! Ora vedo!
CIAO!!!!!

ilsensine
16-06-2006, 11:40
Fatti aiutare da qualche assistente all'università...altrimenti invece che una tesi sul networking rischi di fare una tesi sul kernel linux

francowr
16-06-2006, 12:43
Esatto, networking a parte, sto facendo una tesi di programmazione...
All'inizio della tesi sapevo a malapena le basi + limitate del c... ora mi imbatto sul kernel di linux

Chiedo ogni volta una mano "sul codice" ma ormai mi hanno delegato la cosa; non puoi capi quanto sia amareggiato da sta cosa....

Mi sembra assurdo che una persona su un forum trovi tempo per scrivermi una bozza del codice (quando alla fine proprio non te ne potrebbe frega niente e non vorresti butta tempo per questa cosa...), mentre in laboratorio non me scrivono manco una riga...