Forum: Mikrocontroller und Digitale Elektronik Datenkapselung bei Protokollen, Algorithmus gesucht


von Stephan W. (sir_wedeck)


Lesenswert?

Hallo Leute,
ich bin auf der Suche nach einem "guten" Algorithmus für die 
Datenkapselung bei verschiedenen Protokolle. Also das weiterleiten und 
ein betten der Nutzdaten in den Protokollen.

Ich möchte mein Problem anhand des SNMP-Protokoll erklären.
Wenn ich Daten von Ethernet (bzw SLIP) bekomme, kann ich den Stream, 
anhand der Heads dekodieren und bearbeiten. Die Telegramme werden in 
Richtung SNMP immer kleiner und ich kann den "Start"-Pointer und die 
Länge an die anderen Protokolle weiterleiten. (relative einfach)

Wie sieht es jetzt in die andere Richtung aus:
Das Telegramm vom SNMP muss nun von den unteren Schichten mit ihren 
Headern erweitert werden! (Das Telegramm wird größer)
Ich hab mich etwas umgesehen, aber eine gute Lösung konnte ich für eine 
MC-Implementierung nicht finden.

1) Lösung
Wenn ich nun den SNMP Datensatz an den Anfang des Buffers schreiben 
würde, könnte ich keine weiteren Header schreiben, ohne das ich den 
SNMP-Datensatz nach hinten verschieben muss.(nicht gut, kostet "viel 
Zeit" pro Schicht!)

2) Lösung
Diese hab ich sehr häufig gefunden, aber ist mir zu direkt.
Der SNMP-Handler schreibt ALLE Schichten in einem Rutsch, d.h. er macht 
Ethernet, IP, udp. Das möchte ich nicht, jede Schicht sollte für sich 
autark sein!

3) Lösung
Eine doppelt oder einfach verkettete Liste! Fand ich sehr gut, denn das 
Telegramm kann somit in beide Richtungen wachsen und ist somit sehr 
autark. (aber nicht für MC geeignet, selbst mit einer statischen Liste 
ohne malloc kann ich mir es nicht wirklich effektiv für einen MC 
vorstellen. (Speicher, Verwaltung usw.)

4) Lösung
Die ist mir noch eingefallen, aber ein paar Bekannte meinten schon es 
wäre etwas zu sehr an den Haaren herbei gezogen.
Ich schreibe die Nutzdaten vom SNMP Rückwerts in den Buffer, die Heads 
der anderen Protokollen auch, somit wächst das Telegramm immer am ende 
weiter. Bei der Ausgabe muss ich das Telegramm dann auch Rückwerts 
ausgeben. (naja)

5) Lösung
Was auch noch sehr verbreitet war, war das alle schichten sich einen 
Buffer dynamisch anfordern und den alten Inhalt jeweil koperen. (wie 1, 
viel Zeit, hab kein malloc!)

Was gibs denn noch so auf dem Markt?
Was hab ich übersehen? Warum werden hier bei den Projekten mit AVR und 
INET immer die direkte Methode bevorzugt? (L.2)

Das hat nämlich auch mein ehemaliger Kollege so gemacht, jetzt kann ich 
eine Menge Protokolle neu überarbeiten weil sich ein paar Schichten 
geändert haben.

Ich hoffe Ihr habt noch was im Ärmel. Danke.
mfg
Stephan

:
von Uwe .. (uwegw)


Lesenswert?

Ich wäre (allerdings ohne selbst jemals einen Protokollstack geschrieben 
zu haben) für Lösung 3), also eine Art verkettete Liste.
Wobei man sich noch überlegen könnte, ob wirklich alles dynamisch 
angelegt werden muss. Speziell für die Schichten mit festen Datenlängen 
würden ja statische Buffer ausreichen.
Und für die Schichten mit variabler Länge dann eben dynamisch anlegen 
und aus den statischen Buffern per Pointer verweisen, oder (wenn sich 
die Länge grob eingrenzen lässt) sogar auch statisch mit 
worst-case-Länge.

von Dennis S. (bzzzt)


Lesenswert?

Wenn du weißt, wie groß deine Header insgesamt höchstens werden, dann 
reservierst du halt diesen Platz für den schlimmsten Fall vor der 
Stelle, an der der SNMP-Handler seine Nutzdaten hinschreibt.
Jede Schicht packt halt ihren Header vor die Nutzdaten der verkapselten 
Schicht und fertig ist die Kiste.

Der Overhead hält sich in Grenzen und du sparst dir die Zeiger, die du 
dir bei verketteten Listen merken musst. Und zum Schluss liegt das Paket 
in einem Stück im Speicher.

Macht uIP gewissermaßen so, da gibt es halt einen Zeiger für die 
Nutzdaten, und die Header liegen davor (was bei Ethernet+IP in deren 
Spezialfall einfach ist, weil sie eine feste Länge haben).

von Purzel H. (hacky)


Lesenswert?

Mit einem microcontroller macht man gerne alle schichten auf's mal. Denn 
man moechte damit fertig werden, zwar schnell, und zuverlaessig. 
Gleichzeitig moechte man dynamische Datenstrukturen vermeiden. Also 
keine Malloc und dergleichen. Unter berucksichtigung dieser 
Randbedingungen ist man sofort bei der direkten implementation.

von Stephan W. (sir_wedeck)


Lesenswert?

Nabend,
danke für die Antworten.

@Oktav Oschi
Ja das sehe ich hier bei mir auch, aber nun muss ich jedes Protokoll neu 
bearbeiten, weil sich das NET-IF geändert hat und noch 2 neue 
Bridge(Brücken?)-Protokolle hinzukommen. Jetzt macht die direkte Methode 
einen ziemlichen Arbeitsaufwand. Da ich nicht der Entwickler war und der 
Kollege keine Doku gemacht hat, habe ich besonderen Spaß.

@Dennis S.
Das geht nur wenn man weiß was drunter an Schichten liegt.
siehe Lösung 2. ob ich Platz mache oder es direkt mache, ist für mich 
das gleiche.

@Uwe ...
Ja, so gehts mir auch. Ich habe zwar schon einige Protokolle 
programmiert aber die hatten nur 1 oder 2 Schichten (und festes 
Interface), da war das nicht so wild.

Das Problem ist auch das zu den bestehenden Protokollen noch einige 
hinzukommen sollen und diese dann wieder per Konfiguration aller #ifdef 
auch wieder ausgeschlossen werden sollen.

Deshalb wäre mir eine Weiche-Kopplung der Protokolle untereinander 
lieber.

mfg
Stephan

von Stephan W. (sir_wedeck)


Lesenswert?

Hi Leute,
ab ich echt schon alle Möglichkeiten erkannt?
Kennt keiner noch andere Methoden dafür?

Wieso wird nun die "Direkte" Methode bevorzugt?
Ich muss deshalb viele "ifdef's" einbauen, um die Anzahl der Protokolle 
und Interface konfigurierbar zu machen. (macht den Code nicht gerade 
leicht zu lesen)

Wir haben hier bei uns, 6 Geräte-Familien die verschieden Stacks 
benötigen und es muss doch möglich sein dafür was passendes zu 
schreiben.
Oder ich schreibe, 6 mal einen Neuen Stack, was aber keinen wirklich 
glücklich machen wird.

Was mir wirklich sorgen macht sind nicht die Protokolle selber, sondern 
eher die Interface von denen ich sie bekomme: Funk, RS232, USB, Ethernet 
usw.

mfg
Stephan

von Alex (Gast)


Lesenswert?

Ich werfe jetzt einfach mal das Stichwort 'code generieren' in die 
Runde. Die einzelnen Stacks würden dann während dem Buildprozess 
generiert werden. Das würde die #ifdefs ersetzen.


Wie das dann genau aussehen wird, weiß ich allerdings auch noch nicht.

von S. J. (stj)


Lesenswert?

Hallo,

Ich weis nicht welchen µC du benutzt, aber wenns ein etwas besserer ist 
dann kannst du darüber nachdenken, die einzelnen Protokollschichten in 
getrennten Arrays zu "bauen", und diesen dann per DMA an die Hardware zu 
schicken. Der DMA-Controller kann dann die einzelnen Schichten in der 
richtigen Reihenfolge zusammenbasteln und rausschicken.

Nur beim einlesen musst du dir was anderes überlegen, aber das sollte 
auch nicht das Problem sein, das sich die einzelnen Schichten die Daten 
die sie brauchen, aus dem Empfangspuffer raussuchen.

Gruß,
Stephan

von Simon K. (simon) Benutzerseite


Lesenswert?

Ich habe schon mal angefangen einen Stack zu schreiben. Am sinnvollsten 
ist es, wenn man annimmt, dass alle Header, die noch vor das (in diesem 
Falle SNMP) Paket geschrieben werden müssen, eine maximale oder 
konstante Größe haben!
Wenn du nun das Antwortpaket schreibst (in einer oberen Schicht), holst 
du dir vom Stack die Adresse für den Schreibpuffer, wo die Antwort 
reinkommt. Der Stack berechnet diese Adresse mit Hilfe seines 
(statischen) Sende- und Empfangspuffers PLUS die Worst-Case Größe aller 
Header, die noch vor das Paket gesetzt werden müssen.

z.B. Headergrößen
Ethernet: 14  Bytes max.
IP: 60 Bytes max.
UDP: 8 Bytes max.

Dann dürfte die SNMP Anwendung an der Adresse Puffer + (14 + 60 +8) 
anfangen das SNMP Datagramm zu schreiben.
Dann muss man nur noch konkret in jedem Falle schauen wie groß IP, UDP 
und Ethernet Header sind und den tatsächlichen Startpunkt herausfinden, 
sodass der Header direkt an den zuvorgeschriebenen Header anliegt.

Das sollte am einfachsten für kleine Mikrocontroller zu realisieren 
sein. Bedenke, dass die unterstützten Protokoll-Features für den Stack 
bei kleinen Mikrocontrollern sich nicht dauernd ändern. Sodass die 
tatsächlich genutzten (nicht die Worst-Case) Headergrößen zur 
Compile-Zeit komplett fix sind und sich nicht mehr ändern können (außer 
in Ausnahmefällen). Somit ist eigentlich diese Variante am effektivsten, 
wenn man mit defines arbeitet.
Hat man den Stack einmal per defines konfiguriert, steht die nötige 
Größe des Gesamtpuffers, sowie die Startpunkte der einzelnen Protokolle 
fest und der Compiler optimiert.
So Sachen wie Listen sind eigentlich Overkill. Die braucht man eher bei 
dynamisch sich ändernden Daten.
Sie würden zwar das Programmieren vereinfachen, weil man dann nicht soo 
haargenau jeden Fall auf Buffer-Overflows durchprüfen muss, aber das 
Argument zählt nicht ;-)

Im Übrigen ist das Selberschreiben eines Full-Blown oder sogar nur eines 
Minimum Netzwerk-Stacks eine Höllenaufgabe. Das sieht am Anfang leicht 
aus, macht auch Spaß. Aber danach verbringt man nur noch Zeit mit 
Debuggen via Wireshark o.ä. um die verfluchten (aber dennoch genialen) 
TCP Sequenz und Acknummern hinzubekommen bspw. Oder um die nötigen TCP 
MSS Optionen korrekt zu setzen oder (viel schlimmer) Optionen von einem 
anderen undefinierten Netzwerk-Stack zu erkennen und anzuwenden.

von Peter D. (peda)


Lesenswert?

Wenn Du mit Stack das Protokollformat meinst, das läßt sich nicht 
vermeiden, daß das bei den einzelnen Interfaces völlig unterschiedlich 
ist. Sonst gäbe es ja unterschiedliche Interfaces nicht.
Du mußt also jedes Protokoll für sich parsen, um die Informationen 
auszulesen.

Wenn Du ein Protokoll aber nur transportieren willst, ohne den Inhalt 
auszuwerten, dann definiere einfach ein Universalpaket, welches 
beliebige Paketlängen verpacken kann.
Z.B. beim CAN-Bus kann man immer nur 8 Byte versenden. Um darin andere 
Pakete einzupacken, reserviert man das 1. Byte als Kennzeichen für ein 
Fremdpaket und das 2. als Paketzähler. Jeder CAN-Frame kann dann noch 
bis zu 6 Byte Fremddaten enthalten. Und dann soviel CAN-Pakete basteln, 
wie nötig.

Man sollte aber nicht ein schon verpacktes Protokoll nochmal verpacken.
Wäre quasi so, wie SPI in Software über nen PCF8574 nachzubilden (dauert 
ewig).


Peter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.