@@ -121,6 +121,98 @@ struct sock_filter dhcp_sock_filter [] = {
121121 BPF_STMT (BPF_RET + BPF_K, 0 ),
122122};
123123
124+ // / The following structure defines a Berkeley Packet Filter program to perform
125+ // / packet filtering. The program operates on IPoIB pseudo packets. To help with
126+ // / interpretation of the program, for the types of packets we are interested
127+ // / in, the header layout is:
128+ // /
129+ // / 20 bytes Destination Interface Address
130+ // / 2 bytes Source Ethernet Address
131+ // / 2 bytes Reserved/Unused
132+ // /
133+ // / The rest is identical to aboves Ethernet-Based packets
134+ // /
135+ // / Each instruction is preceded with the comments giving the instruction
136+ // / number within a BPF program, in the following format: #123.
137+
138+ struct sock_filter dhcp_sock_filter_ib [] = {
139+ // Make sure this is an IP packet: check the half-word (two bytes)
140+ // at offset 20 in the packet (the IPoIB pseudo packet type). If it
141+ // is, advance to the next instruction. If not, advance 11
142+ // instructions (which takes execution to the last instruction in
143+ // the sequence: "drop it").
144+ // #0
145+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, IPOIB_PACKET_TYPE_OFFSET),
146+ // #1
147+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0 , 11 ),
148+
149+ // Make sure it's a UDP packet. The IP protocol is at offset
150+ // 9 in the IP header so, adding the IPoIB packet header size
151+ // of 24 bytes gives an absolute byte offset in the packet of 33.
152+ // #2
153+ BPF_STMT (BPF_LD + BPF_B + BPF_ABS,
154+ IPOIB_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
155+ // #3
156+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0 , 9 ),
157+
158+ // Make sure this isn't a fragment by checking that the fragment
159+ // offset field in the IP header is zero. This field is the
160+ // least-significant 13 bits in the bytes at offsets 6 and 7 in
161+ // the IP header, so the half-word at offset 30 (6 + size of
162+ // IPoIB header) is loaded and an appropriate mask applied.
163+ // #4
164+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, IPOIB_HEADER_LEN + IP_FLAGS_OFFSET),
165+ // #5
166+ BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff , 7 , 0 ),
167+
168+ // Check the packet's destination address. The program will only
169+ // allow the packets sent to the broadcast address or unicast
170+ // to the specific address on the interface. By default, this
171+ // address is set to 0 and must be set to the specific value
172+ // when the raw socket is created and the program is attached
173+ // to it. The caller must assign the address to the
174+ // prog.bf_insns[8].k in the network byte order.
175+ // #6
176+ BPF_STMT (BPF_LD + BPF_W + BPF_ABS,
177+ IPOIB_HEADER_LEN + IP_DEST_ADDR_OFFSET),
178+ // If this is a broadcast address, skip the next check.
179+ // #7
180+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff , 1 , 0 ),
181+ // If this is not broadcast address, compare it with the unicast
182+ // address specified for the interface.
183+ // #8
184+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x00000000 , 0 , 4 ),
185+
186+ // Get the IP header length. This is achieved by the following
187+ // (special) instruction that, given the offset of the start
188+ // of the IP header (offset 24) loads the IP header length.
189+ // #9
190+ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, IPOIB_HEADER_LEN),
191+
192+ // Make sure it's to the right port. The following instruction
193+ // adds the previously extracted IP header length to the given
194+ // offset to locate the correct byte. The given offset of 16
195+ // comprises the length of the IPoIB header (24) plus the offset
196+ // of the UDP destination port (2) within the UDP header.
197+ // #10
198+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, IPOIB_HEADER_LEN + UDP_DEST_PORT),
199+ // The following instruction tests against the default DHCP server port,
200+ // but the action port is actually set in PktFilterBPF::openSocket().
201+ // N.B. The code in that method assumes that this instruction is at
202+ // offset 11 in the program. If this is changed, openSocket() must be
203+ // updated.
204+ // #11
205+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0 , 1 ),
206+
207+ // If we passed all the tests, ask for the whole packet.
208+ // #12
209+ BPF_STMT (BPF_RET + BPF_K, (u_int)-1 ),
210+
211+ // Otherwise, drop it.
212+ // #13
213+ BPF_STMT (BPF_RET + BPF_K, 0 ),
214+ };
215+
124216}
125217
126218using namespace isc ::util;
@@ -161,16 +253,30 @@ PktFilterLPF::openSocket(Iface& iface,
161253 struct sock_fprog filter_program;
162254 memset (&filter_program, 0 , sizeof (filter_program));
163255
164- filter_program.filter = dhcp_sock_filter;
165- filter_program.len = sizeof (dhcp_sock_filter) / sizeof (struct sock_filter );
256+ if (iface.getHWType () == HTYPE_INFINIBAND) {
257+ filter_program.filter = dhcp_sock_filter_ib;
258+ filter_program.len = sizeof (dhcp_sock_filter_ib) / sizeof (struct sock_filter );
259+
260+ // Configure the filter program to receive unicast packets sent to the
261+ // specified address. The program will also allow packets sent to the
262+ // 255.255.255.255 broadcast address.
263+ dhcp_sock_filter_ib[8 ].k = addr.toUint32 ();
264+
265+ // Override the default port value.
266+ dhcp_sock_filter_ib[11 ].k = port;
267+ } else {
268+ filter_program.filter = dhcp_sock_filter;
269+ filter_program.len = sizeof (dhcp_sock_filter) / sizeof (struct sock_filter );
166270
167- // Configure the filter program to receive unicast packets sent to the
168- // specified address. The program will also allow packets sent to the
169- // 255.255.255.255 broadcast address.
170- dhcp_sock_filter[8 ].k = addr.toUint32 ();
271+ // Configure the filter program to receive unicast packets sent to the
272+ // specified address. The program will also allow packets sent to the
273+ // 255.255.255.255 broadcast address.
274+ dhcp_sock_filter[8 ].k = addr.toUint32 ();
275+
276+ // Override the default port value.
277+ dhcp_sock_filter[11 ].k = port;
278+ }
171279
172- // Override the default port value.
173- dhcp_sock_filter[11 ].k = port;
174280 // Apply the filter.
175281 if (setsockopt (sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_program,
176282 sizeof (filter_program)) < 0 ) {
@@ -264,7 +370,21 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
264370 Pkt4Ptr dummy_pkt = Pkt4Ptr (new Pkt4 (DHCPDISCOVER, 0 ));
265371
266372 // Decode ethernet, ip and udp headers.
267- decodeEthernetHeader (buf, dummy_pkt);
373+ if (iface.getHWType () == HTYPE_INFINIBAND) {
374+ decodeIPoIBHeader (buf, dummy_pkt);
375+
376+ // The IPoIB header does not contain the local address.
377+ // Set it from the interface instead.
378+ if (iface.getMacLen () != HWAddr::INFINIBAND_HWADDR_LEN) {
379+ isc_throw (SocketReadError,
380+ " Invalid local hardware address size for IPoIB interface." );
381+ }
382+ HWAddrPtr hwaddr (new HWAddr (iface.getMac (), iface.getMacLen (),
383+ iface.getHWType ()));
384+ dummy_pkt->setLocalHWAddr (hwaddr);
385+ } else {
386+ decodeEthernetHeader (buf, dummy_pkt);
387+ }
268388 decodeIpUdpHeader (buf, dummy_pkt);
269389
270390 // Read the DHCP data.
@@ -304,11 +424,14 @@ PktFilterLPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
304424 pkt->setLocalHWAddr (hwaddr);
305425 }
306426
307-
308- // Ethernet frame header.
309- // Note that we don't validate whether HW addresses in 'pkt'
310- // are valid because they are checked by the function called.
311- writeEthernetHeader (pkt, buf);
427+ if (iface.getHWType () == HTYPE_INFINIBAND) {
428+ writeIPoIBHeader (iface, pkt, buf);
429+ } else {
430+ // Ethernet frame header.
431+ // Note that we don't validate whether HW addresses in 'pkt'
432+ // are valid because they are checked by the function called.
433+ writeEthernetHeader (pkt, buf);
434+ }
312435
313436 // IP and UDP header
314437 writeIpUdpHeader (pkt, buf);
0 commit comments