@@ -121,6 +121,98 @@ struct sock_filter dhcp_sock_filter [] = {
121
121
BPF_STMT (BPF_RET + BPF_K, 0 ),
122
122
};
123
123
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
+
124
216
}
125
217
126
218
using namespace isc ::util;
@@ -161,16 +253,30 @@ PktFilterLPF::openSocket(Iface& iface,
161
253
struct sock_fprog filter_program;
162
254
memset (&filter_program, 0 , sizeof (filter_program));
163
255
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 );
166
270
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
+ }
171
279
172
- // Override the default port value.
173
- dhcp_sock_filter[11 ].k = port;
174
280
// Apply the filter.
175
281
if (setsockopt (sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_program,
176
282
sizeof (filter_program)) < 0 ) {
@@ -264,7 +370,21 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
264
370
Pkt4Ptr dummy_pkt = Pkt4Ptr (new Pkt4 (DHCPDISCOVER, 0 ));
265
371
266
372
// 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
+ }
268
388
decodeIpUdpHeader (buf, dummy_pkt);
269
389
270
390
// Read the DHCP data.
@@ -304,11 +424,14 @@ PktFilterLPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
304
424
pkt->setLocalHWAddr (hwaddr);
305
425
}
306
426
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
+ }
312
435
313
436
// IP and UDP header
314
437
writeIpUdpHeader (pkt, buf);
0 commit comments