@@ -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 Source Interface Address
130+ // / 2 bytes Packet Type
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 26
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;
@@ -169,16 +261,30 @@ PktFilterLPF::openSocket(Iface& iface,
169261 struct sock_fprog filter_program;
170262 memset (&filter_program, 0 , sizeof (filter_program));
171263
172- filter_program.filter = dhcp_sock_filter;
173- filter_program.len = sizeof (dhcp_sock_filter) / sizeof (struct sock_filter );
264+ if (iface.getHWType () == HTYPE_INFINIBAND) {
265+ filter_program.filter = dhcp_sock_filter_ib;
266+ filter_program.len = sizeof (dhcp_sock_filter_ib) / sizeof (struct sock_filter );
267+
268+ // Configure the filter program to receive unicast packets sent to the
269+ // specified address. The program will also allow packets sent to the
270+ // 255.255.255.255 broadcast address.
271+ dhcp_sock_filter_ib[8 ].k = addr.toUint32 ();
174272
175- // Configure the filter program to receive unicast packets sent to the
176- // specified address. The program will also allow packets sent to the
177- // 255.255.255.255 broadcast address.
178- dhcp_sock_filter[8 ].k = addr.toUint32 ();
273+ // Override the default port value.
274+ dhcp_sock_filter_ib[11 ].k = port;
275+ } else {
276+ filter_program.filter = dhcp_sock_filter;
277+ filter_program.len = sizeof (dhcp_sock_filter) / sizeof (struct sock_filter );
278+
279+ // Configure the filter program to receive unicast packets sent to the
280+ // specified address. The program will also allow packets sent to the
281+ // 255.255.255.255 broadcast address.
282+ dhcp_sock_filter[8 ].k = addr.toUint32 ();
283+
284+ // Override the default port value.
285+ dhcp_sock_filter[11 ].k = port;
286+ }
179287
180- // Override the default port value.
181- dhcp_sock_filter[11 ].k = port;
182288 // Apply the filter.
183289 if (setsockopt (sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_program,
184290 sizeof (filter_program)) < 0 ) {
@@ -315,7 +421,21 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
315421 Pkt4Ptr dummy_pkt = Pkt4Ptr (new Pkt4 (DHCPDISCOVER, 0 ));
316422
317423 // Decode ethernet, ip and udp headers.
318- decodeEthernetHeader (buf, dummy_pkt);
424+ if (iface.getHWType () == HTYPE_INFINIBAND) {
425+ decodeIPoIBHeader (buf, dummy_pkt);
426+
427+ // The IPoIB header does not contain the local address.
428+ // Set it from the interface instead.
429+ if (iface.getMacLen () != HWAddr::INFINIBAND_HWADDR_LEN) {
430+ isc_throw (SocketReadError,
431+ " Invalid local hardware address size for IPoIB interface." );
432+ }
433+ HWAddrPtr hwaddr (new HWAddr (iface.getMac (), iface.getMacLen (),
434+ iface.getHWType ()));
435+ dummy_pkt->setLocalHWAddr (hwaddr);
436+ } else {
437+ decodeEthernetHeader (buf, dummy_pkt);
438+ }
319439 decodeIpUdpHeader (buf, dummy_pkt);
320440
321441 auto v4_len = buf.getLength () - buf.getPosition ();
@@ -379,11 +499,14 @@ PktFilterLPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
379499 pkt->setLocalHWAddr (hwaddr);
380500 }
381501
382-
383- // Ethernet frame header.
384- // Note that we don't validate whether HW addresses in 'pkt'
385- // are valid because they are checked by the function called.
386- writeEthernetHeader (pkt, buf);
502+ if (iface.getHWType () == HTYPE_INFINIBAND) {
503+ writeIPoIBHeader (iface, pkt, buf);
504+ } else {
505+ // Ethernet frame header.
506+ // Note that we don't validate whether HW addresses in 'pkt'
507+ // are valid because they are checked by the function called.
508+ writeEthernetHeader (pkt, buf);
509+ }
387510
388511 // IP and UDP header
389512 writeIpUdpHeader (pkt, buf);
0 commit comments